Compare commits
84 Commits
BauSystem/
...
Lobby/refa
| Author | SHA1 | Date | |
|---|---|---|---|
|
d0c1413ea6
|
|||
|
5f7c5f0a18
|
|||
|
9e9f405e30
|
|||
|
e6848b27a0
|
|||
|
93d0011b46
|
|||
| f56fedefe4 | |||
| 167bb4e266 | |||
| f6a9ce184b | |||
|
d5708c110c
|
|||
|
f23c1215b7
|
|||
| cfcaf1569c | |||
|
dc56b67ff6
|
|||
|
13c4a3ff8b
|
|||
|
7e5a13989b
|
|||
|
990a03ca6c
|
|||
| 4a608fe5b5 | |||
|
5ca15aa117
|
|||
|
9b459bd12c
|
|||
|
b20d37e252
|
|||
| a8c98594a9 | |||
|
1c076b5bbf
|
|||
|
133ddb39cc
|
|||
| ebb375d8d6 | |||
| 8ada9a6335 | |||
|
0760a5a08a
|
|||
|
852ff95757
|
|||
|
5c7d388876
|
|||
|
4f92f8132d
|
|||
|
56fb63f781
|
|||
|
273efff87d
|
|||
|
0cac6f36c1
|
|||
|
8680b9e6cf
|
|||
| 6c94efaf90 | |||
| f6261ad989 | |||
|
614e989892
|
|||
| 84e1f605bd | |||
| 0ea5a62dbe | |||
|
0eb6047139
|
|||
|
fcebecf745
|
|||
| dd14e9f518 | |||
|
6c5239c8fc
|
|||
|
fc71f47add
|
|||
|
5d36393643
|
|||
|
ebc6f50261
|
|||
| 69cf219e39 | |||
| fb4e53165f | |||
| 415d783365 | |||
| ee99708340 | |||
|
c9d74fb656
|
|||
|
e50e52950b
|
|||
| cac0ae3e13 | |||
| f9b3dd34cf | |||
|
e5a61226ca
|
|||
|
0c35ace5e2
|
|||
|
23bcf14ca5
|
|||
|
63a5fcff97
|
|||
|
39b3cdb897
|
|||
| 3ccfe92afb | |||
| c17b76851d | |||
| f0e18bfc72 | |||
| 160f982955 | |||
|
6ac0143459
|
|||
| 98ca9e852c | |||
|
|
17910ec8a4 | ||
|
56bc75763b
|
|||
|
8272c73b48
|
|||
|
9acfb32ae0
|
|||
|
b2a4b05545
|
|||
|
89e2df0eb2
|
|||
|
73da9179bf
|
|||
|
0fbbcdacea
|
|||
|
4e6933f2fd
|
|||
|
eea1073892
|
|||
|
702aa1cfa6
|
|||
|
6ea73f4890
|
|||
|
14e82f36a5
|
|||
|
a8eaf3daa7
|
|||
|
b51ea484e4
|
|||
|
8bef19ed8b
|
|||
| 1aff7b30a6 | |||
| c8ac984ad3 | |||
| a462231bab | |||
| e6bbb76a0b | |||
| eb63381b83 |
@@ -1,18 +1,20 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem;
|
||||
@@ -44,6 +46,7 @@ import de.steamwar.linkage.SpigotLinker;
|
||||
import de.steamwar.message.Message;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameRule;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -69,7 +72,6 @@ public class BauSystem extends JavaPlugin implements Listener {
|
||||
@Getter
|
||||
private static BauSystem instance;
|
||||
|
||||
@Getter
|
||||
private SpigotLinker linker;
|
||||
|
||||
@Override
|
||||
@@ -127,6 +129,8 @@ public class BauSystem extends JavaPlugin implements Listener {
|
||||
TraceRecorder.instance.init();
|
||||
|
||||
new WorldEditRendererCUIEditor();
|
||||
|
||||
Bukkit.getWorlds().get(0).setGameRule(GameRule.SEND_COMMAND_FEEDBACK, false);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@@ -182,8 +186,7 @@ public class BauSystem extends JavaPlugin implements Listener {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (TickManager.impl.isFrozen())
|
||||
return;
|
||||
if (TickManager.impl.isFrozen()) return;
|
||||
if (counter >= delay) {
|
||||
runnable.run();
|
||||
cancel();
|
||||
@@ -201,8 +204,7 @@ public class BauSystem extends JavaPlugin implements Listener {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (TickManager.impl.isFrozen())
|
||||
return;
|
||||
if (TickManager.impl.isFrozen()) return;
|
||||
if (counter >= (first ? delay : period)) {
|
||||
first = false;
|
||||
runnable.run();
|
||||
@@ -218,4 +220,4 @@ public class BauSystem extends JavaPlugin implements Listener {
|
||||
AtomicReference<BukkitTask> task = new AtomicReference<>();
|
||||
task.set(runTaskTimer(plugin, () -> consumer.accept(task.get()), delay, period));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -198,7 +197,7 @@ public class TestblockCommand extends SWCommand {
|
||||
@Override
|
||||
public List<String> tabCompletes(CommandSender commandSender, PreviousArguments previousArguments, String s) {
|
||||
List<String> 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 +205,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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator;
|
||||
@@ -20,9 +22,7 @@ package de.steamwar.bausystem.features.simulator;
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.SWUtils;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorCursor;
|
||||
import de.steamwar.bausystem.features.simulator.execute.SimulatorExecutor;
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorCursorManager;
|
||||
import de.steamwar.command.PreviousArguments;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.command.TypeMapper;
|
||||
@@ -40,7 +40,7 @@ import java.util.Collection;
|
||||
public class SimulatorCommand extends SWCommand {
|
||||
|
||||
@LinkedInstance
|
||||
public SimulatorCursorManager cursorManager;
|
||||
public SimulatorCursor simulatorCursor;
|
||||
|
||||
public SimulatorCommand() {
|
||||
super("sim", "simulator");
|
||||
@@ -49,12 +49,12 @@ public class SimulatorCommand extends SWCommand {
|
||||
@Register(description = "SIMULATOR_HELP")
|
||||
public void genericCommand(@Validator Player p) {
|
||||
SWUtils.giveItemToPlayer(p, SimulatorStorage.getWand(p));
|
||||
cursorManager.showCursor(p, null);
|
||||
simulatorCursor.calcCursor(p);
|
||||
}
|
||||
|
||||
@Register(value = "change", description = "SIMULATOR_CHANGE_HELP")
|
||||
public void change(@Validator Player p) {
|
||||
if (!SimulatorUtils.isSimulatorItem(p.getInventory().getItemInMainHand()) && !SimulatorUtils.isSimulatorItem(p.getInventory().getItemInOffHand())) {
|
||||
if (!SimulatorCursor.isSimulatorItem(p.getInventory().getItemInMainHand()) && !SimulatorCursor.isSimulatorItem(p.getInventory().getItemInOffHand())) {
|
||||
BauSystem.MESSAGE.send("SIMULATOR_NO_SIM_IN_HAND", p);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,472 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator;
|
||||
|
||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||
import de.steamwar.Reflection;
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.Permission;
|
||||
import de.steamwar.bausystem.SWUtils;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
|
||||
import de.steamwar.bausystem.features.simulator.data.observer.ObserverElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.observer.ObserverPhase;
|
||||
import de.steamwar.bausystem.features.simulator.data.redstone.RedstoneElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.redstone.RedstonePhase;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase;
|
||||
import de.steamwar.bausystem.features.simulator.execute.SimulatorExecutor;
|
||||
import de.steamwar.bausystem.features.simulator.gui.SimulatorGroupGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.SimulatorGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.bausystem.utils.BauMemberUpdateEvent;
|
||||
import de.steamwar.bausystem.utils.ItemUtils;
|
||||
import de.steamwar.bausystem.utils.RayTraceUtils;
|
||||
import de.steamwar.entity.REntity;
|
||||
import de.steamwar.entity.REntityServer;
|
||||
import de.steamwar.entity.RFallingBlockEntity;
|
||||
import de.steamwar.inventory.SWAnvilInv;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import de.steamwar.linkage.MinVersion;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Player;
|
||||
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.inventory.ItemStack;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Linked
|
||||
@MinVersion(19)
|
||||
public class SimulatorCursor implements Listener {
|
||||
|
||||
private static final World WORLD = Bukkit.getWorlds().get(0);
|
||||
private Class<?> position = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Pos");
|
||||
private Class<?> look = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Rot");
|
||||
private Class<?> positionLook = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$PosRot");
|
||||
|
||||
private static Map<Player, CursorType> cursorType = Collections.synchronizedMap(new HashMap<>());
|
||||
private static Map<Player, REntityServer> cursors = Collections.synchronizedMap(new HashMap<>());
|
||||
private static final Set<Player> calculating = new HashSet<>();
|
||||
|
||||
public static boolean isSimulatorItem(ItemStack itemStack) {
|
||||
return ItemUtils.isItem(itemStack, "simulator");
|
||||
}
|
||||
|
||||
public SimulatorCursor() {
|
||||
BiFunction<Player, Object, Object> function = (player, object) -> {
|
||||
calcCursor(player);
|
||||
return object;
|
||||
};
|
||||
TinyProtocol.instance.addFilter(position, function);
|
||||
TinyProtocol.instance.addFilter(look, function);
|
||||
TinyProtocol.instance.addFilter(positionLook, function);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||
calcCursor(event.getPlayer());
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerDropItem(PlayerDropItemEvent event) {
|
||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||
calcCursor(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerItemHeld(PlayerItemHeldEvent event) {
|
||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||
calcCursor(event.getPlayer());
|
||||
}, 1);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBauMemberUpdate(BauMemberUpdateEvent event) {
|
||||
event.getChanged().forEach(SimulatorCursor::calcCursor);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
cursorType.remove(event.getPlayer());
|
||||
cursors.remove(event.getPlayer());
|
||||
synchronized (calculating) {
|
||||
calculating.remove(event.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<Player, Long> LAST_SNEAKS = new HashMap<>();
|
||||
|
||||
static {
|
||||
Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), () -> {
|
||||
long millis = System.currentTimeMillis();
|
||||
LAST_SNEAKS.entrySet().removeIf(entry -> millis - entry.getValue() > 200);
|
||||
}, 1, 1);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onPlayerToggleSneak(PlayerToggleSneakEvent event) {
|
||||
if (!event.isSneaking()) return;
|
||||
Player player = event.getPlayer();
|
||||
if (!isSimulatorItem(player.getInventory().getItemInMainHand()) && !isSimulatorItem(player.getInventory().getItemInOffHand())) {
|
||||
return;
|
||||
}
|
||||
if (LAST_SNEAKS.containsKey(player)) {
|
||||
CursorType currentType = cursorType.getOrDefault(player, CursorType.TNT);
|
||||
if (currentType == CursorType.TNT) {
|
||||
cursorType.put(player, CursorType.REDSTONE_BLOCK);
|
||||
} else {
|
||||
cursorType.put(player, CursorType.TNT);
|
||||
}
|
||||
calcCursor(player);
|
||||
} else {
|
||||
LAST_SNEAKS.put(player, System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
public static CursorType getCursorType(Player player) {
|
||||
return cursorType.getOrDefault(player, CursorType.TNT);
|
||||
}
|
||||
|
||||
public static void setCursorType(Player player, CursorType cursorType) {
|
||||
SimulatorCursor.cursorType.put(player, cursorType);
|
||||
calcCursor(player);
|
||||
}
|
||||
|
||||
public static void calcCursor(Player player) {
|
||||
synchronized (calculating) {
|
||||
if (calculating.contains(player)) return;
|
||||
calculating.add(player);
|
||||
}
|
||||
if (!Permission.BUILD.hasPermission(player) || (!isSimulatorItem(player.getInventory().getItemInMainHand()) && !isSimulatorItem(player.getInventory().getItemInOffHand()))) {
|
||||
if (removeCursor(player) || SimulatorWatcher.show(null, player)) {
|
||||
SWUtils.sendToActionbar(player, "");
|
||||
}
|
||||
synchronized (calculating) {
|
||||
calculating.remove(player);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Simulator simulator = SimulatorStorage.getSimulator(player);
|
||||
if (simulator != null && simulator.getStabGenerator() != null) {
|
||||
removeCursor(player);
|
||||
SimulatorWatcher.show(null, player);
|
||||
SWUtils.sendToActionbar(player, "§cGenerating Stab");
|
||||
synchronized (calculating) {
|
||||
calculating.remove(player);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
SimulatorWatcher.show(simulator, player);
|
||||
List<REntity> entities = SimulatorWatcher.getEntitiesOfSimulator(simulator);
|
||||
RayTraceUtils.RRayTraceResult rayTraceResult = RayTraceUtils.traceREntity(player, player.getLocation(), entities);
|
||||
if (rayTraceResult == null) {
|
||||
removeCursor(player);
|
||||
if (simulator == null) {
|
||||
SWUtils.sendToActionbar(player, "§eSelect Simulator");
|
||||
} else {
|
||||
SWUtils.sendToActionbar(player, "§eOpen Simulator");
|
||||
}
|
||||
synchronized (calculating) {
|
||||
calculating.remove(player);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
showCursor(player, rayTraceResult, simulator != null);
|
||||
synchronized (calculating) {
|
||||
calculating.remove(player);
|
||||
}
|
||||
}
|
||||
|
||||
private static synchronized boolean removeCursor(Player player) {
|
||||
REntityServer entityServer = cursors.get(player);
|
||||
boolean hadCursor = entityServer != null && !entityServer.getEntities().isEmpty();
|
||||
if (entityServer != null) {
|
||||
entityServer.getEntities().forEach(REntity::die);
|
||||
}
|
||||
return hadCursor;
|
||||
}
|
||||
|
||||
private static synchronized void showCursor(Player player, RayTraceUtils.RRayTraceResult rayTraceResult, boolean hasSimulatorSelected) {
|
||||
REntityServer entityServer = cursors.computeIfAbsent(player, __ -> {
|
||||
REntityServer rEntityServer = new REntityServer();
|
||||
rEntityServer.addPlayer(player);
|
||||
return rEntityServer;
|
||||
});
|
||||
|
||||
CursorType type = cursorType.getOrDefault(player, CursorType.TNT);
|
||||
REntity hitEntity = rayTraceResult.getHitEntity();
|
||||
Location location = hitEntity != null ? new Vector(hitEntity.getX(), hitEntity.getY(), hitEntity.getZ()).toLocation(WORLD) :
|
||||
type.position.apply(player, rayTraceResult).toLocation(WORLD);
|
||||
|
||||
Material material = hitEntity != null ? Material.GLASS : type.getMaterial();
|
||||
List<RFallingBlockEntity> entities = entityServer.getEntitiesByType(RFallingBlockEntity.class);
|
||||
entities.removeIf(rFallingBlockEntity -> {
|
||||
if (rFallingBlockEntity.getMaterial() != material) {
|
||||
rFallingBlockEntity.die();
|
||||
return true;
|
||||
}
|
||||
rFallingBlockEntity.move(location);
|
||||
return false;
|
||||
});
|
||||
if (entities.isEmpty()) {
|
||||
RFallingBlockEntity rFallingBlockEntity = new RFallingBlockEntity(entityServer, location, material);
|
||||
rFallingBlockEntity.setNoGravity(true);
|
||||
if (material == Material.GLASS) {
|
||||
rFallingBlockEntity.setGlowing(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSimulatorSelected) {
|
||||
if (hitEntity != null) {
|
||||
SWUtils.sendToActionbar(player, "§eEdit Position");
|
||||
} else {
|
||||
SWUtils.sendToActionbar(player, "§eAdd new " + type.name);
|
||||
}
|
||||
} else {
|
||||
SWUtils.sendToActionbar(player, "§eCreate new Simulator");
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector getPosFree(Player player, RayTraceUtils.RRayTraceResult result) {
|
||||
Vector pos = result.getHitPosition();
|
||||
|
||||
BlockFace face = result.getHitBlockFace();
|
||||
if (face != null) {
|
||||
switch (face) {
|
||||
case DOWN:
|
||||
pos.setY(pos.getY() - 0.98);
|
||||
break;
|
||||
case EAST:
|
||||
pos.setX(pos.getX() + 0.49);
|
||||
break;
|
||||
case WEST:
|
||||
pos.setX(pos.getX() - 0.49);
|
||||
break;
|
||||
case NORTH:
|
||||
pos.setZ(pos.getZ() - 0.49);
|
||||
break;
|
||||
case SOUTH:
|
||||
pos.setZ(pos.getZ() + 0.49);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (face.getModY() == 0 && player.isSneaking()) {
|
||||
pos.setY(pos.getY() - 0.49);
|
||||
}
|
||||
}
|
||||
|
||||
if (!player.isSneaking()) {
|
||||
pos.setX(pos.getBlockX() + 0.5);
|
||||
if (face == null || face.getModY() == 0)
|
||||
pos.setY(pos.getBlockY() + 0.0);
|
||||
pos.setZ(pos.getBlockZ() + 0.5);
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
private static Vector getPosBlockAligned(Player player, RayTraceUtils.RRayTraceResult result) {
|
||||
Vector pos = result.getHitPosition();
|
||||
|
||||
BlockFace face = result.getHitBlockFace();
|
||||
if (face != null) {
|
||||
switch (face) {
|
||||
case DOWN:
|
||||
pos.setY(pos.getY() - 0.98);
|
||||
break;
|
||||
case EAST:
|
||||
pos.setX(pos.getX() + 0.49);
|
||||
break;
|
||||
case WEST:
|
||||
pos.setX(pos.getX() - 0.49);
|
||||
break;
|
||||
case NORTH:
|
||||
pos.setZ(pos.getZ() - 0.49);
|
||||
break;
|
||||
case SOUTH:
|
||||
pos.setZ(pos.getZ() + 0.49);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pos.setX(pos.getBlockX() + 0.5);
|
||||
if (pos.getY() - pos.getBlockY() != 0 && face == BlockFace.UP) {
|
||||
pos.setY(pos.getBlockY() + 1.0);
|
||||
} else {
|
||||
pos.setY(pos.getBlockY());
|
||||
}
|
||||
pos.setZ(pos.getBlockZ() + 0.5);
|
||||
return pos;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum CursorType {
|
||||
TNT(Material.TNT, Material.GUNPOWDER, SimulatorCursor::getPosFree, "TNT", vector -> new TNTElement(vector).add(new TNTPhase())),
|
||||
REDSTONE_BLOCK(Material.REDSTONE_BLOCK, Material.REDSTONE, SimulatorCursor::getPosBlockAligned, "Redstone Block", vector -> new RedstoneElement(vector).add(new RedstonePhase())),
|
||||
OBSERVER(Material.OBSERVER, Material.QUARTZ, SimulatorCursor::getPosBlockAligned, "Observer", vector -> new ObserverElement(vector).add(new ObserverPhase())),
|
||||
;
|
||||
|
||||
public final Material material;
|
||||
public final Material nonSelectedMaterial;
|
||||
public final BiFunction<Player, RayTraceUtils.RRayTraceResult, Vector> position;
|
||||
public final String name;
|
||||
public final Function<Vector, SimulatorElement<?>> elementFunction;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||
if (!ItemUtils.isItem(event.getItem(), "simulator")) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.setCancelled(true);
|
||||
Player player = event.getPlayer();
|
||||
Simulator simulator = SimulatorStorage.getSimulator(player);
|
||||
|
||||
if (event.getAction() == Action.LEFT_CLICK_BLOCK || event.getAction() == Action.LEFT_CLICK_AIR) {
|
||||
if (simulator == null) {
|
||||
return;
|
||||
}
|
||||
SimulatorExecutor.run(event.getPlayer(), simulator, null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getAction() != Action.RIGHT_CLICK_BLOCK && event.getAction() != Action.RIGHT_CLICK_AIR) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
RayTraceUtils.RRayTraceResult rayTraceResult = RayTraceUtils.traceREntity(player, player.getLocation(), SimulatorWatcher.getEntitiesOfSimulator(simulator));
|
||||
if (simulator == null) {
|
||||
if (rayTraceResult == null) {
|
||||
SimulatorStorage.openSimulatorSelector(player);
|
||||
} else {
|
||||
SWAnvilInv anvilInv = new SWAnvilInv(player, "Name");
|
||||
anvilInv.setCallback(s -> {
|
||||
Simulator sim = SimulatorStorage.getSimulator(s);
|
||||
if (sim != null) {
|
||||
BauSystem.MESSAGE.send("SIMULATOR_NAME_ALREADY_EXISTS", player);
|
||||
return;
|
||||
}
|
||||
if (!s.matches("[a-zA-Z_0-9-]+")) {
|
||||
BauSystem.MESSAGE.send("SIMULATOR_NAME_INVALID", player);
|
||||
return;
|
||||
}
|
||||
sim = new Simulator(s);
|
||||
SimulatorStorage.addSimulator(s, sim);
|
||||
createElement(player, rayTraceResult, sim);
|
||||
SimulatorStorage.setSimulator(player, sim);
|
||||
});
|
||||
anvilInv.open();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (rayTraceResult == null) {
|
||||
new SimulatorGui(player, simulator).open();
|
||||
return;
|
||||
}
|
||||
|
||||
if (rayTraceResult.getHitEntity() != null) {
|
||||
REntity hitEntity = rayTraceResult.getHitEntity();
|
||||
Vector vector = new Vector(hitEntity.getX(), hitEntity.getY(), hitEntity.getZ());
|
||||
List<SimulatorElement<?>> elements = simulator.getGroups().stream().map(SimulatorGroup::getElements).flatMap(List::stream).filter(element -> {
|
||||
return element.getWorldPos().distanceSquared(vector) < (1 / 16.0) * (1 / 16.0);
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
switch (elements.size()) {
|
||||
case 0:
|
||||
return;
|
||||
case 1:
|
||||
// Open single element present in Simulator
|
||||
SimulatorElement<?> element = elements.get(0);
|
||||
SimulatorGroup group1 = element.getGroup(simulator);
|
||||
SimulatorBaseGui back = new SimulatorGui(player, simulator);
|
||||
if (group1.getElements().size() > 1) {
|
||||
back = new SimulatorGroupGui(player, simulator, group1, back);
|
||||
}
|
||||
element.open(player, simulator, group1, back);
|
||||
break;
|
||||
default:
|
||||
List<SimulatorGroup> parents = elements.stream().map(e -> e.getGroup(simulator)).distinct().collect(Collectors.toList());
|
||||
if (parents.size() == 1) {
|
||||
// Open multi element present in Simulator in existing group
|
||||
SimulatorGui simulatorGui = new SimulatorGui(player, simulator);
|
||||
new SimulatorGroupGui(player, simulator, parents.get(0), simulatorGui).open();
|
||||
} else {
|
||||
// Open multi element present in Simulator in implicit group
|
||||
SimulatorGroup group2 = new SimulatorGroup();
|
||||
group2.setMaterial(null);
|
||||
group2.getElements().addAll(elements);
|
||||
SimulatorGui simulatorGui = new SimulatorGui(player, simulator);
|
||||
new SimulatorGroupGui(player, simulator, group2, simulatorGui).open();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Add new Element to current simulator
|
||||
createElement(player, rayTraceResult, simulator);
|
||||
}
|
||||
|
||||
private void createElement(Player player, RayTraceUtils.RRayTraceResult rayTraceResult, Simulator simulator) {
|
||||
CursorType type = cursorType.getOrDefault(player, CursorType.TNT);
|
||||
Vector vector = type.position.apply(player, rayTraceResult);
|
||||
if (type == CursorType.REDSTONE_BLOCK) {
|
||||
vector.subtract(new Vector(0.5, 0, 0.5));
|
||||
}
|
||||
SimulatorElement<?> element = type.elementFunction.apply(vector);
|
||||
SimulatorGroup group = new SimulatorGroup().add(element);
|
||||
simulator.getGroups().add(group);
|
||||
SimulatorGui simulatorGui = new SimulatorGui(player, simulator);
|
||||
element.open(player, simulator, group, simulatorGui);
|
||||
SimulatorWatcher.update(simulator);
|
||||
calcCursor(player);
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the
|
||||
* GNU Affero General Public License as published by the Free Software Foundation, either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator;
|
||||
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.display.ASimulatorCursor;
|
||||
import de.steamwar.bausystem.features.simulator.display.EmptySimulatorCursor;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorCursor;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorCursorMode;
|
||||
|
||||
import de.steamwar.linkage.Linked;
|
||||
import de.steamwar.linkage.MinVersion;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import org.bukkit.event.player.*;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import java.util.*;
|
||||
|
||||
// TODO fix memory leak when players leave the server
|
||||
// TODO fix cursor not being hidden when player deequips simulator item
|
||||
// TODO fix simulator onclick
|
||||
|
||||
@Linked
|
||||
@MinVersion(19)
|
||||
public class SimulatorCursorManager implements Listener {
|
||||
public static final SimulatorCursorManager INSTANCE = new SimulatorCursorManager();
|
||||
|
||||
private final Map<Player, Map<Simulator, ASimulatorCursor>> openCursorsByPlayerBySimulator = new HashMap<>();
|
||||
private final Map<Player, ASimulatorCursor> activeCursorByPlayer = new HashMap<>();
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerItemEquip(PlayerItemHeldEvent event) {
|
||||
ItemStack newItem = event.getPlayer().getInventory().getItem(event.getNewSlot());
|
||||
if (SimulatorUtils.isSimulatorItem(newItem)) {
|
||||
Simulator simulator = SimulatorStorage.getSimulator(newItem);
|
||||
showCursor(event.getPlayer(), simulator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the cursor for the given simulator to the given player. Shows an empty cursor if the
|
||||
* simulator is null.
|
||||
*/
|
||||
public void showCursor(Player player, Simulator simulator) {
|
||||
var currentActiveCursor = activeCursorByPlayer.get(player);
|
||||
if (currentActiveCursor != null) {
|
||||
currentActiveCursor.hide();
|
||||
}
|
||||
|
||||
var cursorMode = currentActiveCursor != null ? currentActiveCursor.getCursorMode() : SimulatorCursorMode.TNT;
|
||||
|
||||
var cursorsBySimulator = openCursorsByPlayerBySimulator.computeIfAbsent(player, __ -> new HashMap<>());
|
||||
var cursor = cursorsBySimulator.get(simulator);
|
||||
if (cursor == null) {
|
||||
if (simulator == null) {
|
||||
ASimulatorCursor emptyCursor = new EmptySimulatorCursor(player, cursorMode);
|
||||
cursorsBySimulator.put(simulator, emptyCursor);
|
||||
cursor = emptyCursor;
|
||||
} else {
|
||||
ASimulatorCursor newCursor = new SimulatorCursor(simulator, player, cursorMode);
|
||||
cursorsBySimulator.put(simulator, newCursor);
|
||||
cursor = newCursor;
|
||||
}
|
||||
}
|
||||
|
||||
cursor.show();
|
||||
}
|
||||
|
||||
public Optional<SimulatorCursorMode> getActiveCursorMode(Player player) {
|
||||
var currentActiveCursor = activeCursorByPlayer.get(player);
|
||||
if (currentActiveCursor != null) {
|
||||
return Optional.of(currentActiveCursor.getCursorMode());
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public void setActiveCursorMode(Player player, SimulatorCursorMode mode) {
|
||||
var currentActiveCursor = activeCursorByPlayer.get(player);
|
||||
if (currentActiveCursor != null) {
|
||||
currentActiveCursor.setCursorMode(mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,20 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator;
|
||||
@@ -54,13 +56,12 @@ public class SimulatorStorage implements Enable {
|
||||
|
||||
public static Simulator getSimulator(Player player) {
|
||||
Simulator simulator = getSimulator(player.getInventory().getItemInMainHand());
|
||||
if (simulator != null)
|
||||
return simulator;
|
||||
if (simulator != null) return simulator;
|
||||
return getSimulator(player.getInventory().getItemInOffHand());
|
||||
}
|
||||
|
||||
public static Simulator getSimulator(ItemStack itemStack) {
|
||||
if (!SimulatorUtils.isSimulatorItem(itemStack)) {
|
||||
if (!SimulatorCursor.isSimulatorItem(itemStack)) {
|
||||
return null;
|
||||
}
|
||||
String selection = ItemUtils.getTag(itemStack, simulatorSelection);
|
||||
@@ -85,11 +86,11 @@ public class SimulatorStorage implements Enable {
|
||||
YAPIONFormatSimulatorLoader yapionFormatSimulatorLoader = new YAPIONFormatSimulatorLoader();
|
||||
|
||||
File[] files = simulatorsDir.listFiles();
|
||||
if (files == null)
|
||||
return;
|
||||
if (files == null) return;
|
||||
for (File file : files) {
|
||||
try {
|
||||
List<Simulator> simulators = simFormatSimulatorLoader.load(file).orElse(null);
|
||||
List<Simulator> simulators = simFormatSimulatorLoader.load(file)
|
||||
.orElse(null);
|
||||
if (simulators != null) {
|
||||
simulators.forEach(simulator -> {
|
||||
simulatorMap.put(simulator.getName(), simulator);
|
||||
@@ -101,7 +102,8 @@ public class SimulatorStorage implements Enable {
|
||||
}
|
||||
|
||||
try {
|
||||
List<Simulator> simulators = simulatorFormatSimulatorLoader.load(file).orElse(null);
|
||||
List<Simulator> simulators = simulatorFormatSimulatorLoader.load(file)
|
||||
.orElse(null);
|
||||
if (simulators != null) {
|
||||
simulators.forEach(simulator -> {
|
||||
simulatorMap.put(simulator.getName(), simulator);
|
||||
@@ -114,7 +116,8 @@ public class SimulatorStorage implements Enable {
|
||||
}
|
||||
|
||||
try {
|
||||
List<Simulator> simulators = yapionFormatSimulatorLoader.load(file).orElse(null);
|
||||
List<Simulator> simulators = yapionFormatSimulatorLoader.load(file)
|
||||
.orElse(null);
|
||||
if (simulators != null) {
|
||||
simulators.forEach(simulator -> {
|
||||
simulatorMap.put(simulator.getName(), simulator);
|
||||
@@ -128,8 +131,7 @@ public class SimulatorStorage implements Enable {
|
||||
}
|
||||
|
||||
public static void openSimulatorSelector(Player player) {
|
||||
SimulatorPageGui<Simulator> simulatorPageGui = new SimulatorPageGui<Simulator>(player, null, 6 * 9,
|
||||
simulatorMap.values().stream().sorted(Comparator.comparing(Simulator::getName)).collect(Collectors.toList())) {
|
||||
SimulatorPageGui<Simulator> simulatorPageGui = new SimulatorPageGui<Simulator>(player, null, 6 * 9, simulatorMap.values().stream().sorted(Comparator.comparing(Simulator::getName)).collect(Collectors.toList())) {
|
||||
@Override
|
||||
public String baseTitle() {
|
||||
return "Simulators";
|
||||
@@ -169,11 +171,7 @@ public class SimulatorStorage implements Enable {
|
||||
}
|
||||
|
||||
public static ItemStack getWand(Player p) {
|
||||
ItemStack itemStack = new SWItem(Material.BLAZE_ROD, BauSystem.MESSAGE.parse("SIMULATOR_WAND_NAME", p),
|
||||
Arrays.asList(BauSystem.MESSAGE.parse("SIMULATOR_WAND_LORE_1", p), BauSystem.MESSAGE.parse("SIMULATOR_WAND_LORE_2", p),
|
||||
BauSystem.MESSAGE.parse("SIMULATOR_WAND_LORE_3", p), BauSystem.MESSAGE.parse("SIMULATOR_WAND_LORE_4", p),
|
||||
BauSystem.MESSAGE.parse("SIMULATOR_WAND_LORE_5", p)),
|
||||
false, null).getItemStack();
|
||||
ItemStack itemStack = new SWItem(Material.BLAZE_ROD, BauSystem.MESSAGE.parse("SIMULATOR_WAND_NAME", p), Arrays.asList(BauSystem.MESSAGE.parse("SIMULATOR_WAND_LORE_1", p), BauSystem.MESSAGE.parse("SIMULATOR_WAND_LORE_2", p), BauSystem.MESSAGE.parse("SIMULATOR_WAND_LORE_3", p), BauSystem.MESSAGE.parse("SIMULATOR_WAND_LORE_4", p), BauSystem.MESSAGE.parse("SIMULATOR_WAND_LORE_5", p)), false, null).getItemStack();
|
||||
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||
itemMeta.setCustomModelData(1);
|
||||
itemStack.setItemMeta(itemMeta);
|
||||
@@ -185,9 +183,9 @@ public class SimulatorStorage implements Enable {
|
||||
ItemStack mainHand = player.getInventory().getItemInMainHand();
|
||||
ItemStack offHand = player.getInventory().getItemInOffHand();
|
||||
ItemStack itemStack;
|
||||
if (SimulatorUtils.isSimulatorItem(mainHand)) {
|
||||
if (SimulatorCursor.isSimulatorItem(mainHand)) {
|
||||
itemStack = mainHand;
|
||||
} else if (SimulatorUtils.isSimulatorItem(offHand)) {
|
||||
} else if (SimulatorCursor.isSimulatorItem(offHand)) {
|
||||
itemStack = offHand;
|
||||
} else {
|
||||
itemStack = null;
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
package de.steamwar.bausystem.features.simulator;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import de.steamwar.bausystem.utils.ItemUtils;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class SimulatorUtils {
|
||||
public static boolean isSimulatorItem(ItemStack itemStack) {
|
||||
return ItemUtils.isItem(itemStack, "simulator");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
|
||||
import de.steamwar.bausystem.features.simulator.storage.SimulatorSaver;
|
||||
import de.steamwar.bausystem.shared.Pair;
|
||||
import de.steamwar.entity.REntity;
|
||||
import de.steamwar.entity.REntityServer;
|
||||
import de.steamwar.entity.RFallingBlockEntity;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import de.steamwar.linkage.MinVersion;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@UtilityClass
|
||||
public class SimulatorWatcher {
|
||||
|
||||
private final World WORLD = Bukkit.getWorlds().get(0);
|
||||
private Map<Simulator, REntityServer> entityServers = new HashMap<>();
|
||||
private Map<Player, Pair<Simulator, Runnable>> watchers = new HashMap<>();
|
||||
|
||||
public void watch(Player player, Simulator simulator, Runnable watcher) {
|
||||
if (simulator == null || watcher == null) {
|
||||
watchers.remove(player);
|
||||
} else {
|
||||
watchers.put(player, new Pair<>(simulator, watcher));
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void update(Simulator simulator) {
|
||||
REntityServer rEntityServer = entityServers.get(simulator);
|
||||
if (rEntityServer != null) {
|
||||
rEntityServer.getEntities().forEach(REntity::die);
|
||||
createSim(rEntityServer, simulator);
|
||||
}
|
||||
|
||||
new ArrayList<>(watchers.values()).forEach(simulatorRunnablePair -> {
|
||||
if (simulatorRunnablePair.getKey() == simulator) {
|
||||
simulatorRunnablePair.getValue().run();
|
||||
}
|
||||
});
|
||||
SimulatorSaver.saveSimulator(SimulatorStorage.simulatorsDir, simulator);
|
||||
}
|
||||
|
||||
@Linked
|
||||
@MinVersion(19)
|
||||
public static class QuitListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
watchers.remove(event.getPlayer());
|
||||
show(null, event.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
private REntityServer createSim(REntityServer server, Simulator simulator) {
|
||||
if (simulator == null) {
|
||||
return null;
|
||||
}
|
||||
Map<Vector, Set<Class<?>>> positionCache = new HashMap<>();
|
||||
simulator.getGroups().stream().map(group -> group.getElements().stream().map(element -> new Pair<>(group, element)).collect(Collectors.toList())).flatMap(List::stream).forEach(pair -> {
|
||||
SimulatorGroup group = pair.getKey();
|
||||
SimulatorElement<?> element = pair.getValue();
|
||||
|
||||
boolean wasNotPresent = positionCache.computeIfAbsent(element.getPosition(), __ -> new HashSet<>())
|
||||
.add(element.getClass());
|
||||
if (!wasNotPresent) return;
|
||||
Material material = group.isDisabled() || element.isDisabled() ? element.getWorldDisabledMaterial() : element.getWorldMaterial();
|
||||
Location location = element.getWorldPos().toLocation(WORLD);
|
||||
RFallingBlockEntity rFallingBlockEntity = new RFallingBlockEntity(server, location, material);
|
||||
rFallingBlockEntity.setNoGravity(true);
|
||||
});
|
||||
return server;
|
||||
}
|
||||
|
||||
public synchronized boolean show(Simulator sim, Player player) {
|
||||
AtomicBoolean removed = new AtomicBoolean();
|
||||
entityServers.forEach((simulator, rEntityServer) -> {
|
||||
if (rEntityServer == null) return;
|
||||
if (rEntityServer.getPlayers().contains(player) && sim != simulator) {
|
||||
rEntityServer.removePlayer(player);
|
||||
removed.set(true);
|
||||
}
|
||||
});
|
||||
if (sim == null) return removed.get();
|
||||
entityServers.computeIfAbsent(sim, __ -> createSim(new REntityServer(), sim)).addPlayer(player);
|
||||
return removed.get();
|
||||
}
|
||||
|
||||
synchronized List<REntity> getEntitiesOfSimulator(Simulator simulator) {
|
||||
REntityServer entityServer = entityServers.get(simulator);
|
||||
if (entityServer == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return entityServer.getEntities();
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package de.steamwar.bausystem.features.simulator.display;
|
||||
|
||||
import java.util.List;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerToggleSneakEvent;
|
||||
import de.steamwar.bausystem.utils.cursor.Cursor;
|
||||
import de.steamwar.entity.REntityServer;
|
||||
import lombok.Getter;
|
||||
|
||||
public abstract class ASimulatorCursor extends Cursor implements Listener {
|
||||
protected final Player owner;
|
||||
|
||||
@Getter
|
||||
protected SimulatorCursorMode cursorMode;
|
||||
|
||||
protected ASimulatorCursor(Player owner, REntityServer targetServer, SimulatorCursorMode cursorMode) {
|
||||
super(targetServer, owner, Material.GLASS, Material.TNT, List.of(Cursor.CursorMode.FREE, Cursor.CursorMode.BLOCK_ALIGNED));
|
||||
this.cursorMode = cursorMode;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public void swapCursorMode() {
|
||||
cursorMode = cursorMode.switchType();
|
||||
setCursorMaterial(cursorMode.getMaterial());
|
||||
setAllowedCursorModes(cursorMode.getAllowedCursorModes());
|
||||
}
|
||||
|
||||
public void setCursorMode(SimulatorCursorMode mode) {
|
||||
this.cursorMode = mode;
|
||||
setCursorMaterial(cursorMode.getMaterial());
|
||||
setAllowedCursorModes(cursorMode.getAllowedCursorModes());
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
super.hide();
|
||||
super.getTargetServer().removePlayer(owner);
|
||||
}
|
||||
|
||||
public void show() {
|
||||
super.show();
|
||||
super.getTargetServer().addPlayer(owner);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerShift(PlayerToggleSneakEvent event) {
|
||||
if (event.getPlayer() != owner) {
|
||||
return;
|
||||
}
|
||||
swapCursorMode();
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package de.steamwar.bausystem.features.simulator.display;
|
||||
|
||||
import java.util.Optional;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.block.Action;
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorStorage;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
|
||||
import de.steamwar.entity.REntityServer;
|
||||
import de.steamwar.inventory.SWAnvilInv;
|
||||
|
||||
public class EmptySimulatorCursor extends ASimulatorCursor {
|
||||
public EmptySimulatorCursor(Player owner, SimulatorCursorMode cursorMode) {
|
||||
super(owner, new REntityServer(), cursorMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(Optional<Location> clickedLocation, boolean clickedOnEntity, Action clickAction) {
|
||||
if (clickAction == Action.LEFT_CLICK_AIR) {
|
||||
SimulatorStorage.openSimulatorSelector(owner);
|
||||
} else if (clickAction == Action.LEFT_CLICK_BLOCK) {
|
||||
SWAnvilInv anvilInv = new SWAnvilInv(owner, "Name");
|
||||
anvilInv.setCallback(name -> {
|
||||
Simulator sim = SimulatorStorage.getSimulator(name);
|
||||
if (sim != null) {
|
||||
BauSystem.MESSAGE.send("SIMULATOR_NAME_ALREADY_EXISTS", owner);
|
||||
return;
|
||||
}
|
||||
if (!name.matches("[a-zA-Z_0-9-]+")) {
|
||||
BauSystem.MESSAGE.send("SIMULATOR_NAME_INVALID", owner);
|
||||
return;
|
||||
}
|
||||
sim = new Simulator(name);
|
||||
SimulatorStorage.addSimulator(name, sim);
|
||||
SimulatorElement<?> element = cursorMode.getElementFunction().apply(clickedLocation.get().toVector());
|
||||
SimulatorGroup group = new SimulatorGroup();
|
||||
group.add(element);
|
||||
sim.add(group);
|
||||
SimulatorStorage.setSimulator(owner, sim);
|
||||
});
|
||||
anvilInv.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package de.steamwar.bausystem.features.simulator.display;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.util.Vector;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
|
||||
import de.steamwar.bausystem.features.simulator.execute.SimulatorExecutor;
|
||||
import de.steamwar.bausystem.features.simulator.gui.SimulatorGroupGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.SimulatorGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
|
||||
public class SimulatorCursor extends ASimulatorCursor {
|
||||
private final Simulator simulator;
|
||||
|
||||
public SimulatorCursor(Simulator simulator, Player owner, SimulatorCursorMode cursorMode) {
|
||||
super(owner, SimulatorRenderer.renderSimulator(simulator), cursorMode);
|
||||
|
||||
this.simulator = simulator;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onClick(Optional<Location> clickedLocation, boolean clickedOnEntity, Action clickAction) {
|
||||
if (clickAction == Action.RIGHT_CLICK_AIR || clickAction == Action.RIGHT_CLICK_BLOCK) {
|
||||
SimulatorExecutor.run(owner, simulator, null);
|
||||
} else if (!clickedOnEntity || clickedLocation.isEmpty()) {
|
||||
new SimulatorGui(owner, simulator);
|
||||
} else {
|
||||
Vector vector = clickedLocation.get().toVector();
|
||||
List<SimulatorElement<?>> elements = simulator.getGroups().stream().map(SimulatorGroup::getElements).flatMap(List::stream)
|
||||
.filter(element -> element.getWorldPos().distanceSquared(vector) < (1 / 16.0) * (1 / 16.0)).toList();
|
||||
|
||||
switch (elements.size()) {
|
||||
case 0:
|
||||
return;
|
||||
case 1:
|
||||
// Open single element present in Simulator
|
||||
SimulatorElement<?> element = elements.get(0);
|
||||
SimulatorGroup group1 = element.getGroup(simulator);
|
||||
SimulatorBaseGui back = new SimulatorGui(owner, simulator);
|
||||
if (group1.getElements().size() > 1) {
|
||||
back = new SimulatorGroupGui(owner, simulator, group1, back);
|
||||
}
|
||||
element.open(owner, simulator, group1, back);
|
||||
break;
|
||||
default:
|
||||
List<SimulatorGroup> parents = elements.stream().map(e -> e.getGroup(simulator)).distinct().toList();
|
||||
if (parents.size() == 1) {
|
||||
// Open multi element present in Simulator in existing group
|
||||
SimulatorGui simulatorGui = new SimulatorGui(owner, simulator);
|
||||
new SimulatorGroupGui(owner, simulator, parents.get(0), simulatorGui).open();
|
||||
} else {
|
||||
// Open multi element present in Simulator in implicit group
|
||||
SimulatorGroup group2 = new SimulatorGroup();
|
||||
group2.setMaterial(null);
|
||||
group2.getElements().addAll(elements);
|
||||
SimulatorGui simulatorGui = new SimulatorGui(owner, simulator);
|
||||
new SimulatorGroupGui(owner, simulator, group2, simulatorGui).open();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package de.steamwar.bausystem.features.simulator.display;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.util.Vector;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.observer.ObserverElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.observer.ObserverPhase;
|
||||
import de.steamwar.bausystem.features.simulator.data.redstone.RedstoneElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.redstone.RedstonePhase;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase;
|
||||
import de.steamwar.bausystem.utils.cursor.Cursor.CursorMode;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum SimulatorCursorMode {
|
||||
TNT(Material.TNT, Material.GUNPOWDER, "TNT", vector -> new TNTElement(vector).add(new TNTPhase()),
|
||||
List.of(CursorMode.FREE, CursorMode.BLOCK_ALIGNED)), REDSTONE_BLOCK(Material.REDSTONE_BLOCK, Material.REDSTONE_WIRE, "Redstone Block",
|
||||
vector -> new RedstoneElement(vector).add(new RedstonePhase()), List.of(CursorMode.BLOCK_ALIGNED)), OBSERVER(Material.OBSERVER, Material.QUARTZ,
|
||||
"Observer", vector -> new ObserverElement(vector).add(new ObserverPhase()), List.of(CursorMode.BLOCK_ALIGNED)),;
|
||||
|
||||
public final Material material;
|
||||
public final Material nonSelectedMaterial;
|
||||
public final String name;
|
||||
public final Function<Vector, SimulatorElement<?>> elementFunction;
|
||||
public final List<CursorMode> allowedCursorModes;
|
||||
|
||||
public SimulatorCursorMode switchType() {
|
||||
if (this == TNT) {
|
||||
return REDSTONE_BLOCK;
|
||||
}
|
||||
if (this == REDSTONE_BLOCK) {
|
||||
return OBSERVER;
|
||||
}
|
||||
return TNT;
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the
|
||||
* GNU Affero General Public License as published by the Free Software Foundation, either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.display;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorStorage;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
|
||||
import de.steamwar.bausystem.features.simulator.storage.SimulatorSaver;
|
||||
import de.steamwar.bausystem.shared.Pair;
|
||||
import de.steamwar.entity.REntity;
|
||||
import de.steamwar.entity.REntityServer;
|
||||
import de.steamwar.entity.RFallingBlockEntity;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@UtilityClass
|
||||
public class SimulatorRenderer implements Listener {
|
||||
private final World WORLD = Bukkit.getWorlds().get(0);
|
||||
private Map<Simulator, REntityServer> entityServers = new HashMap<>();
|
||||
|
||||
public synchronized void update(Simulator simulator) {
|
||||
renderSimulator(simulator);
|
||||
|
||||
SimulatorSaver.saveSimulator(SimulatorStorage.simulatorsDir, simulator);
|
||||
}
|
||||
|
||||
public REntityServer renderSimulator(Simulator simulator) {
|
||||
if (simulator == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
REntityServer server = entityServers.computeIfAbsent(simulator, __ -> new REntityServer());
|
||||
|
||||
server.getEntities().forEach(REntity::die);
|
||||
|
||||
Map<Vector, Set<Class<?>>> positionCache = new HashMap<>();
|
||||
simulator.getGroups().stream().map(group -> group.getElements().stream().map(element -> new Pair<>(group, element)).toList()).flatMap(List::stream)
|
||||
.forEach(pair -> {
|
||||
SimulatorGroup group = pair.getKey();
|
||||
SimulatorElement<?> element = pair.getValue();
|
||||
|
||||
boolean wasNotPresent = positionCache.computeIfAbsent(element.getPosition(), __ -> new HashSet<>()).add(element.getClass());
|
||||
if (!wasNotPresent)
|
||||
return;
|
||||
Material material = group.isDisabled() || element.isDisabled() ? element.getWorldDisabledMaterial() : element.getWorldMaterial();
|
||||
Location location = element.getWorldPos().toLocation(WORLD);
|
||||
RFallingBlockEntity rFallingBlockEntity = new RFallingBlockEntity(server, location, material);
|
||||
rFallingBlockEntity.setNoGravity(true);
|
||||
});
|
||||
return server;
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
package de.steamwar.bausystem.features.simulator.execute;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
|
||||
import de.steamwar.bausystem.utils.bossbar.BossBarService;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -72,7 +72,7 @@ public abstract class StabStep {
|
||||
|
||||
protected final void stop() {
|
||||
data.simulator.setStabGenerator(null);
|
||||
SimulatorRenderer.update(data.simulator);
|
||||
SimulatorWatcher.update(data.simulator);
|
||||
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
BauSystemBossbar bossbar = BossBarService.instance.get(player, data.region, "simulator_stab_generator");
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorCursorManager;
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorCursor;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorCursorMode;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.data.CMDs;
|
||||
import de.steamwar.inventory.SWItem;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class SimulatorCursorSwitcherGui extends SimulatorBaseGui {
|
||||
private final SimulatorCursorManager cursorManager = BauSystem.getInstance().getLinker().get(SimulatorCursorManager.class).orElseThrow();
|
||||
|
||||
private SimulatorBaseGui back;
|
||||
|
||||
@@ -50,12 +50,14 @@ public class SimulatorCursorSwitcherGui extends SimulatorBaseGui {
|
||||
}).setCustomModelData(CMDs.BACK));
|
||||
|
||||
int slot = 2;
|
||||
SimulatorCursorMode currentType = cursorManager.getActiveCursorMode(player).orElse(SimulatorCursorMode.TNT);
|
||||
for (SimulatorCursorMode type : SimulatorCursorMode.values()) {
|
||||
SimulatorCursor.CursorType currentType = SimulatorCursor.getCursorType(player);
|
||||
for (SimulatorCursor.CursorType type : SimulatorCursor.CursorType.values()) {
|
||||
boolean selected = type == currentType;
|
||||
SWItem swItem = new SWItem(selected ? type.material : type.nonSelectedMaterial, "§e" + type.name)
|
||||
.setCustomModelData(selected ? 0 : CMDs.Simulator.NEW_PHASE).setLore(Collections.singletonList("§eClick to select")).setCallback(click -> {
|
||||
cursorManager.setActiveCursorMode(player, type);
|
||||
.setCustomModelData(selected ? 0 : CMDs.Simulator.NEW_PHASE)
|
||||
.setLore(Collections.singletonList("§eClick to select"))
|
||||
.setCallback(click -> {
|
||||
SimulatorCursor.setCursorType(player, type);
|
||||
player.closeInventory();
|
||||
});
|
||||
inventory.setItem(slot, swItem);
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorPageGui;
|
||||
import de.steamwar.inventory.InvCallback;
|
||||
@@ -36,11 +38,8 @@ public class SimulatorGroupChooserGui extends SimulatorPageGui<SimulatorGroup> {
|
||||
private final SimulatorGroup parent;
|
||||
private final SimulatorBaseGui back;
|
||||
|
||||
public SimulatorGroupChooserGui(Player player, Simulator simulator, SimulatorElement<?> subject,
|
||||
SimulatorGroup parent, SimulatorBaseGui back) {
|
||||
super(player, simulator, 6 * 9,
|
||||
simulator.getGroups().stream().filter(e -> e != parent).filter(e -> subject.canBeInGroup(e))
|
||||
.collect(Collectors.toList()));
|
||||
public SimulatorGroupChooserGui(Player player, Simulator simulator, SimulatorElement<?> subject, SimulatorGroup parent, SimulatorBaseGui back) {
|
||||
super(player, simulator, 6 * 9, simulator.getGroups().stream().filter(e -> e != parent).filter(e -> subject.canBeInGroup(e)).collect(Collectors.toList()));
|
||||
this.subject = subject;
|
||||
this.parent = parent;
|
||||
this.back = back;
|
||||
@@ -57,7 +56,7 @@ public class SimulatorGroupChooserGui extends SimulatorPageGui<SimulatorGroup> {
|
||||
simulator.getGroups().add(newParent);
|
||||
parent.getElements().remove(subject);
|
||||
back.open();
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
if (parent.getElements().size() == 1) {
|
||||
parent.setDisabled(false);
|
||||
parent.setMaterial(Material.BARREL);
|
||||
@@ -84,7 +83,7 @@ public class SimulatorGroupChooserGui extends SimulatorPageGui<SimulatorGroup> {
|
||||
parent.setMaterial(Material.BARREL);
|
||||
}
|
||||
back.open();
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
};
|
||||
return simulatorGroup.toItem(player, invCallback, invCallback);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorPageGui;
|
||||
import de.steamwar.data.CMDs;
|
||||
@@ -58,7 +60,7 @@ public class SimulatorGroupGui extends SimulatorPageGui<SimulatorElement<?>> {
|
||||
}
|
||||
|
||||
if (simulatorGroup.getElements().removeIf(element -> element.getPhases().isEmpty())) {
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}
|
||||
if (simulatorGroup.getElements().size() < 2) {
|
||||
back.open();
|
||||
@@ -73,12 +75,11 @@ public class SimulatorGroupGui extends SimulatorPageGui<SimulatorElement<?>> {
|
||||
|
||||
inventory.setItem(8, new SWItem(Material.BARRIER, "§eDelete", clickType -> {
|
||||
simulatorGroup.getElements().clear();
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DELETE));
|
||||
|
||||
inventory.setItem(4, simulatorGroup.toItem(player, clickType -> {
|
||||
if (simulatorGroup.getMaterial() == null)
|
||||
return;
|
||||
if (simulatorGroup.getMaterial() == null) return;
|
||||
new SimulatorMaterialGui(player, simulator, simulatorGroup::getMaterial, simulatorGroup::setMaterial, this).open();
|
||||
}, clickType -> {
|
||||
}));
|
||||
@@ -86,19 +87,17 @@ public class SimulatorGroupGui extends SimulatorPageGui<SimulatorElement<?>> {
|
||||
inventory.setItem(48, new SWItem(Material.REPEATER, "§eSettings", clickType -> {
|
||||
new SimulatorGroupSettingsGui(player, simulator, simulatorGroup, this).open();
|
||||
}).setCustomModelData(CMDs.Simulator.SETTINGS));
|
||||
boolean disabled = simulatorGroup.getMaterial() == null ? simulatorGroup.getElements().stream().allMatch(SimulatorElement::isDisabled)
|
||||
: simulatorGroup.isDisabled();
|
||||
inventory.setItem(50,
|
||||
new SWItem(disabled ? Material.ENDER_PEARL : Material.ENDER_EYE, simulatorGroup.isDisabled() ? "§cDisabled" : "§aEnabled", clickType -> {
|
||||
if (simulatorGroup.getMaterial() == null) {
|
||||
simulatorGroup.getElements().forEach(simulatorElement -> {
|
||||
simulatorElement.setDisabled(!disabled);
|
||||
});
|
||||
} else {
|
||||
simulatorGroup.setDisabled(!disabled);
|
||||
}
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED));
|
||||
boolean disabled = simulatorGroup.getMaterial() == null ? simulatorGroup.getElements().stream().allMatch(SimulatorElement::isDisabled) : simulatorGroup.isDisabled();
|
||||
inventory.setItem(50, new SWItem(disabled ? Material.ENDER_PEARL : Material.ENDER_EYE, simulatorGroup.isDisabled() ? "§cDisabled" : "§aEnabled", clickType -> {
|
||||
if (simulatorGroup.getMaterial() == null) {
|
||||
simulatorGroup.getElements().forEach(simulatorElement -> {
|
||||
simulatorElement.setDisabled(!disabled);
|
||||
});
|
||||
} else {
|
||||
simulatorGroup.setDisabled(!disabled);
|
||||
}
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.data.CMDs;
|
||||
@@ -35,8 +37,7 @@ public class SimulatorGroupSettingsGui extends SimulatorBaseGui {
|
||||
private final SimulatorGroup simulatorGroup;
|
||||
private final SimulatorBaseGui back;
|
||||
|
||||
public SimulatorGroupSettingsGui(Player player, Simulator simulator, SimulatorGroup simulatorGroup,
|
||||
SimulatorBaseGui back) {
|
||||
public SimulatorGroupSettingsGui(Player player, Simulator simulator, SimulatorGroup simulatorGroup, SimulatorBaseGui back) {
|
||||
super(player, simulator, 5 * 9);
|
||||
this.simulatorGroup = simulatorGroup;
|
||||
this.back = back;
|
||||
@@ -61,169 +62,164 @@ public class SimulatorGroupSettingsGui extends SimulatorBaseGui {
|
||||
|
||||
// Material Chooser
|
||||
inventory.setItem(4, simulatorGroup.toItem(player, clickType -> {
|
||||
if (simulatorGroup.getMaterial() == null)
|
||||
return;
|
||||
new SimulatorMaterialGui(player, simulator, simulatorGroup::getMaterial, simulatorGroup::setMaterial, this)
|
||||
.open();
|
||||
if (simulatorGroup.getMaterial() == null) return;
|
||||
new SimulatorMaterialGui(player, simulator, simulatorGroup::getMaterial, simulatorGroup::setMaterial, this).open();
|
||||
}, clickType -> {
|
||||
}));
|
||||
|
||||
// Base Tick
|
||||
int baseTicks = simulatorGroup.getBaseTick();
|
||||
inventory.setItem(9,
|
||||
new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
simulatorGroup.changeBaseTicks(clickType.isShiftClick() ? 5 : 1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(9, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
simulatorGroup.changeBaseTicks(clickType.isShiftClick() ? 5 : 1);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
SWItem baseTick = new SWItem(Material.REPEATER, "§eTicks§8:§7 " + baseTicks, clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Ticks", baseTicks + "", Integer::parseInt, integer -> {
|
||||
if (integer < 0)
|
||||
return false;
|
||||
if (integer < 0) return false;
|
||||
simulatorGroup.changeBaseTicks(integer - baseTicks);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).setItem(Material.REPEATER).open();
|
||||
});
|
||||
baseTick.getItemStack().setAmount(Math.max(1, Math.min(baseTicks, 64)));
|
||||
inventory.setItem(18, baseTick);
|
||||
inventory.setItem(27, new SWItem(SWItem.getDye(baseTicks > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"),
|
||||
false, clickType -> {
|
||||
if (baseTicks - (clickType.isShiftClick() ? 5 : 1) < 0) {
|
||||
simulatorGroup.changeBaseTicks(-baseTicks);
|
||||
} else {
|
||||
simulatorGroup.changeBaseTicks(clickType.isShiftClick() ? -5 : -1);
|
||||
}
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
inventory.setItem(27, new SWItem(SWItem.getDye(baseTicks > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
if (baseTicks - (clickType.isShiftClick() ? 5 : 1) < 0) {
|
||||
simulatorGroup.changeBaseTicks(-baseTicks);
|
||||
} else {
|
||||
simulatorGroup.changeBaseTicks(clickType.isShiftClick() ? -5 : -1);
|
||||
}
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
boolean allTNT = simulatorGroup.getElements().stream().allMatch(TNTElement.class::isInstance);
|
||||
|
||||
if (allTNT) {
|
||||
// Subpixel Alignment
|
||||
inventory.setItem(21, new SWItem(Material.SUNFLOWER, "§7Align§8: §eCenter", clickType -> {
|
||||
simulatorGroup.getElements().stream().map(TNTElement.class::cast).forEach(tntElement -> {
|
||||
tntElement.alignX(0);
|
||||
tntElement.alignZ(0);
|
||||
});
|
||||
SimulatorRenderer.update(simulator);
|
||||
simulatorGroup.getElements().stream()
|
||||
.map(TNTElement.class::cast)
|
||||
.forEach(tntElement -> {
|
||||
tntElement.alignX(0);
|
||||
tntElement.alignZ(0);
|
||||
});
|
||||
SimulatorWatcher.update(simulator);
|
||||
}));
|
||||
|
||||
// Z
|
||||
SWItem negativZItem = new SWItem(Material.OAK_BUTTON, "§7Align§8: §eNegativ Z", clickType -> {
|
||||
simulatorGroup.getElements().stream().map(TNTElement.class::cast).forEach(tntElement -> {
|
||||
if (tntElement.getAlignment().getZ() != -1)
|
||||
tntElement.alignZ(-1);
|
||||
});
|
||||
SimulatorRenderer.update(simulator);
|
||||
simulatorGroup.getElements().stream()
|
||||
.map(TNTElement.class::cast)
|
||||
.forEach(tntElement -> {
|
||||
if (tntElement.getAlignment().getZ() != -1) tntElement.alignZ(-1);
|
||||
});
|
||||
SimulatorWatcher.update(simulator);
|
||||
});
|
||||
negativZItem.setEnchanted(
|
||||
simulatorGroup.getElements().stream().map(TNTElement.class::cast)
|
||||
.allMatch(tntElement -> tntElement.getAlignment().getZ() == -1));
|
||||
negativZItem.setEnchanted(simulatorGroup.getElements().stream()
|
||||
.map(TNTElement.class::cast)
|
||||
.allMatch(tntElement -> tntElement.getAlignment().getZ() == -1));
|
||||
inventory.setItem(20, negativZItem);
|
||||
|
||||
SWItem positivZItem = new SWItem(Material.OAK_BUTTON, "§7Align§8: §ePositiv Z", clickType -> {
|
||||
simulatorGroup.getElements().stream().map(TNTElement.class::cast).forEach(tntElement -> {
|
||||
if (tntElement.getAlignment().getZ() != 1)
|
||||
tntElement.alignZ(1);
|
||||
});
|
||||
SimulatorRenderer.update(simulator);
|
||||
simulatorGroup.getElements().stream()
|
||||
.map(TNTElement.class::cast)
|
||||
.forEach(tntElement -> {
|
||||
if (tntElement.getAlignment().getZ() != 1) tntElement.alignZ(1);
|
||||
});
|
||||
SimulatorWatcher.update(simulator);
|
||||
});
|
||||
positivZItem.setEnchanted(
|
||||
simulatorGroup.getElements().stream().map(TNTElement.class::cast)
|
||||
.allMatch(tntElement -> tntElement.getAlignment().getZ() == 1));
|
||||
positivZItem.setEnchanted(simulatorGroup.getElements().stream()
|
||||
.map(TNTElement.class::cast)
|
||||
.allMatch(tntElement -> tntElement.getAlignment().getZ() == 1));
|
||||
inventory.setItem(22, positivZItem);
|
||||
|
||||
// X
|
||||
SWItem negativXItem = new SWItem(Material.STONE_BUTTON, "§7Align§8: §eNegativ X", clickType -> {
|
||||
simulatorGroup.getElements().stream().map(TNTElement.class::cast).forEach(tntElement -> {
|
||||
if (tntElement.getAlignment().getX() != -1)
|
||||
tntElement.alignX(-1);
|
||||
});
|
||||
simulatorGroup.getElements().stream()
|
||||
.map(TNTElement.class::cast)
|
||||
.forEach(tntElement -> {
|
||||
if (tntElement.getAlignment().getX() != -1) tntElement.alignX(-1);
|
||||
});
|
||||
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
});
|
||||
negativXItem.setEnchanted(
|
||||
simulatorGroup.getElements().stream().map(TNTElement.class::cast)
|
||||
.allMatch(tntElement -> tntElement.getAlignment().getX() == -1));
|
||||
negativXItem.setEnchanted(simulatorGroup.getElements().stream()
|
||||
.map(TNTElement.class::cast)
|
||||
.allMatch(tntElement -> tntElement.getAlignment().getX() == -1));
|
||||
inventory.setItem(12, negativXItem);
|
||||
|
||||
SWItem positivXItem = new SWItem(Material.STONE_BUTTON, "§7Align§8: §ePositiv X", clickType -> {
|
||||
simulatorGroup.getElements().stream().map(TNTElement.class::cast).forEach(tntElement -> {
|
||||
if (tntElement.getAlignment().getX() != 1)
|
||||
tntElement.alignX(1);
|
||||
});
|
||||
SimulatorRenderer.update(simulator);
|
||||
SWItem positivXItem = new SWItem(Material.STONE_BUTTON, "§7Align§8: §ePositiv X", clickType -> {
|
||||
simulatorGroup.getElements().stream()
|
||||
.map(TNTElement.class::cast)
|
||||
.forEach(tntElement -> {
|
||||
if (tntElement.getAlignment().getX() != 1) tntElement.alignX(1);
|
||||
});
|
||||
SimulatorWatcher.update(simulator);
|
||||
});
|
||||
positivXItem.setEnchanted(
|
||||
simulatorGroup.getElements().stream().map(TNTElement.class::cast)
|
||||
.allMatch(tntElement -> tntElement.getAlignment().getX() == -1));
|
||||
positivXItem.setEnchanted(simulatorGroup.getElements().stream()
|
||||
.map(TNTElement.class::cast)
|
||||
.allMatch(tntElement -> tntElement.getAlignment().getX() == -1));
|
||||
inventory.setItem(30, positivXItem);
|
||||
}
|
||||
|
||||
// Pos X
|
||||
inventory.setItem(15, new SWItem(SWItem.getDye(10), "§e+1",
|
||||
Arrays.asList(allTNT ? "§7Shift§8: §e+0.0625" : "§7Shift§8: §e+5"), false, clickType -> {
|
||||
simulatorGroup.move(clickType.isShiftClick() ? (allTNT ? 0.0625 : 5) : 1, 0, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
//Pos X
|
||||
inventory.setItem(15, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList(allTNT ? "§7Shift§8: §e+0.0625" : "§7Shift§8: §e+5"), false, clickType -> {
|
||||
simulatorGroup.move(clickType.isShiftClick() ? (allTNT ? 0.0625 : 5) : 1, 0, 0);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(24, new SWItem(Material.PAPER, "§eX", clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Relative X", "", Double::parseDouble, number -> {
|
||||
if (!allTNT) {
|
||||
if(!allTNT){
|
||||
number = (double) Math.round(number);
|
||||
}
|
||||
simulatorGroup.move(number, 0, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).setItem(Material.PAPER).open();
|
||||
}));
|
||||
inventory.setItem(33, new SWItem(SWItem.getDye(1), "§e-1",
|
||||
Arrays.asList(allTNT ? "§7Shift§8: §e-0.0625" : "§7Shift§8: §e-5"), false, clickType -> {
|
||||
simulatorGroup.move(clickType.isShiftClick() ? (allTNT ? -0.0625 : -5) : -1, 0, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
inventory.setItem(33, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList(allTNT ? "§7Shift§8: §e-0.0625" : "§7Shift§8: §e-5"), false, clickType -> {
|
||||
simulatorGroup.move(clickType.isShiftClick() ? (allTNT ? -0.0625 : -5) : -1, 0, 0);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Pos Y
|
||||
inventory.setItem(16, new SWItem(SWItem.getDye(10), "§e+1",
|
||||
Arrays.asList(allTNT ? "§7Shift§8: §e+0.0625" : "§7Shift§8: §e+5"), false, clickType -> {
|
||||
simulatorGroup.move(0, clickType.isShiftClick() ? (allTNT ? 0.0625 : 5) : 1, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
//Pos Y
|
||||
inventory.setItem(16, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList(allTNT ? "§7Shift§8: §e+0.0625" : "§7Shift§8: §e+5"), false, clickType -> {
|
||||
simulatorGroup.move(0, clickType.isShiftClick() ? (allTNT ? 0.0625 : 5) : 1, 0);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(25, new SWItem(Material.PAPER, "§eY", clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Relative Y", "", Double::parseDouble, number -> {
|
||||
if (!allTNT) {
|
||||
if(!allTNT){
|
||||
number = (double) Math.round(number);
|
||||
}
|
||||
simulatorGroup.move(0, number, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).setItem(Material.PAPER).open();
|
||||
}));
|
||||
inventory.setItem(34, new SWItem(SWItem.getDye(1), "§e-1",
|
||||
Arrays.asList(allTNT ? "§7Shift§8: §e-0.0625" : "§7Shift§8: §e-5"), false, clickType -> {
|
||||
simulatorGroup.move(0, clickType.isShiftClick() ? (allTNT ? -0.0625 : -5) : -1, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED));
|
||||
inventory.setItem(34, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList(allTNT ? "§7Shift§8: §e-0.0625" : "§7Shift§8: §e-5"), false, clickType -> {
|
||||
simulatorGroup.move(0, clickType.isShiftClick() ? (allTNT ? -0.0625 : -5) : -1, 0);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED));
|
||||
|
||||
// Pos Z
|
||||
inventory.setItem(17, new SWItem(SWItem.getDye(10), "§e+1",
|
||||
Arrays.asList(allTNT ? "§7Shift§8: §e+0.0625" : "§7Shift§8: §e+5"), false, clickType -> {
|
||||
simulatorGroup.move(0, 0, clickType.isShiftClick() ? (allTNT ? 0.0625 : 5) : 1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
//Pos Z
|
||||
inventory.setItem(17, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList(allTNT ? "§7Shift§8: §e+0.0625" : "§7Shift§8: §e+5"), false, clickType -> {
|
||||
simulatorGroup.move(0, 0, clickType.isShiftClick() ? (allTNT ? 0.0625 : 5) : 1);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(26, new SWItem(Material.PAPER, "§eZ", clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Relative Z", "", Double::parseDouble, number -> {
|
||||
if (!allTNT) {
|
||||
if(!allTNT){
|
||||
number = (double) Math.round(number);
|
||||
}
|
||||
simulatorGroup.move(0, 0, number);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).setItem(Material.PAPER).open();
|
||||
}));
|
||||
inventory.setItem(35, new SWItem(SWItem.getDye(1), "§e-1",
|
||||
Arrays.asList(allTNT ? "§7Shift§8: §e-0.0625" : "§7Shift§8: §e-5"), false, clickType -> {
|
||||
simulatorGroup.move(0, 0, clickType.isShiftClick() ? (allTNT ? -0.0625 : -5) : -1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
inventory.setItem(35, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList(allTNT ? "§7Shift§8: §e-0.0625" : "§7Shift§8: §e-5"), false, clickType -> {
|
||||
simulatorGroup.move(0, 0, clickType.isShiftClick() ? (allTNT ? -0.0625 : -5) : -1);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,29 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorCursorManager;
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorCursor;
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorCursor;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorCursorMode;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorPageGui;
|
||||
import de.steamwar.data.CMDs;
|
||||
import de.steamwar.inventory.SWItem;
|
||||
@@ -33,8 +32,6 @@ import org.bukkit.entity.Player;
|
||||
|
||||
public class SimulatorGui extends SimulatorPageGui<SimulatorGroup> {
|
||||
|
||||
private final SimulatorCursorManager cursorManager = BauSystem.getInstance().getLinker().get(SimulatorCursorManager.class).orElseThrow();
|
||||
|
||||
public SimulatorGui(Player player, Simulator simulator) {
|
||||
super(player, simulator, 6 * 9, simulator.getGroups());
|
||||
}
|
||||
@@ -46,15 +43,14 @@ public class SimulatorGui extends SimulatorPageGui<SimulatorGroup> {
|
||||
|
||||
@Override
|
||||
public void headerAndFooter() {
|
||||
if (simulator.getGroups().removeIf(element -> element.getElements().isEmpty()
|
||||
|| element.getElements().stream().allMatch(simulatorElement -> simulatorElement.getPhases().isEmpty()))) {
|
||||
SimulatorRenderer.update(simulator);
|
||||
if (simulator.getGroups().removeIf(element -> element.getElements().isEmpty() || element.getElements().stream().allMatch(simulatorElement -> simulatorElement.getPhases().isEmpty()))) {
|
||||
SimulatorWatcher.update(simulator);
|
||||
}
|
||||
|
||||
inventory.setItem(4, simulator.toItem(player, clickType -> {
|
||||
new SimulatorMaterialGui(player, simulator, simulator::getMaterial, simulator::setMaterial, this).open();
|
||||
}));
|
||||
SimulatorCursorMode cursorType = cursorManager.getActiveCursorMode(player).orElse(SimulatorCursorMode.TNT);
|
||||
SimulatorCursor.CursorType cursorType = SimulatorCursor.getCursorType(player);
|
||||
inventory.setItem(48, new SWItem(cursorType.material, "§7Placing §8-§e " + cursorType.name, clickType -> {
|
||||
new SimulatorCursorSwitcherGui(player, simulator, this).open();
|
||||
}));
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorPageGui;
|
||||
import de.steamwar.data.CMDs;
|
||||
@@ -34,8 +36,11 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class SimulatorMaterialGui extends SimulatorPageGui<Material> {
|
||||
|
||||
private static final List<Material> MATERIALS = Arrays.stream(Material.values()).filter(material -> !material.isAir())
|
||||
.filter(material -> !material.isLegacy()).filter(Material::isItem).collect(Collectors.toList());
|
||||
private static final List<Material> MATERIALS = Arrays.stream(Material.values())
|
||||
.filter(material -> !material.isAir())
|
||||
.filter(material -> !material.isLegacy())
|
||||
.filter(Material::isItem)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
private final Supplier<Material> currentMaterial;
|
||||
private Material material;
|
||||
@@ -55,7 +60,7 @@ public class SimulatorMaterialGui extends SimulatorPageGui<Material> {
|
||||
return true;
|
||||
}
|
||||
change.accept(player.getItemOnCursor().getType());
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -76,10 +81,9 @@ public class SimulatorMaterialGui extends SimulatorPageGui<Material> {
|
||||
|
||||
@Override
|
||||
public SWItem convert(Material material) {
|
||||
return new SWItem(material, "§eNew Material", Arrays.asList(material == this.material ? "§eSelected" : "§eClick to select"), material == this.material,
|
||||
clickType -> {
|
||||
change.accept(material);
|
||||
SimulatorRenderer.update(simulator);
|
||||
});
|
||||
return new SWItem(material, "§eNew Material", Arrays.asList(material == this.material ? "§eSelected" : "§eClick to select"), material == this.material, clickType -> {
|
||||
change.accept(material);
|
||||
SimulatorWatcher.update(simulator);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
|
||||
import de.steamwar.bausystem.features.simulator.data.observer.ObserverElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.observer.ObserverPhase;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorScrollGui;
|
||||
import de.steamwar.data.CMDs;
|
||||
@@ -58,7 +60,7 @@ public class SimulatorObserverGui extends SimulatorScrollGui<ObserverPhase> {
|
||||
public void headerAndFooter() {
|
||||
if (observer.getPhases().isEmpty()) {
|
||||
back.open();
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -85,7 +87,7 @@ public class SimulatorObserverGui extends SimulatorScrollGui<ObserverPhase> {
|
||||
|
||||
inventory.setItem(8, new SWItem(Material.BARRIER, "§eDelete", clickType -> {
|
||||
observer.getPhases().clear();
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DELETE));
|
||||
|
||||
// Material Chooser
|
||||
@@ -99,11 +101,10 @@ public class SimulatorObserverGui extends SimulatorScrollGui<ObserverPhase> {
|
||||
}).setCustomModelData(CMDs.Simulator.SETTINGS));
|
||||
|
||||
// Enable/Disable
|
||||
inventory.setItem(48,
|
||||
new SWItem(observer.isDisabled() ? Material.ENDER_PEARL : Material.ENDER_EYE, observer.isDisabled() ? "§cDisabled" : "§aEnabled", clickType -> {
|
||||
observer.setDisabled(!observer.isDisabled());
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED));
|
||||
inventory.setItem(48, new SWItem(observer.isDisabled() ? Material.ENDER_PEARL : Material.ENDER_EYE, observer.isDisabled() ? "§cDisabled" : "§aEnabled", clickType -> {
|
||||
observer.setDisabled(!observer.isDisabled());
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED));
|
||||
|
||||
// Group chooser
|
||||
inventory.setItem(51, new SWItem(Material.LEAD, "§eJoin Group", clickType -> {
|
||||
@@ -138,7 +139,7 @@ public class SimulatorObserverGui extends SimulatorScrollGui<ObserverPhase> {
|
||||
SWItem observer = new SWItem(Material.OBSERVER, "§eObserver", lore, false, clickType -> {
|
||||
if (clickType == ClickType.MIDDLE) {
|
||||
this.observer.getPhases().remove(observerPhase);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
} else {
|
||||
new SimulatorObserverPhaseSettingsGui(player, simulator, this.observer, observerPhase, this).open();
|
||||
}
|
||||
@@ -147,35 +148,42 @@ public class SimulatorObserverGui extends SimulatorScrollGui<ObserverPhase> {
|
||||
|
||||
Supplier<Integer> getter = observerPhase::getTickOffset;
|
||||
Consumer<Integer> setter = observerPhase::setTickOffset;
|
||||
return new SWItem[] {new SWItem(SWItem.getDye(getter.get() < max ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
|
||||
setter.accept(Math.min(max, getter.get() + (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED), observer,
|
||||
return new SWItem[] {
|
||||
new SWItem(SWItem.getDye(getter.get() < max ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
|
||||
setter.accept(Math.min(max, getter.get() + (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED),
|
||||
observer,
|
||||
new SWItem(SWItem.getDye(getter.get() > min ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8:§e -5"), false, clickType -> {
|
||||
setter.accept(Math.max(min, getter.get() - (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED), new SWItem(Material.ANVIL, "§eEdit Activation", clickType -> {
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED),
|
||||
new SWItem(Material.ANVIL, "§eEdit Activation", clickType -> {
|
||||
new SimulatorObserverPhaseSettingsGui(player, simulator, this.observer, observerPhase, this).open();
|
||||
}).setCustomModelData(CMDs.Simulator.EDIT_ACTIVATION),};
|
||||
}).setCustomModelData(CMDs.Simulator.EDIT_ACTIVATION),
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public SWItem[] lastColumn() {
|
||||
return new SWItem[] {new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
|
||||
addNewPhase(clickType.isShiftClick());
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED), new SWItem(Material.QUARTZ, "§eObserver§8:§a New Phase", clickType -> {
|
||||
addNewPhase(false);
|
||||
}).setCustomModelData(CMDs.Simulator.NEW_PHASE), new SWItem(SWItem.getDye(8), "§7", clickType -> {
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED),};
|
||||
return new SWItem[]{
|
||||
new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
|
||||
addNewPhase(clickType.isShiftClick());
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED),
|
||||
new SWItem(Material.QUARTZ, "§eObserver§8:§a New Phase", clickType -> {
|
||||
addNewPhase(false);
|
||||
}).setCustomModelData(CMDs.Simulator.NEW_PHASE),
|
||||
new SWItem(SWItem.getDye(8), "§7", clickType -> {
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED),
|
||||
};
|
||||
}
|
||||
|
||||
private void addNewPhase(boolean shift) {
|
||||
ObserverPhase lastElement = observer.getPhases().get(observer.getPhases().size() - 1);
|
||||
ObserverPhase newPhase = new ObserverPhase(lastElement.getTickOffset() + 4);
|
||||
if (shift)
|
||||
newPhase.setTickOffset(newPhase.getTickOffset() + 5);
|
||||
if (shift) newPhase.setTickOffset(newPhase.getTickOffset() + 5);
|
||||
scroll += 2;
|
||||
observer.add(newPhase);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorPhase;
|
||||
import de.steamwar.bausystem.features.simulator.data.observer.ObserverElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.observer.ObserverPhase;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.core.Core;
|
||||
@@ -39,8 +41,7 @@ public class SimulatorObserverPhaseSettingsGui extends SimulatorBaseGui {
|
||||
private final ObserverPhase observer;
|
||||
private final SimulatorBaseGui back;
|
||||
|
||||
public SimulatorObserverPhaseSettingsGui(Player player, Simulator simulator, ObserverElement observerElement, ObserverPhase observer,
|
||||
SimulatorBaseGui back) {
|
||||
public SimulatorObserverPhaseSettingsGui(Player player, Simulator simulator, ObserverElement observerElement, ObserverPhase observer, SimulatorBaseGui back) {
|
||||
super(player, simulator, 5 * 9);
|
||||
this.observerElement = observerElement;
|
||||
this.observer = observer;
|
||||
@@ -73,7 +74,7 @@ public class SimulatorObserverPhaseSettingsGui extends SimulatorBaseGui {
|
||||
inventory.setItem(8, new SWItem(Material.BARRIER, "§eDelete", clickType -> {
|
||||
observerElement.getPhases().remove(observer);
|
||||
back.open();
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DELETE));
|
||||
|
||||
int index = observerElement.getPhases().indexOf(observer);
|
||||
@@ -93,19 +94,18 @@ public class SimulatorObserverPhaseSettingsGui extends SimulatorBaseGui {
|
||||
max = Integer.MAX_VALUE - 4;
|
||||
}
|
||||
|
||||
// Tick Offset
|
||||
//Tick Offset
|
||||
int offset = observer.getTickOffset();
|
||||
inventory.setItem(10, new SWItem(SWItem.getDye(offset < max ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
observer.setTickOffset(Math.min(max, offset + (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
|
||||
SWItem offsetItem = new SWItem(Material.REPEATER, "§eStart at§8:§7 " + offset, clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Start at", offset + "", Integer::parseInt, integer -> {
|
||||
if (integer < 0)
|
||||
return false;
|
||||
if (integer < 0) return false;
|
||||
observer.setTickOffset(Math.min(Math.max(integer, min), max));
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).setItem(Material.REPEATER).open();
|
||||
});
|
||||
@@ -114,66 +114,60 @@ public class SimulatorObserverPhaseSettingsGui extends SimulatorBaseGui {
|
||||
|
||||
inventory.setItem(28, new SWItem(SWItem.getDye(offset > min ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
observer.setTickOffset(Math.max(min, offset - (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Order
|
||||
//Order
|
||||
int order = observer.getOrder();
|
||||
inventory.setItem(13,
|
||||
new SWItem(SWItem.getDye(order < SimulatorPhase.ORDER_LIMIT ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
observer.setOrder(Math.min(SimulatorPhase.ORDER_LIMIT, order + (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(13, new SWItem(SWItem.getDye(order < SimulatorPhase.ORDER_LIMIT ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
observer.setOrder(Math.min(SimulatorPhase.ORDER_LIMIT, order + (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
|
||||
Material negativeNumbers = Material.getMaterial(Core.getVersion() >= 19 ? "RECOVERY_COMPASS" : "FIREWORK_STAR");
|
||||
SWItem orderItem = new SWItem(order >= 0 ? Material.COMPASS : negativeNumbers, "§eActivation Order§8:§7 " + order, clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Activation Order", order + "", Integer::parseInt, integer -> {
|
||||
if (integer < -SimulatorPhase.ORDER_LIMIT)
|
||||
return false;
|
||||
if (integer > SimulatorPhase.ORDER_LIMIT)
|
||||
return false;
|
||||
if (integer < -SimulatorPhase.ORDER_LIMIT) return false;
|
||||
if (integer > SimulatorPhase.ORDER_LIMIT) return false;
|
||||
observer.setOrder(integer);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).setItem(order >= 0 ? Material.COMPASS : negativeNumbers).open();
|
||||
});
|
||||
orderItem.getItemStack().setAmount(Math.max(1, Math.min(Math.abs(order), 30)));
|
||||
inventory.setItem(22, orderItem);
|
||||
|
||||
inventory.setItem(31,
|
||||
new SWItem(SWItem.getDye(order > -SimulatorPhase.ORDER_LIMIT ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
observer.setOrder(Math.max(-SimulatorPhase.ORDER_LIMIT, order - (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
inventory.setItem(31, new SWItem(SWItem.getDye(order > -SimulatorPhase.ORDER_LIMIT ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
observer.setOrder(Math.max(-SimulatorPhase.ORDER_LIMIT, order - (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Update orientation
|
||||
inventory.setItem(25, new SWItem(Material.SUNFLOWER, "§7", clickType -> {
|
||||
}));
|
||||
inventory.setItem(15, new SWItem(observer.getOrientation() == BlockFace.UP ? Material.LIME_CONCRETE : Material.GRAY_CONCRETE, "§eUp", clickType -> {
|
||||
observer.setOrientation(BlockFace.UP);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}));
|
||||
inventory.setItem(33, new SWItem(observer.getOrientation() == BlockFace.DOWN ? Material.RED_CONCRETE : Material.GRAY_CONCRETE, "§eDown", clickType -> {
|
||||
observer.setOrientation(BlockFace.DOWN);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}));
|
||||
inventory.setItem(16, new SWItem(observer.getOrientation() == BlockFace.NORTH ? Material.LIME_WOOL : Material.GRAY_WOOL, "§eNorth", clickType -> {
|
||||
observer.setOrientation(BlockFace.NORTH);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}));
|
||||
inventory.setItem(34, new SWItem(observer.getOrientation() == BlockFace.SOUTH ? Material.RED_WOOL : Material.GRAY_WOOL, "§eSouth", clickType -> {
|
||||
observer.setOrientation(BlockFace.SOUTH);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}));
|
||||
inventory.setItem(24, new SWItem(observer.getOrientation() == BlockFace.EAST ? Material.LIME_STAINED_GLASS : Material.GRAY_STAINED_GLASS, "§eEast", clickType -> {
|
||||
observer.setOrientation(BlockFace.EAST);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}));
|
||||
inventory.setItem(26, new SWItem(observer.getOrientation() == BlockFace.WEST ? Material.RED_STAINED_GLASS : Material.GRAY_STAINED_GLASS, "§eWest", clickType -> {
|
||||
observer.setOrientation(BlockFace.WEST);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}));
|
||||
inventory.setItem(24,
|
||||
new SWItem(observer.getOrientation() == BlockFace.EAST ? Material.LIME_STAINED_GLASS : Material.GRAY_STAINED_GLASS, "§eEast", clickType -> {
|
||||
observer.setOrientation(BlockFace.EAST);
|
||||
SimulatorRenderer.update(simulator);
|
||||
}));
|
||||
inventory.setItem(26,
|
||||
new SWItem(observer.getOrientation() == BlockFace.WEST ? Material.RED_STAINED_GLASS : Material.GRAY_STAINED_GLASS, "§eWest", clickType -> {
|
||||
observer.setOrientation(BlockFace.WEST);
|
||||
SimulatorRenderer.update(simulator);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.observer.ObserverElement;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.data.CMDs;
|
||||
@@ -66,14 +68,13 @@ public class SimulatorObserverSettingsGui extends SimulatorBaseGui {
|
||||
int baseTicks = observer.getBaseTick();
|
||||
inventory.setItem(9, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
observer.changeBaseTicks(clickType.isShiftClick() ? 5 : 1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
SWItem baseTick = new SWItem(Material.REPEATER, "§eTicks§8:§7 " + baseTicks, clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Ticks", baseTicks + "", Integer::parseInt, integer -> {
|
||||
if (integer < 0)
|
||||
return false;
|
||||
if (integer < 0) return false;
|
||||
observer.changeBaseTicks(integer - baseTicks);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).setItem(Material.REPEATER).open();
|
||||
});
|
||||
@@ -85,58 +86,58 @@ public class SimulatorObserverSettingsGui extends SimulatorBaseGui {
|
||||
} else {
|
||||
observer.changeBaseTicks(clickType.isShiftClick() ? -5 : -1);
|
||||
}
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Pos X
|
||||
inventory.setItem(15, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
//Pos X
|
||||
inventory.setItem(15, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
observer.move(clickType.isShiftClick() ? 5 : 1, 0, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(24, new SWItem(Material.PAPER, "§eX§8:§7 " + observer.getPosition().getBlockX(), clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "X", observer.getPosition().getBlockX() + "", Integer::parseInt, i -> {
|
||||
observer.getPosition().setX(i);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).open();
|
||||
}));
|
||||
inventory.setItem(33, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
observer.move(clickType.isShiftClick() ? -5 : -1, 0, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Pos Y
|
||||
//Pos Y
|
||||
inventory.setItem(16, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
observer.move(0, clickType.isShiftClick() ? 5 : 1, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED));
|
||||
inventory.setItem(25, new SWItem(Material.PAPER, "§eY§8:§7 " + observer.getPosition().getBlockY(), clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Y", observer.getPosition().getBlockY() + "", Integer::parseInt, i -> {
|
||||
observer.getPosition().setY(i);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).open();
|
||||
}));
|
||||
inventory.setItem(34, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
observer.move(0, clickType.isShiftClick() ? -5 : -1, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Pos Z
|
||||
//Pos Z
|
||||
inventory.setItem(17, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
observer.move(0, 0, clickType.isShiftClick() ? 5 : 1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED));
|
||||
inventory.setItem(26, new SWItem(Material.PAPER, "§eZ§8:§7 " + observer.getPosition().getBlockZ(), clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Z", observer.getPosition().getBlockZ() + "", Integer::parseInt, i -> {
|
||||
observer.getPosition().setZ(i);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).open();
|
||||
}));
|
||||
inventory.setItem(35, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
observer.move(0, 0, clickType.isShiftClick() ? -5 : -1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
|
||||
import de.steamwar.bausystem.features.simulator.data.redstone.RedstoneElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.redstone.RedstonePhase;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorScrollGui;
|
||||
import de.steamwar.data.CMDs;
|
||||
@@ -59,7 +61,7 @@ public class SimulatorRedstoneGui extends SimulatorScrollGui<SimulatorRedstoneGu
|
||||
public void headerAndFooter() {
|
||||
if (redstone.getPhases().isEmpty()) {
|
||||
back.open();
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -91,7 +93,7 @@ public class SimulatorRedstoneGui extends SimulatorScrollGui<SimulatorRedstoneGu
|
||||
|
||||
inventory.setItem(8, new SWItem(Material.BARRIER, "§eDelete", clickType -> {
|
||||
redstone.getPhases().clear();
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DELETE));
|
||||
|
||||
// Material Chooser
|
||||
@@ -105,11 +107,10 @@ public class SimulatorRedstoneGui extends SimulatorScrollGui<SimulatorRedstoneGu
|
||||
}).setCustomModelData(CMDs.Simulator.SETTINGS));
|
||||
|
||||
// Enable/Disable
|
||||
inventory.setItem(48,
|
||||
new SWItem(redstone.isDisabled() ? Material.ENDER_PEARL : Material.ENDER_EYE, redstone.isDisabled() ? "§cDisabled" : "§aEnabled", clickType -> {
|
||||
redstone.setDisabled(!redstone.isDisabled());
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED));
|
||||
inventory.setItem(48, new SWItem(redstone.isDisabled() ? Material.ENDER_PEARL : Material.ENDER_EYE, redstone.isDisabled() ? "§cDisabled" : "§aEnabled", clickType -> {
|
||||
redstone.setDisabled(!redstone.isDisabled());
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED));
|
||||
|
||||
// Group chooser
|
||||
inventory.setItem(51, new SWItem(Material.LEAD, "§eJoin Group", clickType -> {
|
||||
@@ -150,49 +151,55 @@ public class SimulatorRedstoneGui extends SimulatorScrollGui<SimulatorRedstoneGu
|
||||
lore.add("");
|
||||
lore.add("§7Click§8:§e Edit");
|
||||
lore.add("§7Middle-Click§8:§e Remove");
|
||||
SWItem redstone = new SWItem(redstoneSubPhase.place ? Material.REDSTONE_BLOCK : Material.STONE, redstoneSubPhase.place ? "§eActivate" : "§eDeactivate",
|
||||
lore, false, clickType -> {
|
||||
if (clickType == ClickType.MIDDLE) {
|
||||
this.redstone.getPhases().remove(redstoneSubPhase.phase);
|
||||
SimulatorRenderer.update(simulator);
|
||||
} else {
|
||||
new SimulatorRedstonePhaseSettingsGui(player, simulator, this.redstone, redstoneSubPhase.phase, this).open();
|
||||
}
|
||||
});
|
||||
SWItem redstone = new SWItem(redstoneSubPhase.place ? Material.REDSTONE_BLOCK : Material.STONE, redstoneSubPhase.place ? "§eActivate" : "§eDeactivate", lore, false, clickType -> {
|
||||
if (clickType == ClickType.MIDDLE) {
|
||||
this.redstone.getPhases().remove(redstoneSubPhase.phase);
|
||||
SimulatorWatcher.update(simulator);
|
||||
} else {
|
||||
new SimulatorRedstonePhaseSettingsGui(player, simulator, this.redstone, redstoneSubPhase.phase, this).open();
|
||||
}
|
||||
});
|
||||
redstone.getItemStack().setAmount(Math.max(1, Math.min(time, 64)));
|
||||
|
||||
Supplier<Integer> getter = redstoneSubPhase.place ? redstoneSubPhase.phase::getTickOffset : redstoneSubPhase.phase::getLifetime;
|
||||
Consumer<Integer> setter = redstoneSubPhase.place ? redstoneSubPhase.phase::setTickOffset : redstoneSubPhase.phase::setLifetime;
|
||||
return new SWItem[] {new SWItem(SWItem.getDye(getter.get() < max ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
|
||||
setter.accept(Math.min(max, getter.get() + (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED), redstone,
|
||||
return new SWItem[] {
|
||||
new SWItem(SWItem.getDye(getter.get() < max ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
|
||||
setter.accept(Math.min(max, getter.get() + (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED),
|
||||
redstone,
|
||||
new SWItem(SWItem.getDye(getter.get() > min ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8:§e -5"), false, clickType -> {
|
||||
setter.accept(Math.max(min, getter.get() - (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED), new SWItem(Material.ANVIL, "§eEdit Activation", clickType -> {
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED),
|
||||
new SWItem(Material.ANVIL, "§eEdit Activation", clickType -> {
|
||||
new SimulatorRedstonePhaseSettingsGui(player, simulator, this.redstone, redstoneSubPhase.phase, this).open();
|
||||
}).setCustomModelData(CMDs.Simulator.EDIT_ACTIVATION),};
|
||||
}).setCustomModelData(CMDs.Simulator.EDIT_ACTIVATION),
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public SWItem[] lastColumn() {
|
||||
return new SWItem[] {new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
|
||||
addNewPhase(clickType.isShiftClick());
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED), new SWItem(Material.REDSTONE, "§eRedstone§8:§a New Phase", clickType -> {
|
||||
addNewPhase(false);
|
||||
}).setCustomModelData(CMDs.Simulator.NEW_PHASE), new SWItem(SWItem.getDye(8), "§7", clickType -> {
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED),};
|
||||
return new SWItem[]{
|
||||
new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
|
||||
addNewPhase(clickType.isShiftClick());
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED),
|
||||
new SWItem(Material.REDSTONE, "§eRedstone§8:§a New Phase", clickType -> {
|
||||
addNewPhase(false);
|
||||
}).setCustomModelData(CMDs.Simulator.NEW_PHASE),
|
||||
new SWItem(SWItem.getDye(8), "§7", clickType -> {
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED),
|
||||
};
|
||||
}
|
||||
|
||||
private void addNewPhase(boolean shift) {
|
||||
RedstonePhase lastElement = redstone.getPhases().get(redstone.getPhases().size() - 1);
|
||||
RedstonePhase newPhase = new RedstonePhase(lastElement.getTickOffset() + lastElement.getLifetime() + 1);
|
||||
if (shift)
|
||||
newPhase.setTickOffset(newPhase.getTickOffset() + 5);
|
||||
if (shift) newPhase.setTickOffset(newPhase.getTickOffset() + 5);
|
||||
scroll += 2;
|
||||
redstone.add(newPhase);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorPhase;
|
||||
import de.steamwar.bausystem.features.simulator.data.redstone.RedstoneElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.redstone.RedstonePhase;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.core.Core;
|
||||
@@ -37,8 +39,7 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui {
|
||||
private final RedstonePhase redstone;
|
||||
private final SimulatorBaseGui back;
|
||||
|
||||
public SimulatorRedstonePhaseSettingsGui(Player player, Simulator simulator, RedstoneElement redstoneElement, RedstonePhase redstone,
|
||||
SimulatorBaseGui back) {
|
||||
public SimulatorRedstonePhaseSettingsGui(Player player, Simulator simulator, RedstoneElement redstoneElement, RedstonePhase redstone, SimulatorBaseGui back) {
|
||||
super(player, simulator, 5 * 9);
|
||||
this.redstoneElement = redstoneElement;
|
||||
this.redstone = redstone;
|
||||
@@ -71,7 +72,7 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui {
|
||||
inventory.setItem(8, new SWItem(Material.BARRIER, "§eDelete", clickType -> {
|
||||
redstoneElement.getPhases().remove(redstone);
|
||||
back.open();
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DELETE));
|
||||
|
||||
int index = redstoneElement.getPhases().indexOf(redstone);
|
||||
@@ -94,19 +95,18 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui {
|
||||
maxOffset = Integer.MAX_VALUE - 5;
|
||||
}
|
||||
|
||||
// Tick Offset
|
||||
//Tick Offset
|
||||
int offset = redstone.getTickOffset();
|
||||
inventory.setItem(10, new SWItem(SWItem.getDye(offset < maxOffset ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
redstone.setTickOffset(Math.min(maxOffset, offset + (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
|
||||
SWItem offsetItem = new SWItem(Material.REPEATER, "§eStart at§8:§7 " + offset, clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Start at", offset + "", Integer::parseInt, integer -> {
|
||||
if (integer < 0)
|
||||
return false;
|
||||
if (integer < 0) return false;
|
||||
redstone.setTickOffset(Math.min(Math.max(integer, min), maxOffset));
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).setItem(Material.REPEATER).open();
|
||||
});
|
||||
@@ -115,22 +115,21 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui {
|
||||
|
||||
inventory.setItem(28, new SWItem(SWItem.getDye(offset > min ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
redstone.setTickOffset(Math.max(min, offset - (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Lifetime
|
||||
//Lifetime
|
||||
int lifetime = redstone.getLifetime();
|
||||
inventory.setItem(11, new SWItem(SWItem.getDye(lifetime < maxLifetime ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
redstone.setLifetime(Math.min(maxLifetime, lifetime + (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
|
||||
SWItem lifetimeItem = new SWItem(Material.CLOCK, "§eActivation Time§8:§7 " + lifetime, clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Activation Time", lifetime + "", Integer::parseInt, integer -> {
|
||||
if (integer < 0)
|
||||
return false;
|
||||
if (integer < 0) return false;
|
||||
redstone.setLifetime(Math.min(integer, maxLifetime));
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).setItem(Material.CLOCK).open();
|
||||
});
|
||||
@@ -139,36 +138,32 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui {
|
||||
|
||||
inventory.setItem(29, new SWItem(SWItem.getDye(lifetime > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
redstone.setLifetime(Math.max(0, lifetime - (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Order
|
||||
//Order
|
||||
int order = redstone.getOrder();
|
||||
inventory.setItem(13,
|
||||
new SWItem(SWItem.getDye(order < SimulatorPhase.ORDER_LIMIT ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
redstone.setOrder(Math.min(SimulatorPhase.ORDER_LIMIT, order + (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(13, new SWItem(SWItem.getDye(order < SimulatorPhase.ORDER_LIMIT ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
redstone.setOrder(Math.min(SimulatorPhase.ORDER_LIMIT, order + (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
|
||||
Material negativeNumbers = Material.getMaterial(Core.getVersion() >= 19 ? "RECOVERY_COMPASS" : "FIREWORK_STAR");
|
||||
SWItem orderItem = new SWItem(order >= 0 ? Material.COMPASS : negativeNumbers, "§eActivation Order§8:§7 " + order, clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Activation Order", order + "", Integer::parseInt, integer -> {
|
||||
if (integer < -SimulatorPhase.ORDER_LIMIT)
|
||||
return false;
|
||||
if (integer > SimulatorPhase.ORDER_LIMIT)
|
||||
return false;
|
||||
if (integer < -SimulatorPhase.ORDER_LIMIT) return false;
|
||||
if (integer > SimulatorPhase.ORDER_LIMIT) return false;
|
||||
redstone.setOrder(integer);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).setItem(order >= 0 ? Material.COMPASS : negativeNumbers).open();
|
||||
});
|
||||
orderItem.getItemStack().setAmount(Math.max(1, Math.min(Math.abs(order), 30)));
|
||||
inventory.setItem(22, orderItem);
|
||||
|
||||
inventory.setItem(31,
|
||||
new SWItem(SWItem.getDye(order > -SimulatorPhase.ORDER_LIMIT ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
redstone.setOrder(Math.max(-SimulatorPhase.ORDER_LIMIT, order - (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
inventory.setItem(31, new SWItem(SWItem.getDye(order > -SimulatorPhase.ORDER_LIMIT ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
redstone.setOrder(Math.max(-SimulatorPhase.ORDER_LIMIT, order - (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.redstone.RedstoneElement;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.data.CMDs;
|
||||
@@ -65,14 +67,13 @@ public class SimulatorRedstoneSettingsGui extends SimulatorBaseGui {
|
||||
int baseTicks = redstone.getBaseTick();
|
||||
inventory.setItem(9, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
redstone.changeBaseTicks(clickType.isShiftClick() ? 5 : 1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
SWItem baseTick = new SWItem(Material.REPEATER, "§eTicks§8:§7 " + baseTicks, clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Ticks", baseTicks + "", Integer::parseInt, integer -> {
|
||||
if (integer < 0)
|
||||
return false;
|
||||
if (integer < 0) return false;
|
||||
redstone.changeBaseTicks(integer - baseTicks);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).setItem(Material.REPEATER).open();
|
||||
});
|
||||
@@ -84,58 +85,58 @@ public class SimulatorRedstoneSettingsGui extends SimulatorBaseGui {
|
||||
} else {
|
||||
redstone.changeBaseTicks(clickType.isShiftClick() ? -5 : -1);
|
||||
}
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Pos X
|
||||
//Pos X
|
||||
inventory.setItem(15, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
redstone.move(clickType.isShiftClick() ? 5 : 1, 0, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(24, new SWItem(Material.PAPER, "§eX§8:§7 " + redstone.getPosition().getBlockX(), clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "X", redstone.getPosition().getBlockX() + "", Integer::parseInt, i -> {
|
||||
redstone.getPosition().setX(i);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).open();
|
||||
}));
|
||||
inventory.setItem(33, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
redstone.move(clickType.isShiftClick() ? -5 : -1, 0, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Pos Y
|
||||
//Pos Y
|
||||
inventory.setItem(16, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
redstone.move(0, clickType.isShiftClick() ? 5 : 1, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(25, new SWItem(Material.PAPER, "§eY§8:§7 " + redstone.getPosition().getBlockY(), clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Y", redstone.getPosition().getBlockY() + "", Integer::parseInt, i -> {
|
||||
redstone.getPosition().setY(i);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).open();
|
||||
}));
|
||||
inventory.setItem(34, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
redstone.move(0, clickType.isShiftClick() ? -5 : -1, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Pos Z
|
||||
//Pos Z
|
||||
inventory.setItem(17, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
redstone.move(0, 0, clickType.isShiftClick() ? 5 : 1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(26, new SWItem(Material.PAPER, "§eZ§8:§7 " + redstone.getPosition().getBlockZ(), clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Z", redstone.getPosition().getBlockZ() + "", Integer::parseInt, i -> {
|
||||
redstone.getPosition().setZ(i);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).open();
|
||||
}));
|
||||
inventory.setItem(35, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
redstone.move(0, 0, clickType.isShiftClick() ? -5 : -1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.data.CMDs;
|
||||
import de.steamwar.inventory.SWItem;
|
||||
@@ -53,52 +55,50 @@ public class SimulatorSettingsGui extends SimulatorBaseGui {
|
||||
new SimulatorMaterialGui(player, simulator, simulator::getMaterial, simulator::setMaterial, this).open();
|
||||
}));
|
||||
|
||||
// AutoTrace
|
||||
inventory.setItem(19, new SWItem(simulator.isAutoTrace() ? Material.CHAIN_COMMAND_BLOCK : Material.COMMAND_BLOCK,
|
||||
"§eAutoTrace§8: " + (simulator.isAutoTrace() ? "§aOn" : "§cOff"), clickType -> {
|
||||
simulator.setAutoTrace(!simulator.isAutoTrace());
|
||||
SimulatorRenderer.update(simulator);
|
||||
}));
|
||||
inventory.setItem(20, new SWItem(simulator.isAutoTestblock() ? Material.END_STONE : Material.BARRIER,
|
||||
"§eTestblock§8: " + (simulator.isAutoTestblock() ? "§aOn" : "§cOff"), clickType -> {
|
||||
simulator.setAutoTestblock(!simulator.isAutoTestblock());
|
||||
SimulatorRenderer.update(simulator);
|
||||
}));
|
||||
//AutoTrace
|
||||
inventory.setItem(19, new SWItem(simulator.isAutoTrace() ? Material.CHAIN_COMMAND_BLOCK : Material.COMMAND_BLOCK, "§eAutoTrace§8: " + (simulator.isAutoTrace() ? "§aOn" : "§cOff"), clickType -> {
|
||||
simulator.setAutoTrace(!simulator.isAutoTrace());
|
||||
SimulatorWatcher.update(simulator);
|
||||
}));
|
||||
inventory.setItem(20, new SWItem(simulator.isAutoTestblock() ? Material.END_STONE : Material.BARRIER, "§eTestblock§8: " + (simulator.isAutoTestblock() ? "§aOn" : "§cOff"), clickType -> {
|
||||
simulator.setAutoTestblock(!simulator.isAutoTestblock());
|
||||
SimulatorWatcher.update(simulator);
|
||||
}));
|
||||
|
||||
// Pos X
|
||||
//Pos X
|
||||
inventory.setItem(15, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
simulator.move(clickType.isShiftClick() ? 5 : 1, 0, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(24, new SWItem(Material.PAPER, "§eX", clickType -> {
|
||||
}));
|
||||
inventory.setItem(33, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
simulator.move(clickType.isShiftClick() ? -5 : -1, 0, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Pos Y
|
||||
//Pos Y
|
||||
inventory.setItem(16, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
simulator.move(0, clickType.isShiftClick() ? 5 : 1, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(25, new SWItem(Material.PAPER, "§eY", clickType -> {
|
||||
}));
|
||||
inventory.setItem(34, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
simulator.move(0, clickType.isShiftClick() ? -5 : -1, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Pos Z
|
||||
//Pos Z
|
||||
inventory.setItem(17, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
simulator.move(0, 0, clickType.isShiftClick() ? 5 : 1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(26, new SWItem(Material.PAPER, "§eZ", clickType -> {
|
||||
}));
|
||||
inventory.setItem(35, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
simulator.move(0, 0, clickType.isShiftClick() ? -5 : -1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.bausystem.features.simulator.execute.SimulatorStabGenerator;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
@@ -58,7 +60,7 @@ public class SimulatorTNTGui extends SimulatorScrollGui<TNTPhase> {
|
||||
public void headerAndFooter() {
|
||||
if (tnt.getPhases().isEmpty()) {
|
||||
back.open();
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -85,7 +87,7 @@ public class SimulatorTNTGui extends SimulatorScrollGui<TNTPhase> {
|
||||
|
||||
inventory.setItem(8, new SWItem(Material.BARRIER, "§eDelete", clickType -> {
|
||||
tnt.getPhases().clear();
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DELETE));
|
||||
|
||||
// Material Chooser
|
||||
@@ -96,18 +98,16 @@ public class SimulatorTNTGui extends SimulatorScrollGui<TNTPhase> {
|
||||
inventory.setItem(47, new SWItem(Material.REPEATER, "§eSettings", clickType -> {
|
||||
new SimulatorTNTSettingsGui(player, simulator, tnt, this).open();
|
||||
}).setCustomModelData(CMDs.Simulator.SETTINGS));
|
||||
inventory.setItem(48,
|
||||
new SWItem(tnt.isDisabled() ? Material.ENDER_PEARL : Material.ENDER_EYE, tnt.isDisabled() ? "§cDisabled" : "§aEnabled", clickType -> {
|
||||
tnt.setDisabled(!tnt.isDisabled());
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED));
|
||||
inventory.setItem(48, new SWItem(tnt.isDisabled() ? Material.ENDER_PEARL : Material.ENDER_EYE, tnt.isDisabled() ? "§cDisabled" : "§aEnabled", clickType -> {
|
||||
tnt.setDisabled(!tnt.isDisabled());
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED));
|
||||
if (Core.getVersion() > 19) {
|
||||
inventory.setItem(49, new SWItem(Material.CALIBRATED_SCULK_SENSOR, "§eCreate Stab", click -> {
|
||||
new SimulatorAnvilGui<>(player, "Depth Limit", "", Integer::parseInt, depthLimit -> {
|
||||
if (depthLimit <= 0)
|
||||
return false;
|
||||
if (depthLimit <= 0) return false;
|
||||
simulator.setStabGenerator(new SimulatorStabGenerator(Region.getRegion(player.getLocation()), simulator, tnt, depthLimit));
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, null).open();
|
||||
}).setCustomModelData(CMDs.Simulator.CREATE_STAB));
|
||||
@@ -117,7 +117,7 @@ public class SimulatorTNTGui extends SimulatorScrollGui<TNTPhase> {
|
||||
tntElement.add(new TNTPhase());
|
||||
parent.add(tntElement);
|
||||
new SimulatorGroupGui(player, simulator, parent, new SimulatorGui(player, simulator)).open();
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.MAKE_GROUP));
|
||||
inventory.setItem(51, new SWItem(Material.LEAD, "§eJoin Group", clickType -> {
|
||||
new SimulatorGroupChooserGui(player, simulator, tnt, tnt.getGroup(simulator), this).open();
|
||||
@@ -126,50 +126,52 @@ public class SimulatorTNTGui extends SimulatorScrollGui<TNTPhase> {
|
||||
|
||||
@Override
|
||||
public SWItem[] column(TNTPhase tntSetting, int index) {
|
||||
SWItem tnt = new SWItem(Material.TNT, "§eTNT§8:§7 " + tntSetting.getCount(),
|
||||
Arrays.asList("§7Tick§8: §e" + tntSetting.getTickOffset(), "§7Fuse§8:§e " + tntSetting.getLifetime(), "",
|
||||
"§7Order§8:§e " + tntSetting.getOrder(), "", "§7X-Jump§8: " + (tntSetting.isXJump() ? "§aOn" : "§cOff"),
|
||||
"§7Y-Jump§8: " + (tntSetting.isYJump() ? "§aOn" : "§cOff"), "§7Z-Jump§8: " + (tntSetting.isZJump() ? "§aOn" : "§cOff"), "",
|
||||
"§7Click§8:§e Edit", "§7Middle-Click§8:§e Remove"),
|
||||
false, clickType -> {
|
||||
if (clickType == ClickType.MIDDLE) {
|
||||
this.tnt.getPhases().remove(tntSetting);
|
||||
SimulatorRenderer.update(simulator);
|
||||
} else {
|
||||
new SimulatorTNTPhaseSettingsGui(player, simulator, this.tnt, tntSetting, this).open();
|
||||
}
|
||||
});
|
||||
SWItem tnt = new SWItem(Material.TNT, "§eTNT§8:§7 " + tntSetting.getCount(), Arrays.asList("§7Tick§8: §e" + tntSetting.getTickOffset(), "§7Fuse§8:§e " + tntSetting.getLifetime(), "", "§7Order§8:§e " + tntSetting.getOrder(), "", "§7X-Jump§8: " + (tntSetting.isXJump() ? "§aOn" : "§cOff"), "§7Y-Jump§8: " + (tntSetting.isYJump() ? "§aOn" : "§cOff"), "§7Z-Jump§8: " + (tntSetting.isZJump() ? "§aOn" : "§cOff"), "", "§7Click§8:§e Edit", "§7Middle-Click§8:§e Remove"), false, clickType -> {
|
||||
if (clickType == ClickType.MIDDLE) {
|
||||
this.tnt.getPhases().remove(tntSetting);
|
||||
SimulatorWatcher.update(simulator);
|
||||
} else {
|
||||
new SimulatorTNTPhaseSettingsGui(player, simulator, this.tnt, tntSetting, this).open();
|
||||
}
|
||||
});
|
||||
tnt.getItemStack().setAmount(Math.min(tntSetting.getCount(), 64));
|
||||
|
||||
return new SWItem[] {new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
|
||||
tntSetting.setCount(tntSetting.getCount() + (clickType.isShiftClick() ? 5 : 1));
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED), tnt,
|
||||
return new SWItem[]{
|
||||
new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
|
||||
tntSetting.setCount(tntSetting.getCount() + (clickType.isShiftClick() ? 5 : 1));
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED),
|
||||
tnt,
|
||||
new SWItem(SWItem.getDye(tntSetting.getCount() > 1 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8:§e -5"), false, clickType -> {
|
||||
tntSetting.setCount(Math.max(1, tntSetting.getCount() - (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED), new SWItem(Material.ANVIL, "§eEdit Phase", clickType -> {
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED),
|
||||
new SWItem(Material.ANVIL, "§eEdit Phase", clickType -> {
|
||||
new SimulatorTNTPhaseSettingsGui(player, simulator, this.tnt, tntSetting, this).open();
|
||||
}).setCustomModelData(CMDs.Simulator.EDIT_ACTIVATION),};
|
||||
}).setCustomModelData(CMDs.Simulator.EDIT_ACTIVATION),
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public SWItem[] lastColumn() {
|
||||
return new SWItem[] {new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
|
||||
addNewPhase(clickType.isShiftClick());
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED), new SWItem(Material.GUNPOWDER, "§eTNT§8:§a New Phase", clickType -> {
|
||||
addNewPhase(false);
|
||||
}).setCustomModelData(CMDs.Simulator.NEW_PHASE), new SWItem(SWItem.getDye(8), "§7", clickType -> {
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED),};
|
||||
return new SWItem[]{
|
||||
new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
|
||||
addNewPhase(clickType.isShiftClick());
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED),
|
||||
new SWItem(Material.GUNPOWDER, "§eTNT§8:§a New Phase", clickType -> {
|
||||
addNewPhase(false);
|
||||
}).setCustomModelData(CMDs.Simulator.NEW_PHASE),
|
||||
new SWItem(SWItem.getDye(8), "§7", clickType -> {
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED),
|
||||
};
|
||||
}
|
||||
|
||||
private void addNewPhase(boolean shift) {
|
||||
TNTPhase lastElement = tnt.getPhases().get(tnt.getPhases().size() - 1);
|
||||
TNTPhase newPhase = new TNTPhase(lastElement.getTickOffset() + 1);
|
||||
if (shift)
|
||||
newPhase.setCount(newPhase.getCount() + 5);
|
||||
if (shift) newPhase.setCount(newPhase.getCount() + 5);
|
||||
scroll++;
|
||||
tnt.add(newPhase);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorPhase;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.core.Core;
|
||||
@@ -66,26 +68,25 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui {
|
||||
new SimulatorMaterialGui(player, simulator, tntElement::getMaterial, tntElement::setMaterial, this).open();
|
||||
}));
|
||||
|
||||
// Delete
|
||||
//Delete
|
||||
inventory.setItem(8, new SWItem(Material.BARRIER, "§eDelete", clickType -> {
|
||||
tntElement.getPhases().remove(tnt);
|
||||
back.open();
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DELETE));
|
||||
|
||||
// Count
|
||||
//Count
|
||||
int count = tnt.getCount();
|
||||
inventory.setItem(9, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
tnt.setCount(count + (clickType.isShiftClick() ? 5 : 1));
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
|
||||
SWItem countItem = new SWItem(Material.TNT, "§eCount§8:§7 " + count, clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Count", count + "", Integer::parseInt, integer -> {
|
||||
if (integer < 1)
|
||||
return false;
|
||||
if (integer < 1) return false;
|
||||
tnt.setCount(integer);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).setItem(Material.TNT).open();
|
||||
});
|
||||
@@ -94,22 +95,21 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui {
|
||||
|
||||
inventory.setItem(27, new SWItem(SWItem.getDye(count > 1 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
tnt.setCount(Math.max(1, count - (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Tick Offset
|
||||
//Tick Offset
|
||||
int offset = tnt.getTickOffset();
|
||||
inventory.setItem(10, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
tnt.setTickOffset(offset + (clickType.isShiftClick() ? 5 : 1));
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
|
||||
SWItem offsetItem = new SWItem(Material.REPEATER, "§eStart at§8:§7 " + offset, clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Start at", offset + "", Integer::parseInt, integer -> {
|
||||
if (integer < 0)
|
||||
return false;
|
||||
if (integer < 0) return false;
|
||||
tnt.setTickOffset(integer);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).setItem(Material.REPEATER).open();
|
||||
});
|
||||
@@ -118,22 +118,21 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui {
|
||||
|
||||
inventory.setItem(28, new SWItem(SWItem.getDye(offset > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
tnt.setTickOffset(Math.max(0, offset - (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Lifetime
|
||||
//Lifetime
|
||||
int lifetime = tnt.getLifetime();
|
||||
inventory.setItem(11, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
tnt.setLifetime(lifetime + (clickType.isShiftClick() ? 5 : 1));
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
|
||||
SWItem lifetimeItem = new SWItem(Material.CLOCK, "§eLifetime§8:§7 " + lifetime, clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Lifetime", lifetime + "", Integer::parseInt, integer -> {
|
||||
if (integer < 1)
|
||||
return false;
|
||||
if (integer < 1) return false;
|
||||
tnt.setLifetime(integer);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).setItem(Material.CLOCK).open();
|
||||
});
|
||||
@@ -142,63 +141,56 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui {
|
||||
|
||||
inventory.setItem(29, new SWItem(SWItem.getDye(lifetime > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
tnt.setLifetime(Math.max(1, lifetime - (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Order
|
||||
//Order
|
||||
int order = tnt.getOrder();
|
||||
inventory.setItem(13,
|
||||
new SWItem(SWItem.getDye(order < SimulatorPhase.ORDER_LIMIT ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
tnt.setOrder(Math.min(SimulatorPhase.ORDER_LIMIT, order + (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(13, new SWItem(SWItem.getDye(order < SimulatorPhase.ORDER_LIMIT ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
tnt.setOrder(Math.min(SimulatorPhase.ORDER_LIMIT, order + (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
|
||||
Material negativeNumbers = Material.getMaterial(Core.getVersion() >= 19 ? "RECOVERY_COMPASS" : "FIREWORK_STAR");
|
||||
SWItem orderItem = new SWItem(order >= 0 ? Material.COMPASS : negativeNumbers, "§eCalculation Order§8:§7 " + order, clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Calculation Order", order + "", Integer::parseInt, integer -> {
|
||||
if (integer < -SimulatorPhase.ORDER_LIMIT)
|
||||
return false;
|
||||
if (integer > SimulatorPhase.ORDER_LIMIT)
|
||||
return false;
|
||||
if (integer < -SimulatorPhase.ORDER_LIMIT) return false;
|
||||
if (integer > SimulatorPhase.ORDER_LIMIT) return false;
|
||||
tnt.setOrder(integer);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).setItem(order >= 0 ? Material.COMPASS : negativeNumbers).open();
|
||||
});
|
||||
orderItem.getItemStack().setAmount(Math.max(1, Math.min(Math.abs(order), 30)));
|
||||
inventory.setItem(22, orderItem);
|
||||
|
||||
inventory.setItem(31,
|
||||
new SWItem(SWItem.getDye(order > -SimulatorPhase.ORDER_LIMIT ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
tnt.setOrder(Math.max(-SimulatorPhase.ORDER_LIMIT, order - (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorRenderer.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
inventory.setItem(31, new SWItem(SWItem.getDye(order > -SimulatorPhase.ORDER_LIMIT ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
|
||||
tnt.setOrder(Math.max(-SimulatorPhase.ORDER_LIMIT, order - (clickType.isShiftClick() ? 5 : 1)));
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Jump
|
||||
SWItem jumpX =
|
||||
new SWItem(tnt.isXJump() ? Material.LIME_WOOL : Material.RED_WOOL, "§7TNT §eJump X§8: " + (tnt.isZJump() ? "§aon" : "§coff"), clickType -> {
|
||||
tnt.setXJump(!tnt.isXJump());
|
||||
SimulatorRenderer.update(simulator);
|
||||
});
|
||||
//Jump
|
||||
SWItem jumpX = new SWItem(tnt.isXJump() ? Material.LIME_WOOL : Material.RED_WOOL, "§7TNT §eJump X§8: " + (tnt.isZJump() ? "§aon" : "§coff"), clickType -> {
|
||||
tnt.setXJump(!tnt.isXJump());
|
||||
SimulatorWatcher.update(simulator);
|
||||
});
|
||||
inventory.setItem(33, jumpX);
|
||||
|
||||
SWItem jumpY =
|
||||
new SWItem(tnt.isYJump() ? Material.LIME_WOOL : Material.RED_WOOL, "§7TNT §eJump Y§8: " + (tnt.isYJump() ? "§aon" : "§coff"), clickType -> {
|
||||
tnt.setYJump(!tnt.isYJump());
|
||||
SimulatorRenderer.update(simulator);
|
||||
});
|
||||
SWItem jumpY = new SWItem(tnt.isYJump() ? Material.LIME_WOOL : Material.RED_WOOL, "§7TNT §eJump Y§8: " + (tnt.isYJump() ? "§aon" : "§coff"), clickType -> {
|
||||
tnt.setYJump(!tnt.isYJump());
|
||||
SimulatorWatcher.update(simulator);
|
||||
});
|
||||
inventory.setItem(16, jumpY);
|
||||
|
||||
SWItem jumpZ =
|
||||
new SWItem(tnt.isZJump() ? Material.LIME_WOOL : Material.RED_WOOL, "§7TNT §eJump Z§8: " + (tnt.isZJump() ? "§aon" : "§coff"), clickType -> {
|
||||
tnt.setZJump(!tnt.isZJump());
|
||||
SimulatorRenderer.update(simulator);
|
||||
});
|
||||
SWItem jumpZ = new SWItem(tnt.isZJump() ? Material.LIME_WOOL : Material.RED_WOOL, "§7TNT §eJump Z§8: " + (tnt.isZJump() ? "§aon" : "§coff"), clickType -> {
|
||||
tnt.setZJump(!tnt.isZJump());
|
||||
SimulatorWatcher.update(simulator);
|
||||
});
|
||||
inventory.setItem(35, jumpZ);
|
||||
|
||||
SWItem jumpAll = new SWItem(Material.TNT, "§7TNT §eJump §8: " + (tnt.hasJump() ? "§aon" : "§coff"), clickType -> {
|
||||
tnt.setJump(!tnt.hasJump());
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
});
|
||||
inventory.setItem(25, jumpAll);
|
||||
}
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.data.CMDs;
|
||||
@@ -74,14 +76,13 @@ public class SimulatorTNTSettingsGui extends SimulatorBaseGui {
|
||||
int baseTicks = tnt.getBaseTick();
|
||||
inventory.setItem(9, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
|
||||
tnt.changeBaseTicks(clickType.isShiftClick() ? 5 : 1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
SWItem baseTick = new SWItem(Material.REPEATER, "§eTicks§8:§7 " + baseTicks, clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Ticks", baseTicks + "", Integer::parseInt, integer -> {
|
||||
if (integer < 0)
|
||||
return false;
|
||||
if (integer < 0) return false;
|
||||
tnt.changeBaseTicks(integer - baseTicks);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).setItem(Material.REPEATER).open();
|
||||
});
|
||||
@@ -93,46 +94,42 @@ public class SimulatorTNTSettingsGui extends SimulatorBaseGui {
|
||||
} else {
|
||||
tnt.changeBaseTicks(clickType.isShiftClick() ? -5 : -1);
|
||||
}
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Subpixel Alignment
|
||||
inventory.setItem(21, new SWItem(Material.SUNFLOWER, "§7Align§8: §eCenter", clickType -> {
|
||||
tnt.alignX(0);
|
||||
tnt.alignZ(0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}));
|
||||
|
||||
// Z
|
||||
SWItem negativZItem = new SWItem(Material.OAK_BUTTON, "§7Align§8: §eNegativ Z", clickType -> {
|
||||
if (tnt.getAlignment().getZ() != -1)
|
||||
tnt.alignZ(-1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
if (tnt.getAlignment().getZ() != -1) tnt.alignZ(-1);
|
||||
SimulatorWatcher.update(simulator);
|
||||
});
|
||||
negativZItem.setEnchanted(tnt.getAlignment().getZ() == -1);
|
||||
inventory.setItem(20, negativZItem);
|
||||
|
||||
SWItem positivZItem = new SWItem(Material.OAK_BUTTON, "§7Align§8: §ePositiv Z", clickType -> {
|
||||
if (tnt.getAlignment().getZ() != 1)
|
||||
tnt.alignZ(1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
if (tnt.getAlignment().getZ() != 1) tnt.alignZ(1);
|
||||
SimulatorWatcher.update(simulator);
|
||||
});
|
||||
positivZItem.setEnchanted(tnt.getAlignment().getZ() == 1);
|
||||
inventory.setItem(22, positivZItem);
|
||||
|
||||
// X
|
||||
SWItem negativXItem = new SWItem(Material.STONE_BUTTON, "§7Align§8: §eNegativ X", clickType -> {
|
||||
if (tnt.getAlignment().getX() != -1)
|
||||
tnt.alignX(-1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
if (tnt.getAlignment().getX() != -1) tnt.alignX(-1);
|
||||
SimulatorWatcher.update(simulator);
|
||||
});
|
||||
negativXItem.setEnchanted(tnt.getAlignment().getX() == -1);
|
||||
inventory.setItem(12, negativXItem);
|
||||
|
||||
SWItem positivXItem = new SWItem(Material.STONE_BUTTON, "§7Align§8: §ePositiv X", clickType -> {
|
||||
if (tnt.getAlignment().getX() != 1)
|
||||
tnt.alignX(1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SWItem positivXItem = new SWItem(Material.STONE_BUTTON, "§7Align§8: §ePositiv X", clickType -> {
|
||||
if(tnt.getAlignment().getX() != 1) tnt.alignX(1);
|
||||
SimulatorWatcher.update(simulator);
|
||||
});
|
||||
positivXItem.setEnchanted(tnt.getAlignment().getX() == 1);
|
||||
inventory.setItem(30, positivXItem);
|
||||
@@ -140,52 +137,52 @@ public class SimulatorTNTSettingsGui extends SimulatorBaseGui {
|
||||
// Pos X
|
||||
inventory.setItem(15, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+0.0625"), false, clickType -> {
|
||||
tnt.move(clickType.isShiftClick() ? 0.0625 : 1, 0, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(24, new SWItem(Material.PAPER, "§eX§8:§7 " + tnt.getPosition().getX(), clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "X", tnt.getPosition().getX() + "", Double::parseDouble, d -> {
|
||||
tnt.getPosition().setX(d);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).open();
|
||||
}));
|
||||
inventory.setItem(33, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-0.0625"), false, clickType -> {
|
||||
tnt.move(clickType.isShiftClick() ? -0.0625 : -1, 0, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Pos Y
|
||||
inventory.setItem(16, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+0.0625"), false, clickType -> {
|
||||
tnt.move(0, clickType.isShiftClick() ? 0.0625 : 1, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(25, new SWItem(Material.PAPER, "§eY§8:§7 " + tnt.getPosition().getY(), clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Y", tnt.getPosition().getY() + "", Double::parseDouble, d -> {
|
||||
tnt.getPosition().setY(d);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).open();
|
||||
}));
|
||||
inventory.setItem(34, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-0.0625"), false, clickType -> {
|
||||
tnt.move(0, clickType.isShiftClick() ? -0.0625 : -1, 0);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
|
||||
// Pos Z
|
||||
inventory.setItem(17, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+0.0625"), false, clickType -> {
|
||||
tnt.move(0, 0, clickType.isShiftClick() ? 0.0625 : 1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
|
||||
inventory.setItem(26, new SWItem(Material.PAPER, "§eZ§8:§7 " + tnt.getPosition().getZ(), clickType -> {
|
||||
new SimulatorAnvilGui<>(player, "Z", tnt.getPosition().getZ() + "", Double::parseDouble, d -> {
|
||||
tnt.getPosition().setZ(d);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, this).open();
|
||||
}));
|
||||
inventory.setItem(35, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-0.0625"), false, clickType -> {
|
||||
tnt.move(0, 0, clickType.isShiftClick() ? -0.0625 : -1);
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.simulator.gui.base;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.display.SimulatorRenderer;
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.inventory.SWInventory;
|
||||
import de.steamwar.inventory.SWItem;
|
||||
@@ -43,8 +45,7 @@ public abstract class SimulatorBaseGui {
|
||||
}
|
||||
|
||||
public final void open() {
|
||||
if (!shouldOpen())
|
||||
return;
|
||||
if (!shouldOpen()) return;
|
||||
|
||||
String newTitle = title();
|
||||
String originalTitle = player.getOpenInventory().getTitle();
|
||||
@@ -57,6 +58,7 @@ public abstract class SimulatorBaseGui {
|
||||
setup();
|
||||
if (player.getOpenInventory().getTopInventory() != inv) {
|
||||
inventory.open();
|
||||
SimulatorWatcher.watch(player, simulator, this::open);
|
||||
}
|
||||
if (Core.getVersion() > 19) {
|
||||
player.getOpenInventory().setTitle(title());
|
||||
@@ -68,6 +70,7 @@ public abstract class SimulatorBaseGui {
|
||||
}
|
||||
if (player.getOpenInventory().getTopInventory() == inv) {
|
||||
inventory.open();
|
||||
SimulatorWatcher.watch(player, simulator, this::open);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -79,7 +82,11 @@ public abstract class SimulatorBaseGui {
|
||||
return inv;
|
||||
});
|
||||
setup();
|
||||
inventory.addCloseCallback(clickType -> {
|
||||
SimulatorWatcher.watch(player, null, null);
|
||||
});
|
||||
|
||||
SimulatorWatcher.watch(player, simulator, this::open);
|
||||
if (simulator != null && simulator.getStabGenerator() != null) {
|
||||
populateStabGenerator();
|
||||
} else {
|
||||
@@ -91,7 +98,7 @@ public abstract class SimulatorBaseGui {
|
||||
private void populateStabGenerator() {
|
||||
inventory.setItem(22, new SWItem(Material.BARRIER, "§cCancel Stab Generator", click -> {
|
||||
simulator.getStabGenerator().cancel();
|
||||
SimulatorRenderer.update(simulator);
|
||||
SimulatorWatcher.update(simulator);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Simulator> simulators = new ArrayList<>();
|
||||
for (String s : yapionObject.getKeys()) {
|
||||
|
||||
@@ -87,6 +87,7 @@ public class MaterialLazyInit {
|
||||
Block block = Bukkit.getWorlds().get(0).getBlockAt(0, 0, 0);
|
||||
block.setType(material);
|
||||
unmoveable = block.getPistonMoveReaction() == PistonMoveReaction.BLOCK || block.getPistonMoveReaction() == PistonMoveReaction.IGNORE || block.getState() instanceof TileState;
|
||||
block.setType(Material.AIR);
|
||||
}
|
||||
|
||||
if (material.isItem() && material != Material.AIR) {
|
||||
|
||||
@@ -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!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
package de.steamwar.bausystem.utils.cursor;
|
||||
|
||||
import de.steamwar.bausystem.utils.RayTraceUtils;
|
||||
import de.steamwar.entity.REntity;
|
||||
import de.steamwar.entity.REntityServer;
|
||||
import de.steamwar.entity.RFallingBlockEntity;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Getter
|
||||
public abstract class Cursor {
|
||||
private final World WORLD = Bukkit.getWorlds().get(0);
|
||||
|
||||
private final REntityServer targetServer;
|
||||
private final REntityServer cursorServer;
|
||||
|
||||
private final Player owner;
|
||||
private final Material highlightMaterial;
|
||||
|
||||
private RFallingBlockEntity cursorEntity;
|
||||
|
||||
private Location cursorLocation;
|
||||
private boolean isHittingEntity = false;
|
||||
|
||||
@Setter
|
||||
private Material cursorMaterial;
|
||||
@Setter
|
||||
private List<CursorMode> allowedCursorModes;
|
||||
private boolean visible = true;
|
||||
|
||||
|
||||
|
||||
protected Cursor(REntityServer targetServer, Player owner, Material highlightMaterial, Material cursorMaterial, List<CursorMode> allowedModes) {
|
||||
this.targetServer = targetServer;
|
||||
this.owner = owner;
|
||||
this.highlightMaterial = highlightMaterial;
|
||||
this.cursorMaterial = cursorMaterial;
|
||||
this.allowedCursorModes = allowedModes;
|
||||
|
||||
cursorServer = new REntityServer();
|
||||
cursorServer.addPlayer(owner);
|
||||
|
||||
CursorManager.getInstance().registerCursor(this);
|
||||
}
|
||||
|
||||
public void render() {
|
||||
if (!visible)
|
||||
return;
|
||||
|
||||
RayTraceUtils.RRayTraceResult rayTraceResult = RayTraceUtils.traceREntity(owner, owner.getLocation(), targetServer.getEntities());
|
||||
if (rayTraceResult == null) {
|
||||
if (cursorEntity != null)
|
||||
cursorEntity.die();
|
||||
cursorEntity = null;
|
||||
return;
|
||||
}
|
||||
|
||||
REntity hitEntity = rayTraceResult.getHitEntity() == cursorEntity ? null : rayTraceResult.getHitEntity();
|
||||
|
||||
|
||||
Material activeCursorMaterial = hitEntity == null ? cursorMaterial : highlightMaterial;
|
||||
CursorMode activeCursorMode = allowedCursorModes.stream().filter((mode) -> mode.isActive.test(owner)).min(Comparator.comparingInt(a -> a.priority))
|
||||
.orElse(CursorMode.BLOCK_ALIGNED);
|
||||
|
||||
Location activeCursorLocation = hitEntity == null ? activeCursorMode.positionTransform.apply(owner, rayTraceResult).toLocation(WORLD)
|
||||
: new Vector(hitEntity.getX(), hitEntity.getY(), hitEntity.getZ()).toLocation(WORLD);
|
||||
|
||||
cursorLocation = activeCursorLocation;
|
||||
isHittingEntity = hitEntity != null;
|
||||
|
||||
if (cursorEntity == null) {
|
||||
cursorEntity = new RFallingBlockEntity(cursorServer, activeCursorLocation, activeCursorMaterial);
|
||||
cursorEntity.setNoGravity(true);
|
||||
} else if (cursorEntity.getMaterial() == activeCursorMaterial) {
|
||||
cursorEntity.move(activeCursorLocation);
|
||||
} else {
|
||||
cursorEntity.die();
|
||||
cursorEntity = new RFallingBlockEntity(cursorServer, activeCursorLocation, activeCursorMaterial);
|
||||
cursorEntity.setNoGravity(true);
|
||||
if (activeCursorMaterial == highlightMaterial) {
|
||||
cursorEntity.setGlowing(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
visible = false;
|
||||
if (cursorEntity != null) {
|
||||
cursorEntity.die();
|
||||
cursorEntity = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void show() {
|
||||
visible = true;
|
||||
}
|
||||
|
||||
final void handleClick(Action action) {
|
||||
if (!visible)
|
||||
return;
|
||||
|
||||
onClick(Optional.ofNullable(this.cursorLocation), isHittingEntity, action);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
cursorServer.close();
|
||||
CursorManager.getInstance().unregisterCursor(this);
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
public enum CursorMode {
|
||||
FREE(1, (player, rayTraceResult) -> {
|
||||
Vector pos = rayTraceResult.getHitPosition();
|
||||
|
||||
BlockFace face = rayTraceResult.getHitBlockFace();
|
||||
if (face != null) {
|
||||
switch (face) {
|
||||
case DOWN:
|
||||
pos.setY(pos.getY() - 0.98);
|
||||
break;
|
||||
case EAST:
|
||||
pos.setX(pos.getX() + 0.49);
|
||||
break;
|
||||
case WEST:
|
||||
pos.setX(pos.getX() - 0.49);
|
||||
break;
|
||||
case NORTH:
|
||||
pos.setZ(pos.getZ() - 0.49);
|
||||
break;
|
||||
case SOUTH:
|
||||
pos.setZ(pos.getZ() + 0.49);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (face.getModY() == 0 && player.isSneaking()) {
|
||||
pos.setY(pos.getY() - 0.49);
|
||||
}
|
||||
}
|
||||
|
||||
return pos;
|
||||
}, (player) -> player.isSneaking()),
|
||||
|
||||
BLOCK_ALIGNED(0, (player, rayTraceResult) -> {
|
||||
Vector pos = rayTraceResult.getHitPosition();
|
||||
|
||||
BlockFace face = rayTraceResult.getHitBlockFace();
|
||||
if (face != null) {
|
||||
switch (face) {
|
||||
case DOWN:
|
||||
pos.setY(pos.getY() - 0.98);
|
||||
break;
|
||||
case EAST:
|
||||
pos.setX(pos.getX() + 0.49);
|
||||
break;
|
||||
case WEST:
|
||||
pos.setX(pos.getX() - 0.49);
|
||||
break;
|
||||
case NORTH:
|
||||
pos.setZ(pos.getZ() - 0.49);
|
||||
break;
|
||||
case SOUTH:
|
||||
pos.setZ(pos.getZ() + 0.49);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pos.setX(pos.getBlockX() + 0.5);
|
||||
if (pos.getY() - pos.getBlockY() != 0 && face == BlockFace.UP) {
|
||||
pos.setY(pos.getBlockY() + 1.0);
|
||||
} else {
|
||||
pos.setY(pos.getBlockY());
|
||||
}
|
||||
pos.setZ(pos.getBlockZ() + 0.5);
|
||||
return pos;
|
||||
}, (player) -> true);
|
||||
|
||||
|
||||
private final int priority;
|
||||
private final BiFunction<Player, RayTraceUtils.RRayTraceResult, Vector> positionTransform;
|
||||
private final Predicate<Player> isActive;
|
||||
}
|
||||
|
||||
public abstract void onClick(Optional<Location> cursorLocation, boolean didHitEntity, Action action);
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
package de.steamwar.bausystem.utils.cursor;
|
||||
|
||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||
import de.steamwar.Reflection;
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
@Linked
|
||||
public class CursorManager implements Listener {
|
||||
@Getter
|
||||
private static CursorManager instance;
|
||||
|
||||
private final Set<Player> calculationActive = new HashSet<>();
|
||||
private final Map<Player, List<Cursor>> activeCursors = new HashMap<>();
|
||||
|
||||
public CursorManager() {
|
||||
if (instance == null) {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
BiFunction<Player, Object, Object> function = (player, object) -> {
|
||||
updateCursors(player);
|
||||
return object;
|
||||
};
|
||||
|
||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||
Set<Player> playersWithActiveCursor = activeCursors.keySet();
|
||||
|
||||
playersWithActiveCursor.forEach(this::updateCursors);
|
||||
}, 0);
|
||||
|
||||
Class<?> positionPacketClass = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Pos");
|
||||
Class<?> lookPacketClass = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Rot");
|
||||
Class<?> positionLookPacketClass = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$PosRot");
|
||||
|
||||
TinyProtocol.instance.addFilter(positionPacketClass, function);
|
||||
TinyProtocol.instance.addFilter(lookPacketClass, function);
|
||||
TinyProtocol.instance.addFilter(positionLookPacketClass, function);
|
||||
}
|
||||
|
||||
void registerCursor(Cursor cursor) {
|
||||
List<Cursor> cursorsOfPlayer = activeCursors.getOrDefault(cursor.getOwner(), new ArrayList<>());
|
||||
cursorsOfPlayer.add(cursor);
|
||||
activeCursors.put(cursor.getOwner(), cursorsOfPlayer);
|
||||
}
|
||||
|
||||
void unregisterCursor(Cursor cursor) {
|
||||
List<Cursor> cursorsOfPlayer = activeCursors.get(cursor.getOwner());
|
||||
if (cursorsOfPlayer != null) {
|
||||
cursorsOfPlayer.remove(cursor);
|
||||
if (cursorsOfPlayer.isEmpty()) {
|
||||
activeCursors.remove(cursor.getOwner());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void closeCursorsOf(Player player) {
|
||||
List<Cursor> cursorsOfPlayer = activeCursors.remove(player);
|
||||
if (cursorsOfPlayer != null) {
|
||||
new ArrayList<>(cursorsOfPlayer).forEach(Cursor::close);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void updateCursors(Player player) {
|
||||
if (!activeCursors.containsKey(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (calculationActive) {
|
||||
if (calculationActive.contains(player)) {
|
||||
return;
|
||||
} else {
|
||||
calculationActive.add(player);
|
||||
}
|
||||
}
|
||||
|
||||
List<Cursor> cursors = activeCursors.get(player);
|
||||
|
||||
if (cursors != null) {
|
||||
cursors.forEach(Cursor::render);
|
||||
}
|
||||
|
||||
synchronized (calculationActive) {
|
||||
calculationActive.remove(player);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
private void handlePlayerInteract(PlayerInteractEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
List<Cursor> cursorsOfPlayer = activeCursors.get(player);
|
||||
if (cursorsOfPlayer != null) {
|
||||
cursorsOfPlayer.forEach(cursor -> cursor.handleClick(event.getAction()));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
private void handlePlayerQuit(PlayerQuitEvent event) {
|
||||
closeCursorsOf(event.getPlayer());
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,12 @@ public class FixedFlagStorage implements FlagStorage {
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
flagMap.clear();
|
||||
for (Flag flag : Flag.getFlags()) {
|
||||
if (flag == Flag.TESTBLOCK) continue;
|
||||
if (flag == Flag.COLOR) continue;
|
||||
if (flag == Flag.CHANGED) continue;
|
||||
flagMap.remove(flag);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -91,7 +91,12 @@ public class FixedGlobalFlagStorage implements FlagStorage {
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
flagMap.clear();
|
||||
for (Flag flag : Flag.getFlags()) {
|
||||
if (flag == Flag.TESTBLOCK) continue;
|
||||
if (flag == Flag.COLOR) continue;
|
||||
if (flag == Flag.CHANGED) continue;
|
||||
flagMap.remove(flag);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -50,5 +50,6 @@ tasks.register<DevServer>("DevBau21") {
|
||||
description = "Run a 1.21 Dev Bau"
|
||||
dependsOn(":SpigotCore:shadowJar")
|
||||
dependsOn(":BauSystem:shadowJar")
|
||||
dependsOn(":SchematicSystem:shadowJar")
|
||||
template = "Bau21"
|
||||
}
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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 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.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.linkage;
|
||||
@@ -30,7 +32,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class AbstractLinker<T> {
|
||||
@@ -51,13 +52,16 @@ public abstract class AbstractLinker<T> {
|
||||
List<Class<?>> classes;
|
||||
try {
|
||||
classes = new BufferedReader(new InputStreamReader(plugin.getClass().getResourceAsStream("/META-INF/annotations/de.steamwar.linkage.Linked")))
|
||||
.lines().map(s -> {
|
||||
.lines()
|
||||
.map(s -> {
|
||||
try {
|
||||
return Class.forName(s, false, plugin.getClass().getClassLoader());
|
||||
} catch (ClassNotFoundException | NoClassDefFoundError e) {
|
||||
throw new SecurityException(e.getMessage(), e);
|
||||
}
|
||||
}).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
} catch (SecurityException e) {
|
||||
Throwable cause = e.getCause();
|
||||
throw new LinkException(cause.getMessage(), cause);
|
||||
@@ -67,15 +71,12 @@ public abstract class AbstractLinker<T> {
|
||||
classes.forEach(clazz -> {
|
||||
MinVersion minVersion = clazz.getAnnotation(MinVersion.class);
|
||||
MaxVersion maxVersion = clazz.getAnnotation(MaxVersion.class);
|
||||
if (!versionCheck(clazz, minVersion, maxVersion))
|
||||
return;
|
||||
if (!versionCheck(clazz, minVersion, maxVersion)) return;
|
||||
EventMode eventMode = clazz.getAnnotation(EventMode.class);
|
||||
if (!eventModeCheck(clazz, eventMode))
|
||||
return;
|
||||
if (!eventModeCheck(clazz, eventMode)) return;
|
||||
PluginCheck[] pluginChecks = clazz.getAnnotationsByType(PluginCheck.class);
|
||||
for (PluginCheck pluginCheck : pluginChecks) {
|
||||
if (!pluginCheck(clazz, pluginCheck))
|
||||
return;
|
||||
if (!pluginCheck(clazz, pluginCheck)) return;
|
||||
}
|
||||
|
||||
Object any;
|
||||
@@ -156,14 +157,12 @@ public abstract class AbstractLinker<T> {
|
||||
/**
|
||||
* There is no need in calling {@link Enable#enable()} by this method.
|
||||
*/
|
||||
protected void linkObject(Object any) {}
|
||||
protected void linkObject(Object any) {
|
||||
}
|
||||
|
||||
/**
|
||||
* There is no need in calling {@link Disable#disable()} ()} by this method.
|
||||
*/
|
||||
protected void unlinkObject(Object any) {}
|
||||
|
||||
public final <L> Optional<L> get(Class<L> clazz) {
|
||||
return Optional.ofNullable((L) instances.get(clazz));
|
||||
protected void unlinkObject(Object any) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
compileOnlyApi("org.jetbrains.kotlin:kotlin-stdlib:2.2.21")
|
||||
compileOnlyApi(libs.exposedCore)
|
||||
compileOnlyApi(libs.exposedDao)
|
||||
compileOnlyApi(libs.exposedJdbc)
|
||||
compileOnlyApi(libs.exposedTime)
|
||||
}
|
||||
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<AuditLog> 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);
|
||||
}
|
||||
}
|
||||
121
CommonCore/SQL/src/de/steamwar/sql/AuditLog.kt
Normal file
121
CommonCore/SQL/src/de/steamwar/sql/AuditLog.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Int>): IntEntity(id) {
|
||||
companion object: IntEntityClass<AuditLog>(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,
|
||||
}
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.Field;
|
||||
import de.steamwar.sql.internal.SelectStatement;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.sql.internal.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class BannedUserIPs {
|
||||
|
||||
private static final Table<BannedUserIPs> table = new Table<>(BannedUserIPs.class);
|
||||
|
||||
private static final SelectStatement<BannedUserIPs> getByID = table.selectFields("UserID");
|
||||
private static final SelectStatement<BannedUserIPs> 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<BannedUserIPs> get(int userID) {
|
||||
return getByID.listSelect(userID);
|
||||
}
|
||||
|
||||
public static List<BannedUserIPs> 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);
|
||||
}
|
||||
}
|
||||
78
CommonCore/SQL/src/de/steamwar/sql/BannedUserIPs.kt
Normal file
78
CommonCore/SQL/src/de/steamwar/sql/BannedUserIPs.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<CompositeID>): CompositeEntity(id) {
|
||||
companion object: CompositeEntityClass<BannedUserIPs>(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()
|
||||
}
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.Field;
|
||||
import de.steamwar.sql.internal.SelectStatement;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.sql.internal.Table;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class BauweltMember {
|
||||
private static final Map<Integer, BauweltMember> memberCache = new HashMap<>();
|
||||
|
||||
public static void clear() {
|
||||
memberCache.clear();
|
||||
}
|
||||
|
||||
private static final Table<BauweltMember> table = new Table<>(BauweltMember.class);
|
||||
private static final SelectStatement<BauweltMember> getMember = table.select(Table.PRIMARY);
|
||||
private static final SelectStatement<BauweltMember> getMembers = table.selectFields("BauweltID");
|
||||
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<BauweltMember> getMembers(UUID bauweltID){
|
||||
return getMembers(SteamwarUser.get(bauweltID).getId());
|
||||
}
|
||||
|
||||
public static List<BauweltMember> getMembers(int bauweltID){
|
||||
return getMembers.listSelect(bauweltID);
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Field(keys = {Table.PRIMARY})
|
||||
private final int bauweltID;
|
||||
@Getter
|
||||
@Field(keys = {Table.PRIMARY})
|
||||
private final int memberID;
|
||||
@Getter
|
||||
@Field(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();
|
||||
}
|
||||
}
|
||||
130
CommonCore/SQL/src/de/steamwar/sql/BauweltMember.kt
Normal file
130
CommonCore/SQL/src/de/steamwar/sql/BauweltMember.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<CompositeID>): CompositeEntity(id) {
|
||||
companion object: CompositeEntityClass<BauweltMember>(BauweltMemberTable) {
|
||||
private val cache = mutableMapOf<Int, BauweltMember>()
|
||||
|
||||
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<Int>, newMemberId: EntityID<Int>) = 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()
|
||||
}
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.Field;
|
||||
import de.steamwar.sql.internal.SelectStatement;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.sql.internal.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class CheckedSchematic {
|
||||
|
||||
private static final Table<CheckedSchematic> table = new Table<>(CheckedSchematic.class);
|
||||
private static final SelectStatement<CheckedSchematic> statusOfNode = new SelectStatement<>(table, "SELECT * FROM CheckedSchematic WHERE NodeId = ? AND DeclineReason != 'Prüfvorgang abgebrochen' ORDER BY EndTime DESC");
|
||||
private static final SelectStatement<CheckedSchematic> 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<CheckedSchematic> 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<CheckedSchematic> getLastDeclinedOfNode(int node) {
|
||||
return statusOfNode.listSelect(node);
|
||||
}
|
||||
|
||||
public static List<CheckedSchematic> previousChecks(SchematicNode node) {
|
||||
return nodeHistory.listSelect(node.getId());
|
||||
}
|
||||
|
||||
public static List<CheckedSchematic> 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);
|
||||
}
|
||||
}
|
||||
100
CommonCore/SQL/src/de/steamwar/sql/CheckedSchematic.kt
Normal file
100
CommonCore/SQL/src/de/steamwar/sql/CheckedSchematic.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<CompositeID>): CompositeEntity(id) {
|
||||
companion object: CompositeEntityClass<CheckedSchematic>(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
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.Field;
|
||||
import de.steamwar.sql.internal.SelectStatement;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.sql.internal.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.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<Event> table = new Table<>(Event.class);
|
||||
|
||||
private static final SelectStatement<Event> byCurrent = new SelectStatement<>(table, "SELECT * FROM Event WHERE Start < now() AND End > now()");
|
||||
private static final SelectStatement<Event> byId = table.select(Table.PRIMARY);
|
||||
private static final SelectStatement<Event> byName = table.select("eventName");
|
||||
private static final SelectStatement<Event> byComing = new SelectStatement<>(table, "SELECT * FROM Event WHERE Start > now()");
|
||||
private static final SelectStatement<Event> 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<Event> 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<Event> 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);
|
||||
}
|
||||
}
|
||||
121
CommonCore/SQL/src/de/steamwar/sql/Event.kt
Normal file
121
CommonCore/SQL/src/de/steamwar/sql/Event.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Int>) : IntEntity(id) {
|
||||
companion object : IntEntityClass<Event>(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() }
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.Field;
|
||||
import de.steamwar.sql.internal.SelectStatement;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.sql.internal.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.*;
|
||||
|
||||
import static java.time.temporal.ChronoUnit.SECONDS;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class EventFight implements Comparable<EventFight> {
|
||||
|
||||
private static final Table<EventFight> table = new Table<>(EventFight.class);
|
||||
private static final SelectStatement<EventFight> byId = table.select(Table.PRIMARY);
|
||||
private static final SelectStatement<EventFight> byGroup = new SelectStatement<EventFight>(table, "SELECT * FROM EventFight WHERE GroupID = ? ORDER BY StartTime ASC");
|
||||
private static final SelectStatement<EventFight> byGroupLast = new SelectStatement<EventFight>(table, "SELECT * FROM EventFight WHERE GroupID = ? ORDER BY StartTime DESC LIMIT 1");
|
||||
private static final SelectStatement<EventFight> allComing = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE StartTime > now() ORDER BY StartTime ASC");
|
||||
private static final SelectStatement<EventFight> event = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE EventID = ? ORDER BY StartTime ASC");
|
||||
private static final SelectStatement<EventFight> 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<EventFight> fights = new PriorityQueue<>();
|
||||
|
||||
public static EventFight get(int fightID) {
|
||||
return byId.select(fightID);
|
||||
}
|
||||
|
||||
public static List<EventFight> get(EventGroup group) {
|
||||
return byGroup.listSelect(group.getId());
|
||||
}
|
||||
|
||||
public static Optional<EventFight> getLast(EventGroup group) {
|
||||
return Optional.ofNullable(byGroupLast.select(group.getId()));
|
||||
}
|
||||
|
||||
public static void loadAllComingFights() {
|
||||
fights.clear();
|
||||
fights.addAll(allComing.listSelect());
|
||||
}
|
||||
|
||||
public static List<EventFight> getEvent(int eventID) {
|
||||
return event.listSelect(eventID);
|
||||
}
|
||||
|
||||
private static List<EventFight> activeFightsCache = null;
|
||||
|
||||
public static void clearActiveFightsCache() {
|
||||
activeFightsCache = null;
|
||||
}
|
||||
|
||||
public static List<EventFight> 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<EventGroup> getGroup() {
|
||||
return Optional.ofNullable(groupId).flatMap(EventGroup::get);
|
||||
}
|
||||
|
||||
public Optional<Team> getWinner() {
|
||||
if(ergebnis == 0)
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(ergebnis == 1 ? Team.get(teamBlue) : Team.get(teamRed));
|
||||
}
|
||||
|
||||
public Optional<Team> getLosser() {
|
||||
if(ergebnis == 0)
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(ergebnis == 1 ? Team.get(teamRed) : Team.get(teamBlue));
|
||||
}
|
||||
|
||||
public List<EventRelation> 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);
|
||||
}
|
||||
}
|
||||
188
CommonCore/SQL/src/de/steamwar/sql/EventFight.kt
Normal file
188
CommonCore/SQL/src/de/steamwar/sql/EventFight.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Int>) : IntEntity(id), Comparable<EventFight> {
|
||||
companion object : IntEntityClass<EventFight>(EventFightTable) {
|
||||
val fights: Queue<EventFight> = 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<EventFight>? = null
|
||||
|
||||
@JvmStatic
|
||||
fun clearActiveFightsCache() {
|
||||
activeFightsCache = null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getActiveFights(): List<EventFight> {
|
||||
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) } }
|
||||
|
||||
val winner: Team?
|
||||
get() = if (ergebnis == 1) Team[teamBlue] else if (ergebnis == 2) Team[teamRed] else null
|
||||
val losser: Team?
|
||||
get() = 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()
|
||||
}
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<EventGroup> table = new Table<>(EventGroup.class);
|
||||
|
||||
private static final SelectStatement<EventGroup> get = table.select(Table.PRIMARY);
|
||||
private static final SelectStatement<EventGroup> 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<EventGroup> 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<EventGroup> 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<Team, Integer> points;
|
||||
|
||||
public List<EventFight> getFights() {
|
||||
return EventFight.get(this);
|
||||
}
|
||||
|
||||
public Set<Integer> getTeamsId() {
|
||||
return getFights().stream().flatMap(fight -> Stream.of(fight.getTeamBlue(), fight.getTeamRed()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public Set<Team> getTeams() {
|
||||
return getTeamsId().stream().map(Team::get).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public Optional<EventFight> getLastFight() {
|
||||
return EventFight.getLast(this);
|
||||
}
|
||||
|
||||
public List<EventRelation> getDependents() {
|
||||
return EventRelation.getGroupRelations(this);
|
||||
}
|
||||
|
||||
public Map<Team, Integer> calculatePoints() {
|
||||
if (points == null) {
|
||||
Map<Integer, Integer> 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
|
||||
}
|
||||
}
|
||||
153
CommonCore/SQL/src/de/steamwar/sql/EventGroup.kt
Normal file
153
CommonCore/SQL/src/de/steamwar/sql/EventGroup.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Int>) : IntEntity(id) {
|
||||
companion object : IntEntityClass<EventGroup>(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) }
|
||||
val lastFight by lazy { Optional.ofNullable(fights.maxByOrNull { it.startTime }) }
|
||||
|
||||
fun getId() = id.value
|
||||
|
||||
private var points: Map<Team, Int>? = null
|
||||
|
||||
fun calculatePoints(): Map<Team, Int> {
|
||||
if (points == null) {
|
||||
val p: MutableMap<Int, Int> = 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
|
||||
}
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<EventRelation> table = new Table<>(EventRelation.class);
|
||||
|
||||
private static final SelectStatement<EventRelation> get = new SelectStatement<>(table, "SELECT * FROM EventRelation WHERE FromType = ? AND FromId = ?");
|
||||
private static final SelectStatement<EventRelation> byId = new SelectStatement<>(table, "SELECT * FROM EventRelation WHERE id = ?");
|
||||
private static final SelectStatement<EventRelation> 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<EventRelation> get(Event event) {
|
||||
return byEvent.listSelect(event.getEventID());
|
||||
}
|
||||
|
||||
public static EventRelation get(int id) {
|
||||
return byId.select(id);
|
||||
}
|
||||
|
||||
public static List<EventRelation> getFightRelations(EventFight fight) {
|
||||
return get.listSelect(FromType.FIGHT, fight.getFightID());
|
||||
}
|
||||
|
||||
public static List<EventRelation> 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<EventFight> getFromFight() {
|
||||
if(fromType == FromType.FIGHT) {
|
||||
return Optional.of(EventFight.get(fromId));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<EventGroup> 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<Team> 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.<Team, Integer>comparingByValue().reversed())
|
||||
.skip(fromPlace)
|
||||
.findFirst()
|
||||
.map(Map.Entry::getKey));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean apply() {
|
||||
Optional<Integer> 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
|
||||
}
|
||||
}
|
||||
149
CommonCore/SQL/src/de/steamwar/sql/EventRelation.kt
Normal file
149
CommonCore/SQL/src/de/steamwar/sql/EventRelation.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Int>) : IntEntity(id) {
|
||||
companion object : IntEntityClass<EventRelation>(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? = 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
|
||||
}
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.Field;
|
||||
import de.steamwar.sql.internal.SelectStatement;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.sql.internal.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class Fight {
|
||||
|
||||
private static final Table<Fight> table = new Table<>(Fight.class);
|
||||
private static final SelectStatement<Fight> 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<Fight> 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<Fight> getPage(int page, int elementsPerPage) {
|
||||
List<Fight> fights = getPage.listSelect(page * elementsPerPage, elementsPerPage);
|
||||
|
||||
List<FightPlayer> 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<FightPlayer> bluePlayers = new ArrayList<>();
|
||||
@Getter
|
||||
private final List<FightPlayer> 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<FightPlayer> fightPlayers) {
|
||||
for(FightPlayer fp : fightPlayers) {
|
||||
if(fp.getFightID() != fightID)
|
||||
continue;
|
||||
|
||||
if(fp.getTeam() == 1)
|
||||
bluePlayers.add(fp);
|
||||
else
|
||||
redPlayers.add(fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
162
CommonCore/SQL/src/de/steamwar/sql/Fight.kt
Normal file
162
CommonCore/SQL/src/de/steamwar/sql/Fight.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Int>) : IntEntity(id) {
|
||||
companion object : IntEntityClass<Fight>(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<Fight> = 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<FightPlayer>
|
||||
lateinit var redPlayers: List<FightPlayer>
|
||||
|
||||
private fun initPlayers(fightPlayers: List<FightPlayer>) {
|
||||
val blue = mutableListOf<FightPlayer>()
|
||||
val red = mutableListOf<FightPlayer>()
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.Field;
|
||||
import de.steamwar.sql.internal.SelectStatement;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.sql.internal.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class FightPlayer {
|
||||
|
||||
private static final Table<FightPlayer> table = new Table<>(FightPlayer.class);
|
||||
private static final Statement create = table.insertAll();
|
||||
private static final SelectStatement<FightPlayer> 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<FightPlayer> batchGet(Stream<Integer> fightIds) {
|
||||
try (SelectStatement<FightPlayer> batch = new SelectStatement<>(table, "SELECT * FROM FightPlayer WHERE FightID IN (" + fightIds.map(Object::toString).collect(Collectors.joining(", ")) + ")")) {
|
||||
return batch.listSelect();
|
||||
}
|
||||
}
|
||||
}
|
||||
80
CommonCore/SQL/src/de/steamwar/sql/FightPlayer.kt
Normal file
80
CommonCore/SQL/src/de/steamwar/sql/FightPlayer.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<CompositeID>) : CompositeEntity(id) {
|
||||
companion object : CompositeEntityClass<FightPlayer>(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<Int>) = 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
|
||||
}
|
||||
@@ -35,11 +35,19 @@ import java.util.stream.Collectors;
|
||||
public final class GameModeConfig<M, W> {
|
||||
|
||||
public static final Function<String, String> ToString = Function.identity();
|
||||
public static final Function<File, String> ToStaticWarGear = __ -> "WarGear";
|
||||
public static final Function<File, String> ToInternalName = file -> file != null ? file.getName().replace(".yml", "") : "WarGear";
|
||||
public static final Function<File, String> ToStaticWarGear = GameModeConfig::constWarGear;
|
||||
public static final Function<File, String> 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<String, GameModeConfig<?, String>> byFileName;
|
||||
private static final Map<String, GameModeConfig<?, String>> byGameName;
|
||||
private static final Map<SchematicType, GameModeConfig<?, String>> bySchematicType;
|
||||
@@ -63,11 +71,15 @@ public final class GameModeConfig<M, W> {
|
||||
}
|
||||
|
||||
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<M, W> {
|
||||
bySchematicType = new HashMap<>();
|
||||
SchematicType.values();
|
||||
DEFAULTS = SQLWrapper.impl.loadGameModeConfig(null);
|
||||
|
||||
byFileName.values().forEach(gameModeConfig -> {
|
||||
List<SchematicType> 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<M, W> {
|
||||
*/
|
||||
public final SchematicType Type;
|
||||
|
||||
private final List<String> SubTypesStrings;
|
||||
|
||||
/**
|
||||
* The schematic types that are also allowed to be chosen in this arena
|
||||
*/
|
||||
@@ -605,6 +631,13 @@ public final class GameModeConfig<M, W> {
|
||||
*/
|
||||
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<M, W> {
|
||||
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<M, W> {
|
||||
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<Set<M>, Integer> Limited = new HashMap<>();
|
||||
@@ -650,6 +685,10 @@ public final class GameModeConfig<M, W> {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.Field;
|
||||
import de.steamwar.sql.internal.SelectStatement;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.sql.internal.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.util.UUID;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class IgnoreSystem {
|
||||
|
||||
private static final Table<IgnoreSystem> table = new Table<>(IgnoreSystem.class, "IgnoredPlayers");
|
||||
private static final SelectStatement<IgnoreSystem> 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());
|
||||
}
|
||||
}
|
||||
74
CommonCore/SQL/src/de/steamwar/sql/IgnoreSystem.kt
Normal file
74
CommonCore/SQL/src/de/steamwar/sql/IgnoreSystem.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<CompositeID>) : CompositeEntity(id) {
|
||||
var ignorer by IgnoreSystemTable.ignorer
|
||||
var ignored by IgnoreSystemTable.ignored
|
||||
|
||||
companion object : CompositeEntityClass<IgnoreSystem>(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()
|
||||
}
|
||||
}
|
||||
}
|
||||
96
CommonCore/SQL/src/de/steamwar/sql/Leaderboard.kt
Normal file
96
CommonCore/SQL/src/de/steamwar/sql/Leaderboard.kt
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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.javatime.CurrentTimestamp
|
||||
import org.jetbrains.exposed.v1.javatime.timestamp
|
||||
import org.jetbrains.exposed.v1.jdbc.select
|
||||
|
||||
object LeaderboardTable : CompositeIdTable("Leaderboard") {
|
||||
val userId = reference("UserId", SteamwarUserTable)
|
||||
val name = varchar("Name", 64).entityId()
|
||||
val time = long("Time")
|
||||
val updatedAt = timestamp("UpdatedAt").defaultExpression(CurrentTimestamp)
|
||||
val bestTime = bool("BestTime")
|
||||
}
|
||||
|
||||
class Leaderboard(id: EntityID<CompositeID>) : CompositeEntity(id) {
|
||||
companion object : CompositeEntityClass<Leaderboard>(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 {
|
||||
findById(CompositeID {
|
||||
it[LeaderboardTable.userId] = user.id.value
|
||||
it[LeaderboardTable.name] = name
|
||||
})
|
||||
}
|
||||
|
||||
@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 {
|
||||
findByIdAndUpdate(CompositeID {
|
||||
it[LeaderboardTable.userId] = userId
|
||||
it[LeaderboardTable.name] = name
|
||||
}) {
|
||||
it.time = time
|
||||
it.bestTime = bestTime
|
||||
} ?: new(
|
||||
CompositeID {
|
||||
it[LeaderboardTable.userId] = userId
|
||||
it[LeaderboardTable.name] = name
|
||||
}
|
||||
) {
|
||||
this.time = time
|
||||
this.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
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Mod> table = new Table<>(Mod.class, "Mods");
|
||||
private static final SelectStatement<Mod> get = table.select(Table.PRIMARY);
|
||||
private static final SelectStatement<Mod> findFirst = new SelectStatement<>(table, "SELECT * FROM Mods WHERE ModType = 0 LIMIT 1");
|
||||
private static final SelectStatement<Mod> 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<Mod> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
88
CommonCore/SQL/src/de/steamwar/sql/Mod.kt
Normal file
88
CommonCore/SQL/src/de/steamwar/sql/Mod.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<CompositeID>) : CompositeEntity(id) {
|
||||
companion object : CompositeEntityClass<Mod>(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");
|
||||
}
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<NodeData> 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<NodeData> 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<NodeData> 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<NodeData> 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;
|
||||
}
|
||||
}
|
||||
100
CommonCore/SQL/src/de/steamwar/sql/NodeData.kt
Normal file
100
CommonCore/SQL/src/de/steamwar/sql/NodeData.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<CompositeID>): 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<NodeData>(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");
|
||||
}
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.Field;
|
||||
import de.steamwar.sql.internal.SelectStatement;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.sql.internal.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.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<NodeDownload> table = new Table<>(NodeDownload.class);
|
||||
private static final Statement insert = table.insertFields("NodeId", "Link");
|
||||
|
||||
private static final SelectStatement<NodeDownload> 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);
|
||||
}
|
||||
}
|
||||
76
CommonCore/SQL/src/de/steamwar/sql/NodeDownload.kt
Normal file
76
CommonCore/SQL/src/de/steamwar/sql/NodeDownload.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Int>("NodeDownload") {
|
||||
override val id = reference("NodeId", SchematicNodeTable).uniqueIndex()
|
||||
val link = varchar("Link", 255)
|
||||
val timestamp = timestamp("Timestamp").defaultExpression(CurrentTimestamp)
|
||||
}
|
||||
|
||||
class NodeDownload(id: EntityID<Int>) : IntEntity(id) {
|
||||
companion object : IntEntityClass<NodeDownload>(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()
|
||||
}
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.Field;
|
||||
import de.steamwar.sql.internal.SelectStatement;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.sql.internal.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class NodeMember {
|
||||
|
||||
public static void init() {
|
||||
// enforce class initialization
|
||||
}
|
||||
|
||||
private static final Table<NodeMember> table = new Table<>(NodeMember.class);
|
||||
private static final SelectStatement<NodeMember> getNodeMember = table.select(Table.PRIMARY);
|
||||
private static final SelectStatement<NodeMember> getNodeMembers = table.selectFields("NodeId");
|
||||
private static final SelectStatement<NodeMember> getSchematics = table.selectFields("UserId");
|
||||
private static final Statement create = table.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<Integer> 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<NodeMember> getNodeMembers(int node) {
|
||||
return new HashSet<>(getNodeMembers.listSelect(node));
|
||||
}
|
||||
|
||||
public static Set<NodeMember> getSchematics(int member) {
|
||||
return new HashSet<>(getSchematics.listSelect(member));
|
||||
}
|
||||
|
||||
public void setParentId(Integer parentId) {
|
||||
this.parentId = parentId;
|
||||
updateParent.update(this.parentId, nodeId, userId);
|
||||
}
|
||||
}
|
||||
92
CommonCore/SQL/src/de/steamwar/sql/NodeMember.kt
Normal file
92
CommonCore/SQL/src/de/steamwar/sql/NodeMember.kt
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<CompositeID>) : CompositeEntity(id) {
|
||||
companion object : CompositeEntityClass<NodeMember>(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: 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) })
|
||||
|
||||
fun setParentId(id: Int?) {
|
||||
parent = Optional.ofNullable(id)
|
||||
}
|
||||
|
||||
override fun delete() = useDb {
|
||||
super.delete()
|
||||
}
|
||||
}
|
||||
117
CommonCore/SQL/src/de/steamwar/sql/PersonalKit.kt
Normal file
117
CommonCore/SQL/src/de/steamwar/sql/PersonalKit.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<CompositeID>): CompositeEntity(id) {
|
||||
companion object: CompositeEntityClass<InternalKit>(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()
|
||||
}
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.Field;
|
||||
import de.steamwar.sql.internal.SelectStatement;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.sql.internal.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class PollAnswer {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private static String currentPoll;
|
||||
|
||||
private static final Table<PollAnswer> table = new Table<>(PollAnswer.class);
|
||||
|
||||
private static final SelectStatement<PollAnswer> 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<Integer, Integer> getCurrentResults() {
|
||||
return getResults.select(rs -> {
|
||||
Map<Integer, Integer> 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);
|
||||
}
|
||||
}
|
||||
78
CommonCore/SQL/src/de/steamwar/sql/PollAnswer.kt
Normal file
78
CommonCore/SQL/src/de/steamwar/sql/PollAnswer.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql
|
||||
|
||||
import de.steamwar.sql.internal.useDb
|
||||
import org.jetbrains.exposed.v1.core.VarCharColumnType
|
||||
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 PollAnswerTable: CompositeIdTable("PollAnswer") {
|
||||
val userId = reference("UserID", SteamwarUserTable)
|
||||
val question = varchar("Question", 150)
|
||||
val answer = integer("Answer")
|
||||
}
|
||||
|
||||
class PollAnswer(id: EntityID<CompositeID>): CompositeEntity(id) {
|
||||
var userId by PollAnswerTable.userId
|
||||
private set
|
||||
var question by PollAnswerTable.question
|
||||
private set
|
||||
private var answerId by PollAnswerTable.answer
|
||||
var answer: Int
|
||||
get() = answerId
|
||||
set(value) = useDb {
|
||||
answerId = value
|
||||
}
|
||||
|
||||
companion object: CompositeEntityClass<PollAnswer>(PollAnswerTable) {
|
||||
@JvmStatic
|
||||
var currentPoll: String? = null
|
||||
|
||||
@JvmStatic
|
||||
fun get(userId: Int) = useDb {
|
||||
find { (PollAnswerTable.userId eq userId) and (PollAnswerTable.question eq currentPoll!!) }.firstOrNull()
|
||||
?: new {
|
||||
this.userId = EntityID(userId, SteamwarUserTable)
|
||||
this.question = currentPoll!!
|
||||
this.answerId = 0
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getCurrentResults(): Map<Int, Int> = useDb {
|
||||
exec("SELECT Count(UserID) AS Times, Answer FROM PollAnswer WHERE Question = ? GROUP BY Answer ORDER BY Times ASC",
|
||||
args = listOf(VarCharColumnType() to currentPoll!!)) {
|
||||
val result = mutableMapOf<Int, Int>()
|
||||
while (it.next()) {
|
||||
result[it.getInt("Answer")] = it.getInt("Times")
|
||||
}
|
||||
result
|
||||
} ?: emptyMap()
|
||||
}
|
||||
}
|
||||
|
||||
fun hasAnswered() = answerId != 0
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Punishment> table = new Table<>(Punishment.class, "Punishments");
|
||||
private static final SelectStatement<Punishment> getPunishments = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE PunishmentId IN (SELECT MAX(PunishmentId) FROM Punishments WHERE UserId = ? GROUP BY Type)");
|
||||
private static final SelectStatement<Punishment> getPunishment = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE UserId = ? AND Type = ? ORDER BY PunishmentId DESC LIMIT 1");
|
||||
private static final SelectStatement<Punishment> 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<PunishmentType, Punishment> getPunishmentsOfPlayer(int user) {
|
||||
return getPunishments.listSelect(user).stream().collect(Collectors.toMap(Punishment::getType, punishment -> punishment));
|
||||
}
|
||||
|
||||
public static List<Punishment> getAllPunishmentsOfPlayer(int user) {
|
||||
return getAllPunishments.listSelect(user);
|
||||
}
|
||||
|
||||
public static boolean isPunished(SteamwarUser user, PunishmentType type, Consumer<Punishment> callback) {
|
||||
Punishment punishment = Punishment.getPunishmentOfPlayer(user.getId(), type);
|
||||
if(punishment == null || !punishment.isCurrent()) {
|
||||
return false;
|
||||
} else {
|
||||
callback.accept(punishment);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
186
CommonCore/SQL/src/de/steamwar/sql/Punishment.kt
Normal file
186
CommonCore/SQL/src/de/steamwar/sql/Punishment.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Int>) : IntEntity(id) {
|
||||
companion object : IntEntityClass<Punishment>(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<Punishment>): 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.TEAM),
|
||||
Mute("MUTE_TEAM", "MUTE_PERMA", "MUTE_UNTIL", "UNMUTE_ERROR", "UNMUTE", UserPerm.TEAM),
|
||||
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.TEAM
|
||||
),
|
||||
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.TEAM, true);
|
||||
|
||||
fun isMulti() = multi
|
||||
}
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.Field;
|
||||
import de.steamwar.sql.internal.SelectStatement;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.sql.internal.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class Referee {
|
||||
|
||||
private static final Table<Referee> table = new Table<>(Referee.class);
|
||||
private static final SelectStatement<Referee> byEvent = table.selectFields("eventID");
|
||||
|
||||
private static final Statement insert = table.insertAll();
|
||||
private static final Statement delete = table.delete("eventReferee");
|
||||
|
||||
public static void add(int eventID, int userID) {
|
||||
insert.update(eventID, userID);
|
||||
}
|
||||
|
||||
public static void remove(int eventID, int userID) {
|
||||
delete.update(eventID, userID);
|
||||
}
|
||||
|
||||
public static Set<Integer> get(int eventID) {
|
||||
return byEvent.listSelect(eventID).stream().map(referee -> referee.userID).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Field(keys = {"eventReferee"})
|
||||
private final int eventID;
|
||||
@Field(keys = {"eventReferee"})
|
||||
private final int userID;
|
||||
}
|
||||
66
CommonCore/SQL/src/de/steamwar/sql/Referee.kt
Normal file
66
CommonCore/SQL/src/de/steamwar/sql/Referee.kt
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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
|
||||
|
||||
object RefereeTable: CompositeIdTable("Referee") {
|
||||
val eventId = reference("EventId", EventTable)
|
||||
val userId = reference("UserId", SteamwarUserTable)
|
||||
|
||||
override val primaryKey = PrimaryKey(eventId, userId)
|
||||
|
||||
init {
|
||||
addIdColumn(eventId)
|
||||
addIdColumn(userId)
|
||||
}
|
||||
}
|
||||
|
||||
class Referee(id: EntityID<CompositeID>): CompositeEntity(id) {
|
||||
companion object: CompositeEntityClass<Referee>(RefereeTable) {
|
||||
@JvmStatic
|
||||
fun add(eventId: Int, userId: Int) = useDb {
|
||||
new {
|
||||
this.eventID = eventId
|
||||
this.userID = userId
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun remove(eventId: Int, userId: Int) = useDb {
|
||||
find { (RefereeTable.eventId eq eventId) and (RefereeTable.userId eq userId) }.firstOrNull()?.delete()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun get(event: Int) = useDb {
|
||||
find { RefereeTable.eventId eq event }.map { it.userID }.toSet()
|
||||
}
|
||||
}
|
||||
|
||||
var eventID by RefereeTable.eventId.transform({ EntityID(it, EventTable) }, { it.value })
|
||||
var userID by RefereeTable.userId.transform({ EntityID(it, SteamwarUserTable) }, { it.value })
|
||||
}
|
||||
@@ -22,6 +22,8 @@ package de.steamwar.sql;
|
||||
import de.steamwar.ImplementationProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public interface SQLWrapper<M> {
|
||||
SQLWrapper<?> impl = ImplementationProvider.getImpl("de.steamwar.sql.SQLWrapperImpl");
|
||||
@@ -30,6 +32,10 @@ public interface SQLWrapper<M> {
|
||||
|
||||
GameModeConfig<M, String> loadGameModeConfig(File file);
|
||||
|
||||
default List<M> getMaterialWithGreaterBlastResistance(double maxBlastResistance) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
default void processSchematicType(GameModeConfig<?, String> gameModeConfig) {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,68 +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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.Field;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.sql.internal.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class SWException {
|
||||
|
||||
public static void init() {
|
||||
// force class initialialisation
|
||||
}
|
||||
|
||||
private static final String CWD = System.getProperty("user.dir");
|
||||
private static final String SERVER_NAME = new File(CWD).getName();
|
||||
|
||||
private static final Table<SWException> table = new Table<>(SWException.class, "Exception");
|
||||
private static final Statement insert = table.insertFields(true, "server", "message", "stacktrace");
|
||||
|
||||
@Field(keys = {Table.PRIMARY}, autoincrement = true)
|
||||
private final int id;
|
||||
@Field(def = "CURRENT_TIMESTAMP")
|
||||
private final Timestamp time;
|
||||
@Field
|
||||
private final String server;
|
||||
@Field
|
||||
private final String message;
|
||||
@Field
|
||||
private final String stacktrace;
|
||||
|
||||
public static void log(String message, String stacktrace){
|
||||
insert.update(SERVER_NAME, generateMessage(message), stacktrace);
|
||||
}
|
||||
|
||||
public static int logGetId(String message, String stacktrace) {
|
||||
return insert.insertGetKey(SERVER_NAME, generateMessage(message), stacktrace);
|
||||
}
|
||||
|
||||
private static String generateMessage(String message) {
|
||||
StringBuilder msgBuilder = new StringBuilder(message);
|
||||
SQLWrapper.impl.additionalExceptionMetadata(msgBuilder);
|
||||
msgBuilder.append("\nCWD: ").append(CWD);
|
||||
return msgBuilder.toString();
|
||||
}
|
||||
}
|
||||
72
CommonCore/SQL/src/de/steamwar/sql/SWException.kt
Normal file
72
CommonCore/SQL/src/de/steamwar/sql/SWException.kt
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql
|
||||
|
||||
import de.steamwar.sql.internal.useDb
|
||||
import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
|
||||
import org.jetbrains.exposed.v1.javatime.CurrentTimestamp
|
||||
import org.jetbrains.exposed.v1.javatime.timestamp
|
||||
import org.jetbrains.exposed.v1.jdbc.insert
|
||||
import org.jetbrains.exposed.v1.jdbc.insertAndGetId
|
||||
import java.io.File
|
||||
|
||||
object ExceptionTable: IntIdTable("Exception") {
|
||||
val time = timestamp("Time").defaultExpression(CurrentTimestamp)
|
||||
val server = text("Server")
|
||||
val message = text("Message")
|
||||
val stackTrace = text("StackTrace")
|
||||
}
|
||||
|
||||
class SWException {
|
||||
companion object {
|
||||
val cwd = System.getProperty("user.dir")
|
||||
val serverName = File(cwd).name
|
||||
|
||||
@JvmStatic
|
||||
fun init() = Unit
|
||||
|
||||
@JvmStatic
|
||||
fun log(message: String, stacktrace: String) = useDb {
|
||||
ExceptionTable.insert {
|
||||
it[ExceptionTable.server] = serverName
|
||||
it[ExceptionTable.message] = generateMessage(message)
|
||||
it[ExceptionTable.stackTrace] = stacktrace
|
||||
}
|
||||
|
||||
Unit
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun logGetId(message: String, stacktrace: String) = useDb {
|
||||
ExceptionTable.insertAndGetId {
|
||||
it[ExceptionTable.server] = serverName
|
||||
it[ExceptionTable.message] = generateMessage(message)
|
||||
it[ExceptionTable.stackTrace] = stacktrace
|
||||
}.value
|
||||
}
|
||||
|
||||
fun generateMessage(message: String): String {
|
||||
val msgBuilder = StringBuilder(message)
|
||||
SQLWrapper.impl.additionalExceptionMetadata(msgBuilder)
|
||||
msgBuilder.append("\nCWD: ").append(cwd)
|
||||
return msgBuilder.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.Field;
|
||||
import de.steamwar.sql.internal.SelectStatement;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.sql.internal.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class SchemElo {
|
||||
private static final int ELO_DEFAULT = 1000;
|
||||
|
||||
private static final Table<SchemElo> table = new Table<>(SchemElo.class);
|
||||
private static final SelectStatement<SchemElo> select = table.select(Table.PRIMARY);
|
||||
private static final Statement setElo = table.insertAll();
|
||||
|
||||
public static int getElo(SchematicNode node, int season) {
|
||||
SchemElo elo = select.select(node, season);
|
||||
return elo != null ? elo.elo : 0;
|
||||
}
|
||||
|
||||
public static int getCurrentElo(int schemID) {
|
||||
SchemElo elo = select.select(schemID, Season.getSeason());
|
||||
return elo != null ? elo.elo : ELO_DEFAULT;
|
||||
}
|
||||
|
||||
public static void setElo(int schemID, int elo) {
|
||||
setElo.update(schemID, elo, Season.getSeason());
|
||||
}
|
||||
|
||||
@Field(keys = {Table.PRIMARY})
|
||||
private final int schemId;
|
||||
@Field
|
||||
private final int elo;
|
||||
@Field(keys = {Table.PRIMARY})
|
||||
private final int season;
|
||||
}
|
||||
74
CommonCore/SQL/src/de/steamwar/sql/SchemElo.kt
Normal file
74
CommonCore/SQL/src/de/steamwar/sql/SchemElo.kt
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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
|
||||
|
||||
object SchemEloTable: CompositeIdTable("SchemElo") {
|
||||
val schemId = reference("SchemId", SchematicNodeTable)
|
||||
val season = integer("Season").entityId()
|
||||
val elo = integer("Elo")
|
||||
|
||||
override val primaryKey = PrimaryKey(schemId, season)
|
||||
|
||||
init {
|
||||
addIdColumn(schemId)
|
||||
}
|
||||
}
|
||||
|
||||
class SchemElo(id: EntityID<CompositeID>): CompositeEntity(id) {
|
||||
companion object: CompositeEntityClass<SchemElo>(SchemEloTable) {
|
||||
@JvmStatic
|
||||
fun getElo(node: SchematicNode, season: Int, defaultElo: Int = 0) = useDb {
|
||||
find { (SchemEloTable.schemId eq node.id) and (SchemEloTable.season eq season) }.firstOrNull()?.elo ?: defaultElo
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getCurrentElo(schemId: Int) = getElo(SchematicNode.byId(schemId)!!, Season.getSeason())
|
||||
|
||||
@JvmStatic
|
||||
fun setElo(node: Int, elo: Int) = useDb {
|
||||
findByIdAndUpdate(CompositeID {
|
||||
it[SchemEloTable.schemId] = node
|
||||
it[SchemEloTable.season] = Season.getSeason()
|
||||
}) {
|
||||
it.elo = elo
|
||||
} ?: SchemEloTable.insertIgnore {
|
||||
it[SchemEloTable.schemId] = node
|
||||
it[SchemEloTable.season] = Season.getSeason()
|
||||
it[SchemEloTable.elo] = elo
|
||||
}
|
||||
|
||||
return@useDb
|
||||
}
|
||||
}
|
||||
|
||||
var node by SchemEloTable.schemId
|
||||
var season by SchemEloTable.season
|
||||
var elo by SchemEloTable.elo
|
||||
}
|
||||
@@ -1,634 +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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.*;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class SchematicNode {
|
||||
|
||||
static {
|
||||
SchematicType.Normal.name(); // Ensure SchematicType is loaded.
|
||||
new SqlTypeMapper<>(SchematicNode.class, null, (rs, identifier) -> {
|
||||
throw new SecurityException("SchematicNode cannot be used as type (recursive select)");
|
||||
}, (st, index, value) -> st.setInt(index, value.nodeId));
|
||||
}
|
||||
|
||||
private static final Map<Integer, Map<String, List<String>>> TAB_CACHE = new HashMap<>();
|
||||
|
||||
public static void clear() {
|
||||
TAB_CACHE.clear();
|
||||
}
|
||||
|
||||
private static final String nodeSelector = "SELECT NodeId, NodeOwner, NodeOwner AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode ";
|
||||
|
||||
private static final Table<SchematicNode> table = new Table<>(SchematicNode.class);
|
||||
private static final Statement create = table.insertFields(true, "NodeOwner", "NodeName", "ParentNode", "NodeItem",
|
||||
"NodeType");
|
||||
private static final Statement update = table.update(Table.PRIMARY, "NodeName", "ParentNode", "NodeItem",
|
||||
"NodeType", "NodeRank", "Config");
|
||||
private static final Statement delete = table.delete(Table.PRIMARY);
|
||||
|
||||
private static final SelectStatement<SchematicNode> byId = new SelectStatement<>(table,
|
||||
nodeSelector + "WHERE NodeId = ?");
|
||||
private static final SelectStatement<SchematicNode> byOwnerNameParent = new SelectStatement<>(table,
|
||||
nodeSelector + "WHERE NodeOwner = ? AND NodeName = ? AND ParentNode " + Statement.NULL_SAFE_EQUALS + "?");
|
||||
private static final SelectStatement<SchematicNode> byParent = new SelectStatement<>(table,
|
||||
nodeSelector + "WHERE ParentNode" + Statement.NULL_SAFE_EQUALS + "? ORDER BY NodeName");
|
||||
private static final SelectStatement<SchematicNode> dirsByParent = new SelectStatement<>(table, nodeSelector
|
||||
+ "WHERE ParentNode" + Statement.NULL_SAFE_EQUALS + "? AND NodeType is NULL ORDER BY NodeName");
|
||||
private static final SelectStatement<SchematicNode> byOwnerType = new SelectStatement<>(table,
|
||||
nodeSelector + "WHERE NodeOwner = ? AND NodeType = ? ORDER BY NodeName");
|
||||
private static final SelectStatement<SchematicNode> byType = new SelectStatement<>(table,
|
||||
nodeSelector + "WHERE NodeType = ? ORDER BY NodeName");
|
||||
private static final SelectStatement<SchematicNode> all = new SelectStatement<>(table,
|
||||
"WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId");
|
||||
private static final SelectStatement<SchematicNode> list = new SelectStatement<>(table,
|
||||
"SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId "
|
||||
+ Statement.NULL_SAFE_EQUALS
|
||||
+ "? AND NM.UserId = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode WHERE (? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?) ORDER BY NodeName");
|
||||
private static final SelectStatement<SchematicNode> byParentName = new SelectStatement<>(table,
|
||||
"SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId "
|
||||
+ Statement.NULL_SAFE_EQUALS
|
||||
+ "? AND NM.UserId = ? AND SchematicNode.NodeName = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode WHERE ((? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?)) AND NodeName = ?");
|
||||
private static final SelectStatement<SchematicNode> schematicAccessibleForUser = new SelectStatement<>(table,
|
||||
"WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeId = ?");
|
||||
private static final SelectStatement<SchematicNode> accessibleByUserTypeInParent = new SelectStatement<>(table,
|
||||
"WITH RECURSIVE RSASN AS(WITH RECURSIVE RSAN AS (WITH RSANH AS (WITH RECURSIVE RSA AS (SELECT SN.NodeId, NM.ParentId FROM SchematicNode SN LEFT JOIN NodeMember NM on SN.NodeId = NM.NodeId WHERE NM.UserId = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN INNER JOIN RSA ON RSA.NodeId = SN.ParentNode) SELECT * FROM RSA UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?) SELECT * FROM RSANH UNION SELECT SN.NodeId, SN.ParentNode FROM RSANH JOIN SchematicNode SN ON SN.ParentNode = RSANH.NodeId) SELECT RSAN.NodeId, RSAN.ParentId FROM RSAN JOIN SchematicNode SN ON SN.NodeId = RSAN.NodeId WHERE NodeType = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN JOIN RSASN ON SN.NodeId = RSASN.ParentId) SELECT SN.*, ? as EffectiveOwner, RSASN.ParentId AS ParentNode FROM RSASN JOIN SchematicNode SN ON SN.NodeId = RSASN.NodeId WHERE RSASN.ParentId"
|
||||
+ Statement.NULL_SAFE_EQUALS + "? ORDER BY NodeName");
|
||||
private static final SelectStatement<SchematicNode> accessibleByUserType = new SelectStatement<>(table,
|
||||
"WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeType = ?");
|
||||
private static final SelectStatement<SchematicNode> byIdAndUser = new SelectStatement<>(table,
|
||||
"SELECT NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode WHERE NodeId = ?");
|
||||
private static final SelectStatement<SchematicNode> allParentsOfNode = new SelectStatement<>(table,
|
||||
"WITH RECURSIVE R AS (SELECT NodeId, ParentNode FROM EffectiveSchematicNode WHERE NodeId = ? AND EffectiveOwner = ? UNION SELECT E.NodeId, E.ParentNode FROM R, EffectiveSchematicNode E WHERE R.ParentNode = E.NodeId AND E.EffectiveOwner = ?) SELECT SN.NodeId, SN.NodeOwner, ? AS EffectiveOwner, SN.NodeName, R.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.Config FROM R INNER JOIN SchematicNode SN ON SN.NodeId = R.NodeId");
|
||||
|
||||
static {
|
||||
NodeMember.init();
|
||||
}
|
||||
|
||||
@Field(keys = { Table.PRIMARY }, autoincrement = true)
|
||||
private final int nodeId;
|
||||
@Field(keys = { "OwnerNameParent" })
|
||||
private final int nodeOwner;
|
||||
@Field(def = "0")
|
||||
@Getter
|
||||
private final int effectiveOwner;
|
||||
@Field(keys = { "OwnerNameParent" })
|
||||
private String nodeName;
|
||||
@Field(keys = { "OwnerNameParent" }, nullable = true)
|
||||
private Integer parentNode;
|
||||
@Field(def = "CURRENT_TIMESTAMP")
|
||||
private Timestamp lastUpdate;
|
||||
@Field(def = "''")
|
||||
private String nodeItem;
|
||||
@Field(def = "'normal'", nullable = true)
|
||||
private SchematicType nodeType;
|
||||
@Field(def = "0")
|
||||
private int nodeRank;
|
||||
@Field
|
||||
private int config;
|
||||
|
||||
private String brCache;
|
||||
|
||||
public SchematicNode(
|
||||
int nodeId,
|
||||
int nodeOwner,
|
||||
int effectiveOwner,
|
||||
String nodeName,
|
||||
Integer parentNode,
|
||||
Timestamp lastUpdate,
|
||||
String nodeItem,
|
||||
SchematicType nodeType,
|
||||
int nodeRank,
|
||||
int config) {
|
||||
this.nodeId = nodeId;
|
||||
this.nodeOwner = nodeOwner;
|
||||
this.effectiveOwner = effectiveOwner;
|
||||
this.nodeName = nodeName;
|
||||
this.parentNode = parentNode;
|
||||
this.nodeItem = nodeItem;
|
||||
this.nodeType = nodeType;
|
||||
this.lastUpdate = lastUpdate;
|
||||
this.nodeRank = nodeRank;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public static List<SchematicNode> getAll(SteamwarUser user) {
|
||||
return all.listSelect(user, user, user);
|
||||
}
|
||||
|
||||
public static Map<Integer, List<SchematicNode>> getAllMap(SteamwarUser user) {
|
||||
return map(getAll(user));
|
||||
}
|
||||
|
||||
public static List<SchematicNode> list(SteamwarUser user, Integer schematicId) {
|
||||
return list.listSelect(user, schematicId, user, user, schematicId, user, schematicId, schematicId);
|
||||
}
|
||||
|
||||
public static SchematicNode byParentName(SteamwarUser user, Integer schematicId, String name) {
|
||||
return byParentName.select(user, schematicId, user, name, user, schematicId, user, schematicId, schematicId,
|
||||
name);
|
||||
}
|
||||
|
||||
public static List<SchematicNode> accessibleByUserType(SteamwarUser user, SchematicType type) {
|
||||
return accessibleByUserType.listSelect(user, user, user, type);
|
||||
}
|
||||
|
||||
public static Map<Integer, List<SchematicNode>> accessibleByUserTypeMap(SteamwarUser user, SchematicType type) {
|
||||
return map(accessibleByUserType(user, type));
|
||||
}
|
||||
|
||||
public static boolean schematicAccessibleForUser(SteamwarUser user, Integer schematicId) {
|
||||
return schematicAccessibleForUser.select(user, user, user, schematicId) != null;
|
||||
}
|
||||
|
||||
public static List<SchematicNode> accessibleByUserTypeParent(SteamwarUser user, SchematicType type,
|
||||
Integer parentId) {
|
||||
return accessibleByUserTypeInParent.listSelect(user, user, type, user, parentId);
|
||||
}
|
||||
|
||||
public static SchematicNode byIdAndUser(SteamwarUser user, Integer id) {
|
||||
return byIdAndUser.select(user, id);
|
||||
}
|
||||
|
||||
public static List<SchematicNode> parentsOfNode(SteamwarUser user, Integer id) {
|
||||
return allParentsOfNode.listSelect(id, user, user, user);
|
||||
}
|
||||
|
||||
private static Map<Integer, List<SchematicNode>> map(List<SchematicNode> in) {
|
||||
Map<Integer, List<SchematicNode>> map = new HashMap<>();
|
||||
for (SchematicNode effectiveSchematicNode : in) {
|
||||
map.computeIfAbsent(effectiveSchematicNode.getOptionalParent().orElse(0), k -> new ArrayList<>())
|
||||
.add(effectiveSchematicNode);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public static SchematicNode createSchematic(int owner, String name, Integer parent) {
|
||||
return createSchematicNode(owner, name, parent, SchematicType.Normal.toDB(), "");
|
||||
}
|
||||
|
||||
public static SchematicNode createSchematicDirectory(int owner, String name, Integer parent) {
|
||||
return createSchematicNode(owner, name, parent, null, "");
|
||||
}
|
||||
|
||||
public static SchematicNode createSchematicNode(int owner, String name, Integer parent, String type, String item) {
|
||||
if (parent != null && parent == 0)
|
||||
parent = null;
|
||||
int nodeId = create.insertGetKey(owner, name, parent, item, type);
|
||||
return getSchematicNode(nodeId);
|
||||
}
|
||||
|
||||
public static SchematicNode getSchematicNode(int owner, String name, SchematicNode parent) {
|
||||
return getSchematicNode(owner, name, parent.getId());
|
||||
}
|
||||
|
||||
public static SchematicNode getSchematicNode(int owner, String name, Integer parent) {
|
||||
return byOwnerNameParent.select(owner, name, parent);
|
||||
}
|
||||
|
||||
public static List<SchematicNode> getSchematicNodeInNode(SchematicNode parent) {
|
||||
return getSchematicNodeInNode(parent.getId());
|
||||
}
|
||||
|
||||
public static List<SchematicNode> getSchematicNodeInNode(Integer parent) {
|
||||
return byParent.listSelect(parent);
|
||||
}
|
||||
|
||||
public static List<SchematicNode> getSchematicDirectoryInNode(Integer parent) {
|
||||
return dirsByParent.listSelect(parent);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static SchematicNode getSchematicDirectory(String name, SchematicNode parent) {
|
||||
return getSchematicNode(name, parent.getId());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static SchematicNode getSchematicDirectory(String name, Integer parent) {
|
||||
return getSchematicNode(name, parent);
|
||||
}
|
||||
|
||||
public static SchematicNode getSchematicNode(String name, Integer parent) {
|
||||
return byParentName.select(name, parent);
|
||||
}
|
||||
|
||||
public static SchematicNode getSchematicNode(int id) {
|
||||
return byId.select(id);
|
||||
}
|
||||
|
||||
public static List<SchematicNode> getAccessibleSchematicsOfTypeInParent(int owner, String schemType,
|
||||
Integer parent) {
|
||||
return accessibleByUserTypeParent(SteamwarUser.get(owner), SchematicType.fromDB(schemType), parent);
|
||||
}
|
||||
|
||||
public static List<SchematicNode> getAllAccessibleSchematicsOfType(int user, String schemType) {
|
||||
return accessibleByUserType(SteamwarUser.get(user), SchematicType.fromDB(schemType));
|
||||
}
|
||||
|
||||
public static List<SchematicNode> getAllSchematicsOfType(int owner, String schemType) {
|
||||
return byOwnerType.listSelect(owner, schemType);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static List<SchematicNode> getAllSchematicsOfType(String schemType) {
|
||||
return byType.listSelect(schemType);
|
||||
}
|
||||
|
||||
public static List<SchematicNode> getAllSchematicsOfType(SchematicType schemType) {
|
||||
return byType.listSelect(schemType);
|
||||
}
|
||||
|
||||
public static List<SchematicNode> deepGet(Integer parent, Predicate<SchematicNode> filter) {
|
||||
List<SchematicNode> finalList = new ArrayList<>();
|
||||
List<SchematicNode> nodes = SchematicNode.getSchematicNodeInNode(parent);
|
||||
nodes.forEach(node -> {
|
||||
if (node.isDir()) {
|
||||
finalList.addAll(deepGet(node.getId(), filter));
|
||||
} else {
|
||||
if (filter.test(node))
|
||||
finalList.add(node);
|
||||
}
|
||||
});
|
||||
return finalList;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static List<SchematicNode> getSchematicsAccessibleByUser(int user, Integer parent) {
|
||||
return list(SteamwarUser.get(user), parent);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static List<SchematicNode> getAllSchematicsAccessibleByUser(int user) {
|
||||
return getAll(SteamwarUser.get(user));
|
||||
}
|
||||
|
||||
public static List<SchematicNode> getAllParentsOfNode(SchematicNode node) {
|
||||
return getAllParentsOfNode(node.getId());
|
||||
}
|
||||
|
||||
public static List<SchematicNode> getAllParentsOfNode(int node) {
|
||||
return allParentsOfNode.listSelect(node);
|
||||
}
|
||||
|
||||
public static SchematicNode getNodeFromPath(SteamwarUser user, String s) {
|
||||
if (s.startsWith("/")) {
|
||||
s = s.substring(1);
|
||||
}
|
||||
if (s.endsWith("/")) {
|
||||
s = s.substring(0, s.length() - 1);
|
||||
}
|
||||
if (s.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (s.contains("/")) {
|
||||
String[] layers = s.split("/");
|
||||
Optional<SchematicNode> currentNode = Optional
|
||||
.ofNullable(SchematicNode.byParentName(user, null, layers[0]));
|
||||
for (int i = 1; i < layers.length; i++) {
|
||||
int finalI = i;
|
||||
Optional<SchematicNode> node = currentNode.map(effectiveSchematicNode -> SchematicNode
|
||||
.byParentName(user, effectiveSchematicNode.getId(), layers[finalI]));
|
||||
if (!node.isPresent()) {
|
||||
return null;
|
||||
} else {
|
||||
currentNode = node;
|
||||
if (!currentNode.map(SchematicNode::isDir).orElse(false) && i != layers.length - 1) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return currentNode.orElse(null);
|
||||
} else {
|
||||
return SchematicNode.byParentName(user, null, s);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<SchematicNode> filterSchems(int user, Predicate<SchematicNode> filter) {
|
||||
List<SchematicNode> finalList = new ArrayList<>();
|
||||
List<SchematicNode> nodes = getSchematicsAccessibleByUser(user, null);
|
||||
nodes.forEach(node -> {
|
||||
if (node.isDir()) {
|
||||
finalList.addAll(deepGet(node.getId(), filter));
|
||||
} else {
|
||||
if (filter.test(node))
|
||||
finalList.add(node);
|
||||
}
|
||||
});
|
||||
return finalList;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return nodeId;
|
||||
}
|
||||
|
||||
public int getOwner() {
|
||||
return nodeOwner;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return nodeName;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.nodeName = name;
|
||||
updateDB();
|
||||
}
|
||||
|
||||
public Integer getParent() {
|
||||
return parentNode;
|
||||
}
|
||||
|
||||
public Optional<Integer> getOptionalParent() {
|
||||
return Optional.ofNullable(parentNode);
|
||||
}
|
||||
|
||||
public void setParent(Integer parent) {
|
||||
this.parentNode = parent;
|
||||
updateDB();
|
||||
}
|
||||
|
||||
public String getItem() {
|
||||
if (nodeItem.isEmpty()) {
|
||||
return isDir() ? "CHEST" : "CAULDRON_ITEM";
|
||||
}
|
||||
return nodeItem;
|
||||
}
|
||||
|
||||
public void setItem(String item) {
|
||||
this.nodeItem = item;
|
||||
updateDB();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public String getType() {
|
||||
return nodeType.name();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setType(String type) {
|
||||
if (isDir())
|
||||
throw new SecurityException("Node is Directory");
|
||||
this.nodeType = SchematicType.fromDB(type);
|
||||
updateDB();
|
||||
}
|
||||
|
||||
public boolean isDir() {
|
||||
return nodeType == null;
|
||||
}
|
||||
|
||||
public String getFileEnding() {
|
||||
if (isDir())
|
||||
throw new SecurityException("Node is Directory");
|
||||
return NodeData.getLatest(this).getNodeFormat().getFileEnding();
|
||||
}
|
||||
|
||||
public int getRank() {
|
||||
if (isDir())
|
||||
throw new SecurityException("Node is Directory");
|
||||
return nodeRank;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int getRankUnsafe() {
|
||||
return nodeRank;
|
||||
}
|
||||
|
||||
public void setRank(int rank) {
|
||||
if (isDir())
|
||||
throw new SecurityException("Node is Directory");
|
||||
this.nodeRank = rank;
|
||||
}
|
||||
|
||||
public SchematicType getSchemtype() {
|
||||
if (isDir())
|
||||
throw new SecurityException("Is Directory");
|
||||
return nodeType;
|
||||
}
|
||||
|
||||
public void setSchemtype(SchematicType type) {
|
||||
if (isDir())
|
||||
throw new SecurityException("Is Directory");
|
||||
this.nodeType = type;
|
||||
updateDB();
|
||||
}
|
||||
|
||||
public boolean replaceColor() {
|
||||
return getConfig(ConfigFlags.REPLACE_COLOR);
|
||||
}
|
||||
|
||||
public void setReplaceColor(boolean replaceColor) {
|
||||
if (isDir())
|
||||
throw new SecurityException("Is Directory");
|
||||
setConfig(ConfigFlags.REPLACE_COLOR, replaceColor);
|
||||
}
|
||||
|
||||
public boolean allowReplay() {
|
||||
return getConfig(ConfigFlags.ALLOW_REPLAY);
|
||||
}
|
||||
|
||||
public void setAllowReplay(boolean allowReplay) {
|
||||
if (isDir())
|
||||
throw new SecurityException("Is Directory");
|
||||
setConfig(ConfigFlags.ALLOW_REPLAY, allowReplay);
|
||||
}
|
||||
|
||||
public boolean isPrepared() {
|
||||
return getConfig(ConfigFlags.IS_PREPARED);
|
||||
}
|
||||
|
||||
public void setPrepared(boolean prepared) {
|
||||
if (isDir())
|
||||
throw new SecurityException("Is Directory");
|
||||
setConfig(ConfigFlags.IS_PREPARED, prepared);
|
||||
}
|
||||
|
||||
public boolean getConfig(ConfigFlags flag) {
|
||||
return (config & (1 << flag.ordinal())) != 0;
|
||||
}
|
||||
|
||||
public void setConfig(ConfigFlags flag, boolean value) {
|
||||
if (value) {
|
||||
config |= (1 << flag.ordinal());
|
||||
} else {
|
||||
config &= ~(1 << flag.ordinal());
|
||||
}
|
||||
updateDB();
|
||||
}
|
||||
|
||||
public SchematicNode getParentNode() {
|
||||
if (parentNode == null)
|
||||
return null;
|
||||
return SchematicNode.getSchematicNode(parentNode);
|
||||
}
|
||||
|
||||
public int getElo(int season) {
|
||||
return SchemElo.getElo(this, season);
|
||||
}
|
||||
|
||||
public boolean accessibleByUser(SteamwarUser user) {
|
||||
return NodeMember.getNodeMember(nodeId, user) != null;
|
||||
}
|
||||
|
||||
public Set<NodeMember> getMembers() {
|
||||
return NodeMember.getNodeMembers(nodeId);
|
||||
}
|
||||
|
||||
public Timestamp getLastUpdate() {
|
||||
return lastUpdate;
|
||||
}
|
||||
|
||||
private void updateDB() {
|
||||
this.lastUpdate = Timestamp.from(Instant.now());
|
||||
update.update(nodeName, parentNode, nodeItem, nodeType, nodeRank, config, nodeId);
|
||||
TAB_CACHE.clear();
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
delete.update(nodeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return nodeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof SchematicNode))
|
||||
return false;
|
||||
|
||||
return ((SchematicNode) obj).getId() == nodeId;
|
||||
}
|
||||
|
||||
public String generateBreadcrumbs(SteamwarUser user) {
|
||||
return byIdAndUser(user, nodeId).generateBreadcrumbs();
|
||||
}
|
||||
|
||||
public String generateBreadcrumbs(String split, SteamwarUser user) {
|
||||
return byIdAndUser(user, nodeId).generateBreadcrumbs(split);
|
||||
}
|
||||
|
||||
public String generateBreadcrumbs() {
|
||||
if (brCache == null) {
|
||||
brCache = generateBreadcrumbs("/");
|
||||
}
|
||||
return brCache;
|
||||
}
|
||||
|
||||
public String generateBreadcrumbs(String split) {
|
||||
StringBuilder builder = new StringBuilder(getName());
|
||||
Optional<SchematicNode> currentNode = Optional.of(this);
|
||||
if (currentNode.map(SchematicNode::isDir).orElse(false)) {
|
||||
builder.append(split);
|
||||
}
|
||||
while (currentNode.isPresent()) {
|
||||
currentNode = currentNode
|
||||
.flatMap(schematicNode -> Optional
|
||||
.ofNullable(NodeMember.getNodeMember(schematicNode.getId(), effectiveOwner))
|
||||
.map(NodeMember::getParent).orElse(schematicNode.getOptionalParent()))
|
||||
.map(SchematicNode::getSchematicNode);
|
||||
currentNode.ifPresent(node -> builder.insert(0, split).insert(0, node.getName()));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public List<Map.Entry<String, Integer>> generateBreadcrumbsMap(SteamwarUser user) {
|
||||
List<Map.Entry<String, Integer>> map = new ArrayList<>();
|
||||
Optional<SchematicNode> currentNode = Optional.of(this);
|
||||
if (currentNode.map(SchematicNode::isDir).orElse(false)) {
|
||||
map.add(new AbstractMap.SimpleEntry<>(getName(), getId()));
|
||||
}
|
||||
while (currentNode.isPresent()) {
|
||||
currentNode = currentNode
|
||||
.flatMap(schematicNode -> Optional
|
||||
.ofNullable(NodeMember.getNodeMember(schematicNode.getId(), effectiveOwner))
|
||||
.map(NodeMember::getParent).orElse(schematicNode.getOptionalParent()))
|
||||
.map(SchematicNode::getSchematicNode);
|
||||
currentNode.ifPresent(node -> map.add(0, new AbstractMap.SimpleEntry<>(node.getName(), node.getId())));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static final List<String> FORBIDDEN_NAMES = Collections.unmodifiableList(Arrays.asList("public"));
|
||||
|
||||
public static boolean invalidSchemName(String[] layers) {
|
||||
for (String layer : layers) {
|
||||
if (layer.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (layer.contains("/") ||
|
||||
layer.contains("\\") ||
|
||||
layer.contains("<") ||
|
||||
layer.contains(">") ||
|
||||
layer.contains("^") ||
|
||||
layer.contains("°") ||
|
||||
layer.contains("'") ||
|
||||
layer.contains("\"") ||
|
||||
layer.contains(" ")) {
|
||||
return true;
|
||||
}
|
||||
if (FORBIDDEN_NAMES.contains(layer.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static List<String> getNodeTabcomplete(SteamwarUser user, String s) {
|
||||
boolean sws = s.startsWith("/");
|
||||
if (sws) {
|
||||
s = s.substring(1);
|
||||
}
|
||||
int index = s.lastIndexOf("/");
|
||||
String cacheKey = index == -1 ? "" : s.substring(0, index);
|
||||
if (TAB_CACHE.containsKey(user.getId()) && TAB_CACHE.get(user.getId()).containsKey(cacheKey)) {
|
||||
return new ArrayList<>(TAB_CACHE.get(user.getId()).get(cacheKey));
|
||||
}
|
||||
List<String> list = new ArrayList<>();
|
||||
if (s.contains("/")) {
|
||||
String preTab = s.substring(0, s.lastIndexOf("/") + 1);
|
||||
SchematicNode pa = SchematicNode.getNodeFromPath(user, preTab);
|
||||
if (pa == null)
|
||||
return new ArrayList<>();
|
||||
List<SchematicNode> nodes = SchematicNode.list(user, pa.getId());
|
||||
String br = pa.generateBreadcrumbs();
|
||||
nodes.forEach(node -> list.add((sws ? "/" : "") + br + node.getName() + (node.isDir() ? "/" : "")));
|
||||
} else {
|
||||
List<SchematicNode> nodes = SchematicNode.list(user, null);
|
||||
nodes.forEach(node -> list.add((sws ? "/" : "") + node.getName() + (node.isDir() ? "/" : "")));
|
||||
}
|
||||
list.remove("//copy");
|
||||
TAB_CACHE.computeIfAbsent(user.getId(), integer -> new HashMap<>()).putIfAbsent(cacheKey, list);
|
||||
return list;
|
||||
}
|
||||
|
||||
public static enum ConfigFlags {
|
||||
REPLACE_COLOR,
|
||||
ALLOW_REPLAY,
|
||||
IS_PREPARED
|
||||
}
|
||||
}
|
||||
436
CommonCore/SQL/src/de/steamwar/sql/SchematicNode.kt
Normal file
436
CommonCore/SQL/src/de/steamwar/sql/SchematicNode.kt
Normal file
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql
|
||||
|
||||
import de.steamwar.sql.internal.fromSql
|
||||
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.CurrentTimestamp
|
||||
import org.jetbrains.exposed.v1.javatime.timestamp
|
||||
import org.jetbrains.exposed.v1.jdbc.insertAndGetId
|
||||
import java.sql.Timestamp
|
||||
import java.util.*
|
||||
import java.util.function.Consumer
|
||||
|
||||
object SchematicNodeTable : IntIdTable("SchematicNode", "NodeId") {
|
||||
val owner = reference("NodeOwner", SteamwarUserTable)
|
||||
val name = varchar("NodeName", 64)
|
||||
val parent = optReference("ParentNode", SchematicNodeTable)
|
||||
val lastUpdate = timestamp("LastUpdate").defaultExpression(CurrentTimestamp)
|
||||
val item = text("NodeItem")
|
||||
val type = varchar("NodeType", 16).nullable()
|
||||
val config = integer("Config")
|
||||
}
|
||||
|
||||
class SchematicNode(id: EntityID<Int>) : IntEntity(id) {
|
||||
companion object : IntEntityClass<SchematicNode>(SchematicNodeTable) {
|
||||
private val fieldIndex: Map<Expression<*>, Int> =
|
||||
SchematicNodeTable.columns.mapIndexed { index, column -> column to index }.toMap()
|
||||
|
||||
private val FORBIDDEN_NAMES = listOf("public")
|
||||
private val FORBIDDEN_CHARS = listOf('/', '\\', '<', '>', '^', '°', '\'', '"', ' ')
|
||||
|
||||
val tabCache = mutableMapOf<Int, MutableMap<String, List<String>>>()
|
||||
|
||||
@JvmStatic
|
||||
fun clear() = tabCache.clear()
|
||||
|
||||
private fun List<SchematicNode>.mapToIds(): Map<Int, SchematicNode> = this.associateBy { it.nodeId }
|
||||
|
||||
@JvmStatic
|
||||
fun getAll(user: SteamwarUser) = fromSql(
|
||||
"WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.* FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId",
|
||||
listOf(
|
||||
IntegerColumnType() to user.getId(),
|
||||
IntegerColumnType() to user.getId()
|
||||
),
|
||||
fieldIndex
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
fun getAllMap(user: SteamwarUser) = getAll(user).mapToIds()
|
||||
|
||||
@JvmStatic
|
||||
fun list(user: SteamwarUser, schematicId: Int?) = fromSql(
|
||||
"SELECT SchematicNode.NodeId, NodeOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId <=> ? AND NM.UserId = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode WHERE (? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?) ORDER BY NodeName",
|
||||
listOf(
|
||||
IntegerColumnType() to schematicId,
|
||||
IntegerColumnType() to user.getId(),
|
||||
IntegerColumnType() to schematicId,
|
||||
IntegerColumnType() to user.getId(),
|
||||
IntegerColumnType() to schematicId,
|
||||
IntegerColumnType() to schematicId,
|
||||
), fieldIndex
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
fun byParentName(user: SteamwarUser, schematicId: Int?, name: String) = fromSql(
|
||||
"SELECT SchematicNode.NodeId, NodeOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId <=> ? AND NM.UserId = ? AND SchematicNode.NodeName = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode WHERE ((? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?)) AND NodeName = ?",
|
||||
listOf(
|
||||
IntegerColumnType() to schematicId,
|
||||
IntegerColumnType() to user.getId(),
|
||||
VarCharColumnType() to name,
|
||||
IntegerColumnType() to schematicId,
|
||||
IntegerColumnType() to user.getId(),
|
||||
IntegerColumnType() to schematicId,
|
||||
IntegerColumnType() to schematicId,
|
||||
VarCharColumnType() to name,
|
||||
), fieldIndex
|
||||
).firstOrNull()
|
||||
|
||||
@JvmStatic
|
||||
fun accessibleByUserType(user: SteamwarUser, type: SchematicType) = fromSql(
|
||||
"WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeType = ?",
|
||||
listOf(
|
||||
IntegerColumnType() to user.getId(),
|
||||
IntegerColumnType() to user.getId(),
|
||||
IntegerColumnType() to user.getId(),
|
||||
VarCharColumnType() to type.toDB(),
|
||||
), fieldIndex
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
fun accessibleByUserTypeMap(user: SteamwarUser, type: SchematicType) =
|
||||
accessibleByUserType(user, type).mapToIds()
|
||||
|
||||
@JvmStatic
|
||||
fun schematicAccessibleForUser(user: SteamwarUser, schematicId: Int?) = fromSql(
|
||||
"WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeId = ?",
|
||||
listOf(
|
||||
IntegerColumnType() to user.getId(),
|
||||
IntegerColumnType() to user.getId(),
|
||||
IntegerColumnType() to user.getId(),
|
||||
IntegerColumnType() to schematicId,
|
||||
),
|
||||
fieldIndex
|
||||
).isNotEmpty()
|
||||
|
||||
@JvmStatic
|
||||
fun accessibleByUserTypeParent(user: SteamwarUser, type: SchematicType, parentId: Int?) = fromSql(
|
||||
"WITH RECURSIVE RSASN AS(WITH RECURSIVE RSAN AS (WITH RSANH AS (WITH RECURSIVE RSA AS (SELECT SN.NodeId, NM.ParentId FROM SchematicNode SN LEFT JOIN NodeMember NM on SN.NodeId = NM.NodeId WHERE NM.UserId = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN INNER JOIN RSA ON RSA.NodeId = SN.ParentNode) SELECT * FROM RSA UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?) SELECT * FROM RSANH UNION SELECT SN.NodeId, SN.ParentNode FROM RSANH JOIN SchematicNode SN ON SN.ParentNode = RSANH.NodeId) SELECT RSAN.NodeId, RSAN.ParentId FROM RSAN JOIN SchematicNode SN ON SN.NodeId = RSAN.NodeId WHERE NodeType = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN JOIN RSASN ON SN.NodeId = RSASN.ParentId) SELECT SN.*, ? as EffectiveOwner, RSASN.ParentId AS ParentNode FROM RSASN JOIN SchematicNode SN ON SN.NodeId = RSASN.NodeId WHERE RSASN.ParentId <=> ? ORDER BY NodeName",
|
||||
listOf(
|
||||
IntegerColumnType() to user.getId(),
|
||||
IntegerColumnType() to user.getId(),
|
||||
VarCharColumnType() to type.toDB(),
|
||||
IntegerColumnType() to user.getId(),
|
||||
IntegerColumnType() to parentId,
|
||||
), fieldIndex
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Deprecated("Use byId")
|
||||
fun byIdAndUser(ignored: SteamwarUser, id: Int) = useDb {
|
||||
findById(id)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun parentsOfNode(user: SteamwarUser, id: Int) = fromSql(
|
||||
"WITH RECURSIVE R AS (SELECT NodeId, ParentNode FROM EffectiveSchematicNode WHERE NodeId = ? UNION SELECT E.NodeId, E.ParentNode FROM R, EffectiveSchematicNode E WHERE R.ParentNode = E.NodeId AND E.EffectiveOwner = ?) SELECT SN.NodeId, SN.NodeOwner, SN.NodeName, R.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.Config FROM R INNER JOIN SchematicNode SN ON SN.NodeId = R.NodeId",
|
||||
listOf(
|
||||
IntegerColumnType() to id,
|
||||
IntegerColumnType() to user.getId(),
|
||||
IntegerColumnType() to user.getId(),
|
||||
), fieldIndex
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
fun createSchematic(owner: Int, name: String, parent: Int?) = createSchematicNode(
|
||||
owner, name, parent,
|
||||
SchematicType.Normal.toDB(), ""
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
fun createSchematicDirectory(owner: Int, name: String, parent: Int?) =
|
||||
createSchematicNode(owner, name, parent, null, "")
|
||||
|
||||
@JvmStatic
|
||||
fun createSchematicNode(owner: Int, name: String, parent: Int?, type: String?, item: String) = useDb {
|
||||
val id = SchematicNodeTable.insertAndGetId {
|
||||
it[this.owner] = EntityID(owner, SteamwarUserTable)
|
||||
it[this.name] = name
|
||||
it[this.parent] =
|
||||
parent?.let { p -> if (p == 0) null else p }?.let { p -> EntityID(p, SchematicNodeTable) }
|
||||
it[this.item] = item
|
||||
it[this.type] = type
|
||||
}
|
||||
return@useDb findById(id) ?: throw IllegalStateException("SchematicNode $id not found")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun byId(id: Int) = useDb { findById(id) }
|
||||
|
||||
@JvmStatic
|
||||
fun getSchematicNode(owner: Int, name: String, parent: Int?) = useDb {
|
||||
find { (SchematicNodeTable.owner eq owner) and (SchematicNodeTable.name eq name) and (SchematicNodeTable.parent eq parent) }.firstOrNull()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getSchematicNode(owner: Int, name: String, parent: SchematicNode) =
|
||||
getSchematicNode(owner, name, parent.nodeId)
|
||||
|
||||
@JvmStatic
|
||||
fun getSchematicNodeInNode(parent: Int?) = useDb {
|
||||
find { (SchematicNodeTable.parent eq parent) }.orderBy(SchematicNodeTable.name to SortOrder.ASC).toList()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getSchematicNodeInNode(parent: SchematicNode) = getSchematicNodeInNode(parent.nodeId)
|
||||
|
||||
@JvmStatic
|
||||
fun getSchematicNode(name: String, parent: Int?) = useDb {
|
||||
find { (SchematicNodeTable.name eq name) and (SchematicNodeTable.parent eq parent) }.firstOrNull()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getSchematicNode(id: Int) = byId(id)
|
||||
|
||||
@JvmStatic
|
||||
fun getAllAccessibleSchematicsOfType(user: Int, type: String) =
|
||||
accessibleByUserType(SteamwarUser.byId(user)!!, SchematicType.fromDB(type)!!)
|
||||
|
||||
@JvmStatic
|
||||
fun getAllSchematicsAccessibleByUser(user: Int) = getAll(SteamwarUser.byId(user)!!)
|
||||
|
||||
@JvmStatic
|
||||
fun getAllSchematicsOfType(owner: Int, type: String) = useDb {
|
||||
find { (SchematicNodeTable.owner eq owner) and (SchematicNodeTable.type eq type) }.orderBy(
|
||||
SchematicNodeTable.name to SortOrder.ASC
|
||||
).toList()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getAllSchematicsOfType(type: SchematicType) = useDb {
|
||||
find { (SchematicNodeTable.type eq type.toDB()) }.orderBy(SchematicNodeTable.name to SortOrder.ASC).toList()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deepGet(parent: Int?, filter: (node: SchematicNode) -> Boolean): List<SchematicNode> =
|
||||
getSchematicNodeInNode(parent)
|
||||
.flatMap {
|
||||
return@flatMap if (it.isDir()) {
|
||||
deepGet(it.nodeId, filter)
|
||||
} else {
|
||||
if (filter(it)) listOf(it) else listOf()
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getNodeFromPath(user: SteamwarUser, path: String): SchematicNode? {
|
||||
var s = path
|
||||
if (s.startsWith("/")) {
|
||||
s = s.drop(1)
|
||||
}
|
||||
if (s.endsWith("/")) {
|
||||
s = s.dropLast(1)
|
||||
}
|
||||
if (s.isEmpty()) return null
|
||||
if (s.contains("/")) {
|
||||
val layers: Array<String?> = s.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
var currentNode = byParentName(user, null, layers[0]!!)
|
||||
for (i in 1..<layers.size) {
|
||||
val node = currentNode?.let { n -> byParentName(user, n.getId(), layers[i]!!) }
|
||||
if (node == null) {
|
||||
return null
|
||||
} else {
|
||||
currentNode = node
|
||||
if (!currentNode.isDir() && i != layers.size - 1
|
||||
) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
return currentNode
|
||||
} else {
|
||||
return byParentName(user, null, s)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun invalidSchemName(layers: Array<String>) = layers.any {
|
||||
it.isEmpty() || FORBIDDEN_CHARS.any { c -> c in it } || FORBIDDEN_NAMES.any { n -> n == it.lowercase() }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getNodeTabcomplete(user: SteamwarUser, s: String): List<String> {
|
||||
var s = s
|
||||
val sws = s.startsWith("/")
|
||||
if (sws) {
|
||||
s = s.substring(1)
|
||||
}
|
||||
val index = s.lastIndexOf("/")
|
||||
val cacheKey = if (index == -1) "" else s.take(index)
|
||||
tabCache[user.getId()]?.get(cacheKey)?.also { return it }
|
||||
|
||||
val list = mutableListOf<String>()
|
||||
if (s.contains("/")) {
|
||||
val preTab = s.take(s.lastIndexOf("/") + 1)
|
||||
val pa = getNodeFromPath(user, preTab) ?: return emptyList()
|
||||
val nodes: List<SchematicNode> = list(user, pa.getId())
|
||||
val br = pa.generateBreadcrumbs(user)
|
||||
nodes.forEach(Consumer { node: SchematicNode? -> list.add((if (sws) "/" else "") + br + node!!.name + (if (node.isDir()) "/" else "")) })
|
||||
} else {
|
||||
val nodes: List<SchematicNode?> = list(user, null)
|
||||
nodes.forEach(Consumer { node: SchematicNode? -> list.add((if (sws) "/" else "") + node!!.name + (if (node.isDir()) "/" else "")) })
|
||||
}
|
||||
list.remove("//copy")
|
||||
tabCache.computeIfAbsent(user.getId()) { i -> mutableMapOf() }.putIfAbsent(cacheKey, list)
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
val nodeId by SchematicNodeTable.id.transform({ EntityID(it, SchematicNodeTable) }, { it.value })
|
||||
val nodeOwner by SchematicNodeTable.owner
|
||||
val owner: Int get() = nodeOwner.value
|
||||
private var nodeName by SchematicNodeTable.name
|
||||
var name: String
|
||||
get() = nodeName
|
||||
set(value) = useDb {
|
||||
nodeName = value
|
||||
}
|
||||
private var parentNodeId by SchematicNodeTable.parent
|
||||
var parent: Int?
|
||||
get() = parentNodeId?.value
|
||||
set(value) = useDb {
|
||||
parentNodeId = value?.let { EntityID(it, SchematicNodeTable) }
|
||||
}
|
||||
val parentNode: SchematicNode?
|
||||
get() = parent?.let { findById(it) }
|
||||
|
||||
val optionalParent: Optional<Int> get() = Optional.ofNullable(parent)
|
||||
var lastUpdate by SchematicNodeTable.lastUpdate.transform({ it.toInstant() }, { Timestamp.from(it) })
|
||||
private var nodeItem by SchematicNodeTable.item
|
||||
var item: String
|
||||
get() = nodeItem.ifEmpty {
|
||||
if (isDir()) "CHEST" else "CAULDRON_ITEM"
|
||||
}
|
||||
set(value) = useDb {
|
||||
nodeItem = value
|
||||
}
|
||||
private var nodeType by SchematicNodeTable.type
|
||||
var schemtype: SchematicType
|
||||
get() = checkDir { SchematicType.fromDB(nodeType!!)!! }
|
||||
set(value) = checkDir { useDb { nodeType = value.toDB() } }
|
||||
var config by SchematicNodeTable.config
|
||||
|
||||
val members: Set<NodeMember> by lazy { NodeMember.getNodeMembers(nodeId) }
|
||||
private lateinit var breadcrumbs: String
|
||||
|
||||
fun getFileEnding(): String = checkDir { NodeData.getLatest(this)!!.nodeFormat.fileEnding }
|
||||
fun getId() = nodeId
|
||||
fun isDir() = nodeType == null
|
||||
|
||||
private fun <T> checkDir(block: () -> T): T {
|
||||
if (isDir()) {
|
||||
throw IllegalStateException("Node is a directory")
|
||||
}
|
||||
|
||||
return block()
|
||||
}
|
||||
|
||||
fun replaceColor() = getConfig(ConfigFlags.REPLACE_COLOR)
|
||||
fun setReplaceColor(value: Boolean) = setConfig(ConfigFlags.REPLACE_COLOR, value)
|
||||
|
||||
fun allowReplay() = getConfig(ConfigFlags.ALLOW_REPLAY)
|
||||
fun setAllowReplay(value: Boolean) = setConfig(ConfigFlags.ALLOW_REPLAY, value)
|
||||
|
||||
fun isPrepared() = getConfig(ConfigFlags.IS_PREPARED)
|
||||
fun setPrepared(value: Boolean) = setConfig(ConfigFlags.IS_PREPARED, value)
|
||||
|
||||
fun getConfig(flag: ConfigFlags) = config and (1 shl flag.ordinal) != 0
|
||||
fun setConfig(flag: ConfigFlags, value: Boolean) = useDb {
|
||||
config = if (value) {
|
||||
config or (1 shl flag.ordinal)
|
||||
} else {
|
||||
config and (1 shl flag.ordinal).inv()
|
||||
}
|
||||
}
|
||||
|
||||
fun getElo(season: Int) = SchemElo.getElo(this, season)
|
||||
|
||||
override fun delete() = useDb {
|
||||
super.delete()
|
||||
}
|
||||
|
||||
override fun hashCode() = nodeId
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is SchematicNode) return false
|
||||
return nodeId == other.nodeId
|
||||
}
|
||||
|
||||
fun generateBreadcrumbs(user: SteamwarUser): String {
|
||||
if (!this::breadcrumbs.isInitialized) {
|
||||
breadcrumbs = generateBreadcrumbs("/", user)
|
||||
}
|
||||
return breadcrumbs
|
||||
}
|
||||
|
||||
fun generateBreadcrumbs(split: String, user: SteamwarUser): String = useDb {
|
||||
val builder: StringBuilder = StringBuilder(name)
|
||||
if (isDir()) {
|
||||
builder.append(split)
|
||||
}
|
||||
var currentNode: SchematicNode? = this@SchematicNode
|
||||
while (currentNode != null) {
|
||||
currentNode = currentNode
|
||||
.let {
|
||||
NodeMember.getNodeMember(it.nodeId, user.getId())
|
||||
?.parent?.orElse(null) ?: it.parent
|
||||
}
|
||||
?.let { findById(it) }
|
||||
?.also {
|
||||
builder.insert(0, split).insert(0, it.name)
|
||||
}
|
||||
}
|
||||
return@useDb builder.toString()
|
||||
}
|
||||
|
||||
fun generateBreadcrumbsMap(user: SteamwarUser): List<Pair<String, Int>> = useDb {
|
||||
val map = mutableListOf<Pair<String, Int>>()
|
||||
var currentNode: SchematicNode? = this@SchematicNode
|
||||
while (currentNode != null) {
|
||||
currentNode = currentNode
|
||||
.also {
|
||||
map.add(0, Pair(it.name, it.nodeId))
|
||||
}
|
||||
.let {
|
||||
NodeMember.getNodeMember(it.nodeId, user.getId())
|
||||
?.parent?.orElse(null) ?: it.parent
|
||||
}
|
||||
?.let { findById(it) }
|
||||
}
|
||||
return@useDb map
|
||||
}
|
||||
|
||||
fun accessibleByUser(user: SteamwarUser) = schematicAccessibleForUser(user, nodeId)
|
||||
|
||||
enum class ConfigFlags {
|
||||
REPLACE_COLOR,
|
||||
ALLOW_REPLAY,
|
||||
IS_PREPARED
|
||||
}
|
||||
|
||||
@Deprecated("Removed")
|
||||
var rank = 0
|
||||
}
|
||||
@@ -1,143 +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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.SqlTypeMapper;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class SchematicType {
|
||||
|
||||
public static final SchematicType Normal = new SchematicType("Normal", "", Type.NORMAL, null, "STONE_BUTTON", false);
|
||||
|
||||
private static final Map<String, SchematicType> fromDB;
|
||||
private static final List<SchematicType> types;
|
||||
|
||||
static {
|
||||
List<SchematicType> tmpTypes = new LinkedList<>();
|
||||
Map<String, SchematicType> tmpFromDB = new HashMap<>();
|
||||
|
||||
tmpTypes.add(Normal);
|
||||
tmpFromDB.put(Normal.name().toLowerCase(), Normal);
|
||||
|
||||
File folder = SQLWrapper.impl.getSchemTypesFolder();
|
||||
if (folder.exists()) {
|
||||
for (File configFile : Arrays.stream(folder.listFiles((file, name) -> name.endsWith(".yml") && !name.endsWith(".kits.yml"))).sorted().collect(Collectors.toList())) {
|
||||
GameModeConfig<?, String> gameModeConfig = SQLWrapper.impl.loadGameModeConfig(configFile);
|
||||
if (gameModeConfig.Schematic.Type == null) continue;
|
||||
if (tmpFromDB.containsKey(gameModeConfig.Schematic.Type.toDB())) continue;
|
||||
SchematicType current = gameModeConfig.Schematic.Type;
|
||||
if (!gameModeConfig.CheckQuestions.isEmpty()) {
|
||||
SchematicType checkType = current.checkType;
|
||||
tmpTypes.add(checkType);
|
||||
tmpFromDB.put(checkType.toDB(), checkType);
|
||||
}
|
||||
tmpTypes.add(current);
|
||||
tmpFromDB.put(current.toDB(), current);
|
||||
SQLWrapper.impl.processSchematicType(gameModeConfig);
|
||||
}
|
||||
}
|
||||
|
||||
fromDB = Collections.unmodifiableMap(tmpFromDB);
|
||||
types = Collections.unmodifiableList(tmpTypes);
|
||||
}
|
||||
|
||||
static {
|
||||
new SqlTypeMapper<>(SchematicType.class, "VARCHAR(16)", (rs, identifier) -> {
|
||||
String t = rs.getString(identifier);
|
||||
return t != null ? fromDB.get(t) : null;
|
||||
}, (st, index, value) -> st.setString(index, value.toDB()));
|
||||
}
|
||||
|
||||
private final String name;
|
||||
@Getter
|
||||
private final String kuerzel;
|
||||
private final Type type;
|
||||
private final SchematicType checkType;
|
||||
@Getter
|
||||
private final String material;
|
||||
@Getter
|
||||
private final Date deadline;
|
||||
@Getter
|
||||
private final boolean manualCheck;
|
||||
|
||||
SchematicType(String name, String kuerzel, Type type, SchematicType checkType, String material, boolean manualCheck){
|
||||
this(name, kuerzel, type, checkType, material, null, manualCheck);
|
||||
}
|
||||
|
||||
SchematicType(String name, String kuerzel, Type type, SchematicType checkType, String material, Date deadline, boolean manualCheck){
|
||||
this.name = name;
|
||||
this.kuerzel = kuerzel;
|
||||
this.type = type;
|
||||
this.checkType = checkType;
|
||||
this.material = material;
|
||||
this.deadline = deadline;
|
||||
this.manualCheck = manualCheck;
|
||||
}
|
||||
|
||||
public boolean isAssignable(){
|
||||
return type == Type.NORMAL || (type == Type.FIGHT_TYPE && checkType != null) || !manualCheck;
|
||||
}
|
||||
|
||||
public SchematicType checkType(){
|
||||
if (!manualCheck) {
|
||||
return this;
|
||||
}
|
||||
return checkType;
|
||||
}
|
||||
|
||||
public boolean check(){
|
||||
return type == Type.CHECK_TYPE;
|
||||
}
|
||||
|
||||
public boolean fightType(){
|
||||
return type == Type.FIGHT_TYPE;
|
||||
}
|
||||
|
||||
public boolean writeable(){
|
||||
return type == Type.NORMAL;
|
||||
}
|
||||
|
||||
public String name(){
|
||||
return name;
|
||||
}
|
||||
|
||||
public String toDB(){
|
||||
return name.toLowerCase();
|
||||
}
|
||||
|
||||
public static SchematicType fromDB(String input) {
|
||||
if (fromDB == null) return null;
|
||||
return fromDB.get(input.toLowerCase());
|
||||
}
|
||||
|
||||
public static List<SchematicType> values(){
|
||||
return types;
|
||||
}
|
||||
|
||||
enum Type{
|
||||
NORMAL,
|
||||
CHECK_TYPE,
|
||||
FIGHT_TYPE
|
||||
}
|
||||
}
|
||||
108
CommonCore/SQL/src/de/steamwar/sql/SchematicType.kt
Normal file
108
CommonCore/SQL/src/de/steamwar/sql/SchematicType.kt
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql
|
||||
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.Locale
|
||||
import java.util.Locale.getDefault
|
||||
import java.util.stream.Collectors
|
||||
|
||||
data class SchematicType(
|
||||
val name: String,
|
||||
val kuerzel: String,
|
||||
val type: Type,
|
||||
val checkType: SchematicType?,
|
||||
val material: String,
|
||||
val deadline: Date?,
|
||||
val manualCheck: Boolean,
|
||||
) {
|
||||
constructor(
|
||||
name: String,
|
||||
kuerzel: String,
|
||||
type: Type,
|
||||
checkType: SchematicType?,
|
||||
material: String,
|
||||
manualCheck: Boolean
|
||||
) : this(name, kuerzel, type, checkType, material, null, manualCheck)
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val Normal = SchematicType("Normal", "", Type.NORMAL, null, "STONE_BUTTON", false)
|
||||
|
||||
private val types: List<SchematicType>
|
||||
private val fromDB: Map<String, SchematicType>?
|
||||
|
||||
init {
|
||||
val tmpTypes = mutableListOf<SchematicType>()
|
||||
val tmpFromDB = mutableMapOf<String, SchematicType>()
|
||||
|
||||
tmpTypes.add(Normal)
|
||||
tmpFromDB[Normal.toDB()] = Normal
|
||||
|
||||
val folder = SQLWrapper.impl.schemTypesFolder
|
||||
if (folder.exists()) {
|
||||
for (configFile in Arrays.stream<File?>(folder.listFiles { _, name ->
|
||||
name.endsWith(
|
||||
".yml"
|
||||
) && !name.endsWith(".kits.yml")
|
||||
}).sorted().collect(Collectors.toList())) {
|
||||
val gameModeConfig = SQLWrapper.impl.loadGameModeConfig(configFile)
|
||||
if (gameModeConfig.Schematic.Type == null) continue
|
||||
if (tmpFromDB.containsKey(gameModeConfig.Schematic.Type.toDB())) continue
|
||||
val current = gameModeConfig.Schematic.Type
|
||||
if (gameModeConfig.CheckQuestions.isNotEmpty()) {
|
||||
val checkType = current.checkType
|
||||
tmpTypes.add(checkType!!)
|
||||
tmpFromDB[checkType.toDB()] = checkType
|
||||
}
|
||||
tmpTypes.add(current)
|
||||
tmpFromDB[current.toDB()] = current
|
||||
SQLWrapper.impl.processSchematicType(gameModeConfig)
|
||||
}
|
||||
}
|
||||
|
||||
types = tmpTypes.toList()
|
||||
fromDB = tmpFromDB.toMap()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun values() = types
|
||||
|
||||
@JvmStatic
|
||||
fun fromDB(value: String) = fromDB?.let { it[value.lowercase()] }
|
||||
}
|
||||
|
||||
fun name() = name
|
||||
fun toDB() = name.lowercase()
|
||||
|
||||
fun check() = type == Type.CHECK_TYPE
|
||||
fun fightType() = type == Type.FIGHT_TYPE
|
||||
fun writeable() = type == Type.NORMAL
|
||||
|
||||
fun checkType() = if (manualCheck) checkType else this
|
||||
fun isAssignable() = type == Type.NORMAL || (type == Type.FIGHT_TYPE && checkType != null) || !manualCheck
|
||||
|
||||
enum class Type {
|
||||
NORMAL,
|
||||
CHECK_TYPE,
|
||||
FIGHT_TYPE
|
||||
}
|
||||
}
|
||||
@@ -1,84 +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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.Field;
|
||||
import de.steamwar.sql.internal.SelectStatement;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.sql.internal.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public class Script {
|
||||
|
||||
private static final Table<Script> table = new Table<>(Script.class);
|
||||
|
||||
private static final SelectStatement<Script> byId = table.select(Table.PRIMARY);
|
||||
private static final SelectStatement<Script> byUserName = table.select("nameUser");
|
||||
private static final SelectStatement<Script> byUser = table.selectFields("userId");
|
||||
|
||||
private static final Statement insert = table.insertFields(true, "userId", "name", "code");
|
||||
private static final Statement updateName = table.update(Table.PRIMARY, "name");
|
||||
private static final Statement updateCode = table.update(Table.PRIMARY, "code");
|
||||
private static final Statement delete = table.delete(Table.PRIMARY);
|
||||
|
||||
public static Script get(int id) {
|
||||
return byId.select(id);
|
||||
}
|
||||
|
||||
public static Script get(SteamwarUser user, String name) {
|
||||
return byUserName.select(user, name);
|
||||
}
|
||||
|
||||
public static Script create(SteamwarUser user, String name, String code) {
|
||||
return new Script(insert.insertGetKey(user, name, code), user.getId(), name, code);
|
||||
}
|
||||
|
||||
public static List<Script> list(SteamwarUser user) {
|
||||
return byUser.listSelect(user);
|
||||
}
|
||||
|
||||
@Field(keys = Table.PRIMARY, autoincrement = true)
|
||||
private final int id;
|
||||
@Field(keys = "nameUser")
|
||||
private final int userId;
|
||||
@Field(keys = "nameUser")
|
||||
private String name;
|
||||
@Field
|
||||
private String code;
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
updateName.update(name, id);
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
updateCode.update(code, id);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
delete.update(id);
|
||||
}
|
||||
}
|
||||
75
CommonCore/SQL/src/de/steamwar/sql/Script.kt
Normal file
75
CommonCore/SQL/src/de/steamwar/sql/Script.kt
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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
|
||||
|
||||
object ScriptTable: IntIdTable("Script") {
|
||||
val userId = reference("UserId", SteamwarUserTable)
|
||||
val name = varchar("Name", 64)
|
||||
val code = text("Code")
|
||||
}
|
||||
|
||||
class Script(id: EntityID<Int>) : IntEntity(id) {
|
||||
companion object : IntEntityClass<Script>(ScriptTable) {
|
||||
@JvmStatic
|
||||
fun byId(id: Int) = useDb { findById(id) }
|
||||
|
||||
@JvmStatic
|
||||
fun get(user: SteamwarUser, name: String) = useDb {
|
||||
find { ScriptTable.userId eq user.id and (ScriptTable.name eq name) }.firstOrNull()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun create(user: SteamwarUser, name: String, code: String) = useDb {
|
||||
new {
|
||||
this.userId = user.id.value
|
||||
this.scriptName = name
|
||||
this.scriptCode = code
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun list(user: SteamwarUser) = useDb {
|
||||
find { ScriptTable.userId eq user.id }.toList()
|
||||
}
|
||||
}
|
||||
|
||||
fun getId() = id.value
|
||||
var userId by ScriptTable.userId.transform({ EntityID(it, SteamwarUserTable) }, { it.value })
|
||||
private var scriptName by ScriptTable.name
|
||||
private var scriptCode by ScriptTable.code
|
||||
|
||||
var name: String
|
||||
get() = scriptName
|
||||
set(value) = useDb { scriptName = value }
|
||||
|
||||
var code: String
|
||||
get() = scriptCode
|
||||
set(value) = useDb { scriptCode = value }
|
||||
|
||||
override fun delete() = useDb { super.delete() }
|
||||
}
|
||||
@@ -46,14 +46,14 @@ public class Season {
|
||||
if (season == -1) return "";
|
||||
int yearSeason = season % 3;
|
||||
int year = (season - yearSeason) / 3;
|
||||
return String.format("%d-%d", year, yearSeason);
|
||||
return String.format("%d-%d", year, yearSeason + 1);
|
||||
}
|
||||
|
||||
public static int convertSeasonToNumber(String season){
|
||||
if (season.isEmpty()) return -1;
|
||||
String[] split = season.split("-");
|
||||
try {
|
||||
return Integer.parseInt(split[0]) * 3 + Integer.parseInt(split[1]);
|
||||
return Integer.parseInt(split[0]) * 3 + Integer.parseInt(split[1]) - 1;
|
||||
} catch (NumberFormatException e) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1,45 +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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.Field;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.sql.internal.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class Session {
|
||||
|
||||
private static final Table<Session> table = new Table<>(Session.class);
|
||||
private static final Statement insert = table.insert(Table.PRIMARY);
|
||||
|
||||
public static void insertSession(int userID, Timestamp startTime){
|
||||
insert.update(userID, startTime);
|
||||
}
|
||||
|
||||
@Field(keys = {Table.PRIMARY})
|
||||
private int userId;
|
||||
@Field(keys = {Table.PRIMARY})
|
||||
private Timestamp startTime;
|
||||
@Field(def = "CURRENT_TIMESTAMP")
|
||||
private Timestamp endTime;
|
||||
}
|
||||
44
CommonCore/SQL/src/de/steamwar/sql/Session.kt
Normal file
44
CommonCore/SQL/src/de/steamwar/sql/Session.kt
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql
|
||||
|
||||
import de.steamwar.sql.internal.useDb
|
||||
import org.jetbrains.exposed.v1.core.Table
|
||||
import org.jetbrains.exposed.v1.core.dao.id.EntityID
|
||||
import org.jetbrains.exposed.v1.javatime.CurrentTimestamp
|
||||
import org.jetbrains.exposed.v1.javatime.timestamp
|
||||
import org.jetbrains.exposed.v1.jdbc.insert
|
||||
import java.sql.Timestamp
|
||||
|
||||
object SessionTable: Table("Session") {
|
||||
val userId = reference("UserId", SteamwarUserTable)
|
||||
val startTime = timestamp("StartTime")
|
||||
val endTime = timestamp("EndTime").defaultExpression(CurrentTimestamp)
|
||||
}
|
||||
|
||||
object Session {
|
||||
@JvmStatic
|
||||
fun insertSession(userId: Int, startTime: Timestamp) = useDb {
|
||||
SessionTable.insert {
|
||||
it[SessionTable.userId] = EntityID(userId, SteamwarUserTable)
|
||||
it[SessionTable.startTime] = startTime.toInstant()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,389 +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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql;
|
||||
|
||||
import de.steamwar.sql.internal.*;
|
||||
import lombok.Getter;
|
||||
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class SteamwarUser {
|
||||
private static final SecureRandom random = new SecureRandom();
|
||||
private static final SecretKeyFactory factory;
|
||||
|
||||
static {
|
||||
try {
|
||||
factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new SecurityException(e);
|
||||
}
|
||||
|
||||
new SqlTypeMapper<>(UUID.class, "CHAR(36)", (rs, identifier) -> UUID.fromString(rs.getString(identifier)), (st, index, value) -> st.setString(index, value.toString()));
|
||||
new SqlTypeMapper<>(Locale.class, "VARCHAR(32)", (rs, identifier) -> {
|
||||
String l = rs.getString(identifier);
|
||||
return l != null ? Locale.forLanguageTag(l) : null;
|
||||
}, (st, index, value) -> st.setString(index, value.toLanguageTag()));
|
||||
new SqlTypeMapper<>(SteamwarUser.class, null, (rs, identifier) -> { throw new SecurityException("SteamwarUser cannot be used as type (recursive select)"); }, (st, index, value) -> st.setInt(index, value.id));
|
||||
}
|
||||
|
||||
private static final Table<SteamwarUser> table = new Table<>(SteamwarUser.class, "UserData");
|
||||
private static final Statement insert = table.insertFields("UUID", "UserName");
|
||||
private static final SelectStatement<SteamwarUser> byID = table.selectFields("id");
|
||||
private static final SelectStatement<SteamwarUser> byUUID = table.selectFields("UUID");
|
||||
private static final SelectStatement<SteamwarUser> byName = table.selectFields("UserName");
|
||||
private static final SelectStatement<SteamwarUser> byDiscord = table.selectFields("DiscordId");
|
||||
private static final SelectStatement<SteamwarUser> byTeam = table.selectFields("Team");
|
||||
private static final SelectStatement<SteamwarUser> getUsersWithPerm = new SelectStatement<>(table, "SELECT S.* FROM UserData S JOIN UserPerm P ON S.id = P.User WHERE P.Perm = ?");
|
||||
private static final SelectStatement<SteamwarUser> getAll = new SelectStatement<SteamwarUser>(table, "SELECT * FROM UserData");
|
||||
|
||||
private static final Statement updateName = table.update(Table.PRIMARY, "UserName");
|
||||
private static final Statement updatePassword = table.update(Table.PRIMARY, "Password");
|
||||
private static final Statement updateLocale = table.update(Table.PRIMARY, "Locale", "ManualLocale");
|
||||
private static final Statement updateTeam = table.update(Table.PRIMARY, "Team");
|
||||
private static final Statement updateLeader = table.update(Table.PRIMARY, "Leader");
|
||||
private static final Statement updateDiscord = table.update(Table.PRIMARY, "DiscordId");
|
||||
|
||||
private static final Statement getPlaytime = new Statement("SELECT SUM(UNIX_TIMESTAMP(EndTime) - UNIX_TIMESTAMP(StartTime)) as Playtime FROM Session WHERE UserID = ?");
|
||||
private static final Statement getFirstjoin = new Statement("SELECT MIN(StartTime) AS FirstJoin FROM Session WHERE UserID = ?");
|
||||
private static final Statement getLastonline = new Statement("SELECT MAX(EndTime) AS LastOnline FROM Session WHERE UserID = ?");
|
||||
|
||||
private static final Map<Integer, SteamwarUser> usersById = new HashMap<>();
|
||||
private static final Map<UUID, SteamwarUser> usersByUUID = new HashMap<>();
|
||||
private static final Map<String, SteamwarUser> usersByName = new HashMap<>();
|
||||
private static final Map<Long, SteamwarUser> usersByDiscord = new HashMap<>();
|
||||
public static void clear() {
|
||||
usersById.clear();
|
||||
usersByName.clear();
|
||||
usersByUUID.clear();
|
||||
usersByDiscord.clear();
|
||||
}
|
||||
|
||||
public static void invalidate(int userId) {
|
||||
SteamwarUser user = usersById.remove(userId);
|
||||
if (user == null)
|
||||
return;
|
||||
usersByName.remove(user.getUserName());
|
||||
usersByUUID.remove(user.getUUID());
|
||||
usersByDiscord.remove(user.getDiscordId());
|
||||
}
|
||||
|
||||
public static SteamwarUser get(String userName){
|
||||
SteamwarUser user = usersByName.get(userName.toLowerCase());
|
||||
if(user != null)
|
||||
return user;
|
||||
return byName.select(userName);
|
||||
}
|
||||
|
||||
public static SteamwarUser get(UUID uuid){
|
||||
SteamwarUser user = usersByUUID.get(uuid);
|
||||
if(user != null)
|
||||
return user;
|
||||
return byUUID.select(uuid);
|
||||
}
|
||||
|
||||
public static SteamwarUser get(int id) {
|
||||
SteamwarUser user = usersById.get(id);
|
||||
if(user != null)
|
||||
return user;
|
||||
return byID.select(id);
|
||||
}
|
||||
|
||||
public static SteamwarUser get(Long discordId) {
|
||||
if(usersByDiscord.containsKey(discordId))
|
||||
return usersByDiscord.get(discordId);
|
||||
return byDiscord.select(discordId);
|
||||
}
|
||||
|
||||
public static SteamwarUser getOrCreate(UUID uuid, String name, Consumer<UUID> newPlayer) {
|
||||
SteamwarUser user = get(uuid);
|
||||
|
||||
if (user != null) {
|
||||
if (!user.userName.equals(name)) {
|
||||
updateName.update(name, user.id);
|
||||
user.userName = name;
|
||||
}
|
||||
|
||||
return user;
|
||||
} else {
|
||||
insert.update(uuid, name);
|
||||
newPlayer.accept(uuid);
|
||||
return get(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<SteamwarUser> getUsersWithPerm(UserPerm userPerm) {
|
||||
return getUsersWithPerm.listSelect(userPerm);
|
||||
}
|
||||
|
||||
public static List<SteamwarUser> getServerTeam() {
|
||||
return Stream.of(getUsersWithPerm(UserPerm.PREFIX_ADMIN),
|
||||
getUsersWithPerm(UserPerm.PREFIX_DEVELOPER),
|
||||
getUsersWithPerm(UserPerm.PREFIX_MODERATOR),
|
||||
getUsersWithPerm(UserPerm.PREFIX_SUPPORTER),
|
||||
getUsersWithPerm(UserPerm.PREFIX_BUILDER)
|
||||
)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<SteamwarUser> getTeam(int teamId) {
|
||||
return byTeam.listSelect(teamId);
|
||||
}
|
||||
|
||||
public static void batchCache(Set<Integer> ids) {
|
||||
ids.removeIf(usersById::containsKey);
|
||||
if(ids.isEmpty())
|
||||
return;
|
||||
|
||||
try (SelectStatement<SteamwarUser> batch = new SelectStatement<>(table, "SELECT * FROM UserData WHERE id IN (" + ids.stream().map(Object::toString).collect(Collectors.joining(", ")) + ")")) {
|
||||
batch.listSelect();
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Field(keys = {Table.PRIMARY}, autoincrement = true)
|
||||
private final int id;
|
||||
@Field(keys = {"uuid"})
|
||||
private final UUID uuid;
|
||||
@Getter
|
||||
@Field
|
||||
private String userName;
|
||||
@Field(nullable = true)
|
||||
private String password;
|
||||
@Getter
|
||||
@Field(def = "0")
|
||||
private int team;
|
||||
@Getter
|
||||
@Field(def = "0")
|
||||
private boolean leader;
|
||||
@Field(nullable = true)
|
||||
private Locale locale;
|
||||
@Field(def = "0")
|
||||
private boolean manualLocale;
|
||||
@Getter
|
||||
@Field(keys = {"discordId"}, nullable = true)
|
||||
private Long discordId;
|
||||
|
||||
private Map<Punishment.PunishmentType, Punishment> punishments = null;
|
||||
private Set<UserPerm> permissions = null;
|
||||
private UserPerm.Prefix prefix = null;
|
||||
|
||||
public SteamwarUser(int id, UUID uuid, String userName, String password, int team, boolean leader, Locale locale, boolean manualLocale, Long discordId) {
|
||||
this.id = id;
|
||||
this.uuid = uuid;
|
||||
this.userName = userName;
|
||||
this.password = password;
|
||||
this.team = team;
|
||||
this.leader = leader;
|
||||
this.locale = locale;
|
||||
this.manualLocale = manualLocale;
|
||||
this.discordId = discordId != null && discordId != 0 ? discordId : null;
|
||||
|
||||
usersById.put(id, this);
|
||||
usersByName.put(userName.toLowerCase(), this);
|
||||
usersByUUID.put(uuid, this);
|
||||
if (this.discordId != null) {
|
||||
usersByDiscord.put(discordId, this);
|
||||
}
|
||||
}
|
||||
|
||||
public UUID getUUID() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
if(locale != null)
|
||||
return locale;
|
||||
return Locale.getDefault();
|
||||
}
|
||||
|
||||
public Punishment getPunishment(Punishment.PunishmentType type) {
|
||||
initPunishments();
|
||||
return punishments.getOrDefault(type, null);
|
||||
}
|
||||
|
||||
public boolean isPunished(Punishment.PunishmentType punishment) {
|
||||
initPunishments();
|
||||
if (!punishments.containsKey(punishment)) {
|
||||
return false;
|
||||
}
|
||||
if (!punishments.get(punishment).isCurrent()) {
|
||||
if (punishment == Punishment.PunishmentType.Ban) {
|
||||
BannedUserIPs.unbanIPs(id);
|
||||
}
|
||||
punishments.remove(punishment);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean hasPerm(UserPerm perm) {
|
||||
initPerms();
|
||||
return permissions.contains(perm);
|
||||
}
|
||||
|
||||
public Set<UserPerm> perms() {
|
||||
initPerms();
|
||||
return permissions;
|
||||
}
|
||||
|
||||
public UserPerm.Prefix prefix() {
|
||||
initPerms();
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public double getOnlinetime() {
|
||||
return getPlaytime.select(rs -> {
|
||||
if (rs.next() && rs.getBigDecimal("Playtime") != null)
|
||||
return rs.getBigDecimal("Playtime").doubleValue();
|
||||
return 0.0;
|
||||
}, id);
|
||||
}
|
||||
|
||||
public Timestamp getFirstjoin() {
|
||||
return getFirstjoin.select(rs -> {
|
||||
if (rs.next())
|
||||
return rs.getTimestamp("FirstJoin");
|
||||
return null;
|
||||
}, id);
|
||||
}
|
||||
|
||||
public Timestamp getLastOnline() {
|
||||
return getLastonline.select(rs -> {
|
||||
if (rs.next())
|
||||
return rs.getTimestamp("LastOnline");
|
||||
return null;
|
||||
}, id);
|
||||
}
|
||||
|
||||
public void punish(Punishment.PunishmentType punishment, Timestamp time, String banReason, int from, boolean perma) {
|
||||
initPunishments();
|
||||
punishments.remove(punishment);
|
||||
punishments.put(punishment, Punishment.createPunishment(id, from, punishment, banReason, time, perma));
|
||||
}
|
||||
|
||||
public void setTeam(int team) {
|
||||
this.team = team;
|
||||
updateTeam.update(team, id);
|
||||
setLeader(false);
|
||||
}
|
||||
|
||||
public void setLeader(boolean leader) {
|
||||
this.leader = leader;
|
||||
updateLeader.update(leader, id);
|
||||
}
|
||||
|
||||
public void setLocale(Locale locale, boolean manualLocale) {
|
||||
if (locale == null || (this.manualLocale && !manualLocale))
|
||||
return;
|
||||
|
||||
this.locale = locale;
|
||||
this.manualLocale = manualLocale;
|
||||
updateLocale.update(locale.toLanguageTag(), manualLocale, id);
|
||||
}
|
||||
|
||||
public void setDiscordId(Long discordId) {
|
||||
usersByDiscord.remove(this.discordId);
|
||||
this.discordId = discordId;
|
||||
updateDiscord.update(discordId, id);
|
||||
if (discordId != null) {
|
||||
usersByDiscord.put(discordId, this);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
try {
|
||||
byte[] salt = new byte[16];
|
||||
random.nextBytes(salt);
|
||||
String saltString = Base64.getEncoder().encodeToString(salt);
|
||||
|
||||
byte[] hash = generateHash(password, salt);
|
||||
String hashString = Base64.getEncoder().encodeToString(hash);
|
||||
this.password = hashString + ":" + saltString;
|
||||
updatePassword.update(this.password, id);
|
||||
} catch (Exception e) {
|
||||
throw new SecurityException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean verifyPassword(String password) {
|
||||
try {
|
||||
if (!hasPassword()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String[] parts = this.password.split(":");
|
||||
if (parts.length != 2) {
|
||||
SQLConfig.impl.getLogger().log(Level.SEVERE ,"Invalid password hash for user {0} ({1})", new Object[]{userName, id});
|
||||
return false;
|
||||
}
|
||||
|
||||
String hashString = parts[0];
|
||||
byte[] realHash = Base64.getDecoder().decode(hashString);
|
||||
String saltString = parts[1];
|
||||
byte[] salt = Base64.getDecoder().decode(saltString);
|
||||
byte[] hash = generateHash(password, salt);
|
||||
return Arrays.equals(realHash, hash);
|
||||
} catch (Exception e) {
|
||||
SQLConfig.impl.getLogger().log(Level.SEVERE, "Error while verifying password for user " + userName + " (" + id + ")", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasPassword() {
|
||||
return this.password != null;
|
||||
}
|
||||
|
||||
private byte[] generateHash(String password, byte[] salt)
|
||||
throws InvalidKeySpecException {
|
||||
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 512);
|
||||
return factory.generateSecret(spec).getEncoded();
|
||||
|
||||
}
|
||||
|
||||
private void initPunishments() {
|
||||
if(punishments != null)
|
||||
return;
|
||||
|
||||
punishments = Punishment.getPunishmentsOfPlayer(id);
|
||||
}
|
||||
|
||||
private void initPerms() {
|
||||
if(permissions != null)
|
||||
return;
|
||||
|
||||
permissions = UserPerm.getPerms(id);
|
||||
prefix = permissions.stream().filter(UserPerm.prefixes::containsKey).findAny().map(UserPerm.prefixes::get).orElse(UserPerm.emptyPrefix);
|
||||
}
|
||||
|
||||
public static List<SteamwarUser> getAll() {
|
||||
return getAll.listSelect();
|
||||
}
|
||||
}
|
||||
289
CommonCore/SQL/src/de/steamwar/sql/SteamwarUser.kt
Normal file
289
CommonCore/SQL/src/de/steamwar/sql/SteamwarUser.kt
Normal file
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.sql
|
||||
|
||||
import de.steamwar.sql.internal.useDb
|
||||
import org.jetbrains.exposed.v1.core.JoinType
|
||||
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.inList
|
||||
import org.jetbrains.exposed.v1.dao.IntEntity
|
||||
import org.jetbrains.exposed.v1.dao.IntEntityClass
|
||||
import org.jetbrains.exposed.v1.jdbc.insert
|
||||
import org.jetbrains.exposed.v1.jdbc.select
|
||||
import java.security.SecureRandom
|
||||
import java.sql.Timestamp
|
||||
import java.util.*
|
||||
import java.util.function.Consumer
|
||||
import javax.crypto.SecretKeyFactory
|
||||
import javax.crypto.spec.PBEKeySpec
|
||||
|
||||
object SteamwarUserTable : IntIdTable("UserData", "id") {
|
||||
val uuid = varchar("UUID", 36)
|
||||
val username = varchar("UserName", 32)
|
||||
val team = reference("Team", TeamTable)
|
||||
val leader = bool("Leader")
|
||||
val locale = varchar("Locale", 16).nullable()
|
||||
val manualLocale = bool("ManualLocale")
|
||||
val bedrock = bool("Bedrock")
|
||||
val password = text("Password").nullable()
|
||||
val discordId = long("DiscordId").nullable()
|
||||
}
|
||||
|
||||
class SteamwarUser(id: EntityID<Int>): IntEntity(id) {
|
||||
companion object: IntEntityClass<SteamwarUser>(SteamwarUserTable) {
|
||||
private val random = SecureRandom()
|
||||
private val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512")
|
||||
|
||||
private val byId = mutableMapOf<Int, SteamwarUser>()
|
||||
private val byUUID = mutableMapOf<UUID, SteamwarUser>()
|
||||
private val byDiscordId = mutableMapOf<Long, SteamwarUser>()
|
||||
private val byUsername = mutableMapOf<String, SteamwarUser>()
|
||||
|
||||
@JvmStatic
|
||||
fun clear() {
|
||||
byId.clear()
|
||||
byUUID.clear()
|
||||
byDiscordId.clear()
|
||||
byUsername.clear()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun invalidate(userId: Int) {
|
||||
val user = byId.remove(userId)
|
||||
if(user != null) {
|
||||
byUUID.remove(user.getUUID())
|
||||
byDiscordId.remove(user.discordId)
|
||||
byUsername.remove(user.userName)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun byId(id: Int) = byId[id] ?: useDb { findById(id)?.also { cache(it) } }
|
||||
|
||||
@JvmStatic
|
||||
fun get(uuid: UUID) = byUUID[uuid] ?: useDb { find { SteamwarUserTable.uuid eq uuid.toString() }.firstOrNull()?.also { cache(it) } }
|
||||
|
||||
@JvmStatic
|
||||
fun get(discordId: Long) = byDiscordId[discordId] ?: useDb { find { SteamwarUserTable.discordId eq discordId }.firstOrNull()?.also { cache(it) } }
|
||||
|
||||
@JvmStatic
|
||||
fun get(username: String) = byUsername[username] ?: useDb { find { SteamwarUserTable.username eq username }.firstOrNull()?.also { cache(it) } }
|
||||
|
||||
private fun cache(user: SteamwarUser) {
|
||||
byId[user.getId()] = user
|
||||
byUUID[user.getUUID()] = user
|
||||
user.discordId?.let { byDiscordId[it] = user }
|
||||
byUsername[user.userName] = user
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getOrCreate(uuid: UUID, name: String, newPlayer: Consumer<UUID>): SteamwarUser {
|
||||
val user = get(uuid)
|
||||
|
||||
return if (user != null) {
|
||||
if (user.userName != name) {
|
||||
useDb {
|
||||
user.userName = name
|
||||
}
|
||||
}
|
||||
|
||||
user
|
||||
} else {
|
||||
useDb {
|
||||
SteamwarUserTable.insert {
|
||||
it[SteamwarUserTable.uuid] = uuid.toString()
|
||||
it[username] = name
|
||||
}
|
||||
}
|
||||
|
||||
newPlayer.accept(uuid)
|
||||
get(uuid) ?: error("User $uuid not found after creation!")
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getUsersWithPerm(perm: UserPerm) = useDb {
|
||||
UserPermTable.join(SteamwarUserTable, JoinType.INNER, UserPermTable.user, SteamwarUserTable.id)
|
||||
.select(SteamwarUserTable.fields).where { UserPermTable.perm eq perm }.map { wrapRow(it) }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getServerTeam() = useDb { listOf(
|
||||
getUsersWithPerm(UserPerm.PREFIX_ADMIN),
|
||||
getUsersWithPerm(UserPerm.PREFIX_DEVELOPER),
|
||||
getUsersWithPerm(UserPerm.PREFIX_MODERATOR),
|
||||
getUsersWithPerm(UserPerm.PREFIX_SUPPORTER),
|
||||
getUsersWithPerm(UserPerm.PREFIX_BUILDER),
|
||||
).flatten() }
|
||||
|
||||
@JvmStatic
|
||||
fun getTeam(teamId: Int) = useDb {
|
||||
find { SteamwarUserTable.team eq teamId }.toList()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun batchCache(ids: MutableSet<Int>) {
|
||||
ids.removeIf(byId::containsKey)
|
||||
if(ids.isEmpty()) return
|
||||
|
||||
useDb {
|
||||
find { SteamwarUserTable.id inList ids }.forEach { cache(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val uuid: UUID by SteamwarUserTable.uuid.transform({ it.toString() }, { UUID.fromString(it) })
|
||||
var userName by SteamwarUserTable.username
|
||||
private var teamInternal by SteamwarUserTable.team
|
||||
var team: Int
|
||||
get() = teamInternal.value
|
||||
set(value) = useDb {
|
||||
teamInternal = EntityID(value, TeamTable)
|
||||
leaderInternal = false
|
||||
}
|
||||
|
||||
private var leaderInternal by SteamwarUserTable.leader
|
||||
var leader: Boolean
|
||||
get() = leaderInternal
|
||||
set(value) = useDb {
|
||||
leaderInternal = value
|
||||
}
|
||||
fun isLeader() = leader
|
||||
|
||||
var locale: Locale by SteamwarUserTable.locale
|
||||
.transform({ it.toLanguageTag() }, { it?.let { Locale.forLanguageTag(it) } ?: Locale.getDefault()})
|
||||
var manualLocale by SteamwarUserTable.manualLocale
|
||||
var bedrock by SteamwarUserTable.bedrock
|
||||
private var passwordInternal by SteamwarUserTable.password
|
||||
var password: String?
|
||||
get() = passwordInternal
|
||||
set(value) {
|
||||
if(value == null) {
|
||||
useDb {
|
||||
passwordInternal = null
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val salt = ByteArray(16)
|
||||
random.nextBytes(salt)
|
||||
val saltString = Base64.getEncoder().encode(salt)
|
||||
|
||||
val hash = generateHash(value, salt)
|
||||
val hashString = Base64.getEncoder().encode(hash)
|
||||
|
||||
useDb {
|
||||
passwordInternal = "$hashString:$saltString"
|
||||
}
|
||||
}
|
||||
|
||||
var discordId by SteamwarUserTable.discordId
|
||||
|
||||
private val punishments by lazy { Punishment.getPunishmentsOfPlayer(id.value) }
|
||||
private val perms by lazy { UserPerm.getPerms(id.value) }
|
||||
private val prefix by lazy { perms.firstOrNull { UserPerm.prefixes.containsKey(it) }?.let { UserPerm.prefixes[it]} ?: UserPerm.emptyPrefix }
|
||||
|
||||
fun getUUID(): UUID = uuid
|
||||
fun getId() = id.value
|
||||
|
||||
fun getPunishment(punishment: Punishment.PunishmentType) = punishments[punishment]
|
||||
fun isPunished(punishment: Punishment.PunishmentType) = getPunishment(punishment)
|
||||
?.let {
|
||||
if (!it.isCurrent()) {
|
||||
if (punishment == Punishment.PunishmentType.Ban) {
|
||||
BannedUserIPs.unbanIPs(id.value)
|
||||
}
|
||||
punishments.remove(punishment)
|
||||
return@let false
|
||||
}
|
||||
|
||||
return@let true
|
||||
} ?: false
|
||||
|
||||
fun hasPerm(perm: UserPerm) = perms.contains(perm)
|
||||
fun perms() = perms
|
||||
fun prefix() = prefix
|
||||
|
||||
fun getOnlinetime() = useDb {
|
||||
exec("SELECT SUM(UNIX_TIMESTAMP(EndTime) - UNIX_TIMESTAMP(StartTime)) as Playtime FROM Session WHERE UserID = ${this@SteamwarUser.id.value}") { rs ->
|
||||
return@exec if (rs.next()) {
|
||||
rs.getBigDecimal("Playtime").toDouble()
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
} ?: 0.0
|
||||
}
|
||||
|
||||
fun getFirstjoin() = useDb {
|
||||
exec("SELECT MIN(StartTime) AS FirstJoin FROM Session WHERE UserID = ${this@SteamwarUser.id.value}") { rs ->
|
||||
return@exec if (rs.next()) {
|
||||
rs.getTimestamp("FirstJoin")
|
||||
} else { null }
|
||||
}
|
||||
}
|
||||
|
||||
fun getLastOnline() = useDb {
|
||||
exec("SELECT MAX(EndTime) AS LastOnline FROM Session WHERE UserID = ${this@SteamwarUser.id.value}") { rs ->
|
||||
return@exec if (rs.next()) {
|
||||
rs.getTimestamp("LastOnline")
|
||||
} else { null }
|
||||
}
|
||||
}
|
||||
|
||||
fun punish(punishment: Punishment.PunishmentType, time: Timestamp, reason: String, from: Int, perma: Boolean) = useDb {
|
||||
punishments.remove(punishment)
|
||||
punishments[punishment] = Punishment.createPunishment(this@SteamwarUser.id.value, from, punishment, reason, time, perma)
|
||||
}
|
||||
|
||||
fun setLocale(locale: Locale?, manualeLocale: Boolean) {
|
||||
if (locale == null || (this.manualLocale && !manualLocale)) return
|
||||
|
||||
useDb {
|
||||
this@SteamwarUser.locale = locale
|
||||
this@SteamwarUser.manualLocale = manualeLocale
|
||||
}
|
||||
}
|
||||
|
||||
fun setDiscordId(discordId: Long) {
|
||||
byDiscordId.remove(this.discordId)
|
||||
useDb {
|
||||
this@SteamwarUser.discordId = discordId
|
||||
}
|
||||
byDiscordId[discordId] = this
|
||||
}
|
||||
|
||||
fun verifyPassword(password: String): Boolean {
|
||||
if (!hasPassword()) return false
|
||||
|
||||
val (hashString, saltString) = this.password!!.split(':')
|
||||
|
||||
val hash = Base64.getDecoder().decode(hashString)
|
||||
val salt = Base64.getDecoder().decode(saltString)
|
||||
|
||||
return hash.contentEquals(generateHash(password, salt))
|
||||
}
|
||||
|
||||
fun hasPassword() = password != null
|
||||
|
||||
fun generateHash(password: String, salt: ByteArray): ByteArray =
|
||||
PBEKeySpec(password.toCharArray(), salt, 65536, 512).let { factory.generateSecret(it).encoded }
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user