forked from SteamWar/SteamWar
Compare commits
23
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09d2ed5384
|
||
|
|
b576c36c2d
|
||
|
|
a089d42d9a
|
||
|
|
0a7a753c48
|
||
|
|
86bfde90b8
|
||
|
|
7c5a927d0f
|
||
|
|
dfb71594b9
|
||
|
|
f535e056c7
|
||
|
|
e67e340707
|
||
|
|
a594a163f7 | ||
|
|
1c0146a02d | ||
|
|
d3fecf763c
|
||
|
|
3944c011b0
|
||
|
|
1f4a77e8b4
|
||
|
|
4d40e52ea6 | ||
|
|
698e411944 | ||
|
|
0fd7aab86c
|
||
|
|
624fe98c47 | ||
|
|
ede7df82f3
|
||
|
|
d0c1413ea6
|
||
|
|
5f7c5f0a18
|
||
|
|
9e9f405e30
|
||
|
|
eb63381b83 |
@@ -151,9 +151,9 @@ class EventFight(id: EntityID<Int>) : IntEntity(id), Comparable<EventFight> {
|
|||||||
val dependents by lazy { useDb { EventRelation.getFightRelations(this@EventFight).toList() } }
|
val dependents by lazy { useDb { EventRelation.getFightRelations(this@EventFight).toList() } }
|
||||||
|
|
||||||
val winner: Team?
|
val winner: Team?
|
||||||
get() = if (ergebnis == 1) Team[teamBlue] else if (ergebnis == 2) Team[teamRed] else null
|
get() = useDb { if (ergebnis == 1) Team[teamBlue] else if (ergebnis == 2) Team[teamRed] else null }
|
||||||
val losser: Team?
|
val losser: Team?
|
||||||
get() = if (ergebnis == 1) Team[teamRed] else if (ergebnis == 2) Team[teamBlue] else null
|
get() = useDb { if (ergebnis == 1) Team[teamRed] else if (ergebnis == 2) Team[teamBlue] else null }
|
||||||
|
|
||||||
fun setGroup(group: Int?) = useDb { groupId = group?.let { EntityID(it, EventGroupTable) } }
|
fun setGroup(group: Int?) = useDb { groupId = group?.let { EntityID(it, EventGroupTable) } }
|
||||||
fun hasFinished() = fight != null || ergebnis != 0
|
fun hasFinished() = fight != null || ergebnis != 0
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ class EventGroup(id: EntityID<Int>) : IntEntity(id) {
|
|||||||
set(value) {
|
set(value) {
|
||||||
groupPointsPerDraw = value
|
groupPointsPerDraw = value
|
||||||
}
|
}
|
||||||
val dependents by lazy { EventRelation.getGroupRelations(this) }
|
val dependents by lazy { EventRelation.getGroupRelations(this).toList() }
|
||||||
val lastFight by lazy { Optional.ofNullable(fights.maxByOrNull { it.startTime }) }
|
val lastFight by lazy { Optional.ofNullable(fights.maxByOrNull { it.startTime }) }
|
||||||
|
|
||||||
fun getId() = id.value
|
fun getId() = id.value
|
||||||
|
|||||||
@@ -117,10 +117,10 @@ class EventRelation(id: EntityID<Int>) : IntEntity(id) {
|
|||||||
fromPlace = place
|
fromPlace = place
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAdvancingTeam(): Team? = when(fromType) {
|
fun getAdvancingTeam(): Team? = useDb { when(fromType) {
|
||||||
FromType.FIGHT -> if (fromPlace == 0) fromFight?.winner else fromFight?.losser
|
FromType.FIGHT -> if (fromPlace == 0) fromFight?.winner else fromFight?.losser
|
||||||
FromType.GROUP -> fromGroup?.calculatePoints()?.toList()?.sortedBy { (_, v) -> v }?.reversed()?.elementAt(fromPlace)?.first
|
FromType.GROUP -> fromGroup?.calculatePoints()?.toList()?.sortedBy { (_, v) -> v }?.reversed()?.elementAt(fromPlace)?.first
|
||||||
}
|
} }
|
||||||
|
|
||||||
fun apply(): Boolean {
|
fun apply(): Boolean {
|
||||||
val team = getAdvancingTeam() ?: return false
|
val team = getAdvancingTeam() ?: return false
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* 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.dao.flushCache
|
||||||
|
import org.jetbrains.exposed.v1.javatime.CurrentTimestamp
|
||||||
|
import org.jetbrains.exposed.v1.javatime.timestamp
|
||||||
|
import org.jetbrains.exposed.v1.jdbc.select
|
||||||
|
import org.jetbrains.exposed.v1.jdbc.upsert
|
||||||
|
|
||||||
|
object LeaderboardTable : CompositeIdTable("Leaderboard") {
|
||||||
|
val userId = reference("UserId", SteamwarUserTable)
|
||||||
|
val name = varchar("LeaderboardName", 64).entityId()
|
||||||
|
val time = long("Time")
|
||||||
|
val updatedAt = timestamp("UpdatedAt").defaultExpression(CurrentTimestamp)
|
||||||
|
val bestTime = bool("BestTime")
|
||||||
|
|
||||||
|
override val primaryKey = PrimaryKey(userId, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
find { (LeaderboardTable.userId eq user.id.value) and (LeaderboardTable.name eq name) }.firstOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getPlayerPlacement(user: SteamwarUser, name: String) = useDb {
|
||||||
|
LeaderboardTable.select(LeaderboardTable.time.count())
|
||||||
|
.where {
|
||||||
|
(LeaderboardTable.name eq name) and (LeaderboardTable.time lessSubQuery LeaderboardTable.select(
|
||||||
|
LeaderboardTable.time
|
||||||
|
).where { (LeaderboardTable.userId eq user.id.value) and (LeaderboardTable.name eq name) })
|
||||||
|
}
|
||||||
|
.firstOrNull()?.get(LeaderboardTable.time.count())?.toInt() ?: Int.MAX_VALUE
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun upsert(userId: Int, name: String, time: Long, bestTime: Boolean) = useDb {
|
||||||
|
LeaderboardTable.upsert(
|
||||||
|
onUpdateExclude = listOf(LeaderboardTable.updatedAt, LeaderboardTable.userId, LeaderboardTable.name)
|
||||||
|
) {
|
||||||
|
it[LeaderboardTable.userId] = userId
|
||||||
|
it[LeaderboardTable.name] = name
|
||||||
|
it[LeaderboardTable.time] = time
|
||||||
|
it[LeaderboardTable.bestTime] = bestTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val user by LeaderboardTable.userId.transform({ EntityID(it, SteamwarUserTable) }, { it.value })
|
||||||
|
val name by LeaderboardTable.name
|
||||||
|
var time by LeaderboardTable.time
|
||||||
|
var updatedAt by LeaderboardTable.updatedAt
|
||||||
|
var bestTime by LeaderboardTable.bestTime
|
||||||
|
}
|
||||||
@@ -55,6 +55,17 @@ class NodeMember(id: EntityID<CompositeID>) : CompositeEntity(id) {
|
|||||||
getNodeMember(node, member) ?: throw IllegalStateException("NodeMember not created")
|
getNodeMember(node, member) ?: throw IllegalStateException("NodeMember not created")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun createNodeMember(node: Int, member: Int, parent: SchematicNode): NodeMember = useDb {
|
||||||
|
if (!parent.isDir()) throw IllegalStateException("Parent must be a directory")
|
||||||
|
NodeMemberTable.insertIgnore {
|
||||||
|
it[this.node] = EntityID(node, SchematicNodeTable)
|
||||||
|
it[this.userId] = EntityID(member, SteamwarUserTable)
|
||||||
|
it[NodeMemberTable.parentNode] = parent.getId()
|
||||||
|
}
|
||||||
|
getNodeMember(node, member) ?: throw IllegalStateException("NodeMember not created")
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun createNodeMember(node: Int, member: SteamwarUser) = createNodeMember(node, member.id.value)
|
fun createNodeMember(node: Int, member: SteamwarUser) = createNodeMember(node, member.id.value)
|
||||||
|
|
||||||
@@ -81,6 +92,7 @@ class NodeMember(id: EntityID<CompositeID>) : CompositeEntity(id) {
|
|||||||
var parent by NodeMemberTable.parentNode.transform(
|
var parent by NodeMemberTable.parentNode.transform(
|
||||||
{ it.map { EntityID(it, SchematicNodeTable) }.getOrNull() },
|
{ it.map { EntityID(it, SchematicNodeTable) }.getOrNull() },
|
||||||
{ Optional.ofNullable(it?.value) })
|
{ Optional.ofNullable(it?.value) })
|
||||||
|
private set
|
||||||
|
|
||||||
fun setParentId(id: Int?) {
|
fun setParentId(id: Int?) {
|
||||||
parent = Optional.ofNullable(id)
|
parent = Optional.ofNullable(id)
|
||||||
|
|||||||
@@ -314,7 +314,7 @@ class SchematicNode(id: EntityID<Int>) : IntEntity(id) {
|
|||||||
parentNodeId = value?.let { EntityID(it, SchematicNodeTable) }
|
parentNodeId = value?.let { EntityID(it, SchematicNodeTable) }
|
||||||
}
|
}
|
||||||
val parentNode: SchematicNode?
|
val parentNode: SchematicNode?
|
||||||
get() = parent?.let { findById(it) }
|
get() = useDb { parent?.let { findById(it) } }
|
||||||
|
|
||||||
val optionalParent: Optional<Int> get() = Optional.ofNullable(parent)
|
val optionalParent: Optional<Int> get() = Optional.ofNullable(parent)
|
||||||
var lastUpdate by SchematicNodeTable.lastUpdate.transform({ it.toInstant() }, { Timestamp.from(it) })
|
var lastUpdate by SchematicNodeTable.lastUpdate.transform({ it.toInstant() }, { Timestamp.from(it) })
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ package de.steamwar.lobby.boatrace;
|
|||||||
import de.steamwar.entity.REntity;
|
import de.steamwar.entity.REntity;
|
||||||
import de.steamwar.entity.REntityServer;
|
import de.steamwar.entity.REntityServer;
|
||||||
import de.steamwar.lobby.LobbySystem;
|
import de.steamwar.lobby.LobbySystem;
|
||||||
import de.steamwar.lobby.util.Leaderboard;
|
import de.steamwar.lobby.util.LeaderboardManager;
|
||||||
import de.steamwar.sql.UserConfig;
|
import de.steamwar.sql.Leaderboard;
|
||||||
|
import de.steamwar.sql.SteamwarUser;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
@@ -43,16 +44,18 @@ import org.bukkit.scheduler.BukkitTask;
|
|||||||
|
|
||||||
import java.util.EventListener;
|
import java.util.EventListener;
|
||||||
|
|
||||||
import static de.steamwar.lobby.util.Leaderboard.renderTime;
|
import static de.steamwar.lobby.util.LeaderboardManager.renderTime;
|
||||||
|
|
||||||
public class BoatRace implements EventListener, Listener {
|
public class BoatRace implements EventListener, Listener {
|
||||||
|
|
||||||
|
private static final String CONFIG_KEY = "lobby@boatrace";
|
||||||
|
|
||||||
private static final double MIN_HEIGHT = 4.3;
|
private static final double MIN_HEIGHT = 4.3;
|
||||||
|
|
||||||
public static final REntityServer boatNpcServer;
|
public static final REntityServer boatNpcServer;
|
||||||
|
|
||||||
private static boolean oneNotStarted = false;
|
private static boolean oneNotStarted = false;
|
||||||
private static final Leaderboard leaderboard;
|
private static final LeaderboardManager leaderboard;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
boatNpcServer = new REntityServer();
|
boatNpcServer = new REntityServer();
|
||||||
@@ -65,7 +68,7 @@ public class BoatRace implements EventListener, Listener {
|
|||||||
new BoatRace(player);
|
new BoatRace(player);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
leaderboard = new Leaderboard(boatNpcServer, "lobby@boatrace", BoatRacePositions.LEADERBOARD, 5);
|
leaderboard = new LeaderboardManager(boatNpcServer, CONFIG_KEY, BoatRacePositions.LEADERBOARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Player player;
|
private final Player player;
|
||||||
@@ -123,12 +126,11 @@ public class BoatRace implements EventListener, Listener {
|
|||||||
HandlerList.unregisterAll(this);
|
HandlerList.unregisterAll(this);
|
||||||
task.cancel();
|
task.cancel();
|
||||||
LobbySystem.getMessage().send("BOAT_RACE_TIME", player, renderTime(time));
|
LobbySystem.getMessage().send("BOAT_RACE_TIME", player, renderTime(time));
|
||||||
String conf = UserConfig.getConfig(player.getUniqueId(), "lobby@boatrace");
|
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
|
||||||
long best = Long.parseLong(conf == null ? String.valueOf(Long.MAX_VALUE) : conf);
|
long best = leaderboard.getPlayerTime(user);
|
||||||
if (time < best) {
|
if (time < best) {
|
||||||
LobbySystem.getMessage().send("BOAT_RACE_NEW_BEST", player);
|
LobbySystem.getMessage().send("BOAT_RACE_NEW_BEST", player);
|
||||||
UserConfig.updatePlayerConfig(player.getUniqueId(), "lobby@boatrace", String.valueOf(time));
|
leaderboard.updateBestTime(user, time);
|
||||||
leaderboard.update();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 1);
|
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 1);
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ package de.steamwar.lobby.jumpandrun;
|
|||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import de.steamwar.lobby.LobbySystem;
|
import de.steamwar.lobby.LobbySystem;
|
||||||
import de.steamwar.lobby.listener.PlayerSpawn;
|
import de.steamwar.lobby.listener.PlayerSpawn;
|
||||||
import de.steamwar.lobby.util.Leaderboard;
|
import de.steamwar.lobby.util.LeaderboardManager;
|
||||||
import de.steamwar.sql.UserConfig;
|
import de.steamwar.sql.SteamwarUser;
|
||||||
import net.md_5.bungee.api.ChatMessageType;
|
import net.md_5.bungee.api.ChatMessageType;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@@ -45,7 +45,7 @@ import java.util.*;
|
|||||||
@Linked
|
@Linked
|
||||||
public class JumpAndRun implements Listener {
|
public class JumpAndRun implements Listener {
|
||||||
|
|
||||||
public static final String JUMP_AND_RUN_CONFIG = "jump_and_run";
|
public static final String JUMP_AND_RUN_CONFIG = "jump_and_run@winter25";
|
||||||
|
|
||||||
private static final String BAR_EMPTY = "||||||||||||||||||||||||||||||";
|
private static final String BAR_EMPTY = "||||||||||||||||||||||||||||||";
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ public class JumpAndRun implements Listener {
|
|||||||
private static final Map<Player, Long> CLICKED = new HashMap<>();
|
private static final Map<Player, Long> CLICKED = new HashMap<>();
|
||||||
private static final Map<Player, Integer> CLICKED_COUNT = new HashMap<>();
|
private static final Map<Player, Integer> CLICKED_COUNT = new HashMap<>();
|
||||||
|
|
||||||
private static final Leaderboard LEADERBOARD = new Leaderboard(LobbySystem.getEntityServer(false), JUMP_AND_RUN_CONFIG, new Location(Bukkit.getWorlds().get(0), 2338.5, 42.5, 1231.5), 5);
|
private static final LeaderboardManager LEADERBOARD = new LeaderboardManager(LobbySystem.getEntityServer(false), JUMP_AND_RUN_CONFIG, new Location(Bukkit.getWorlds().get(0), 2338.5, 42.5, 1231.5));
|
||||||
|
|
||||||
{
|
{
|
||||||
Bukkit.getScheduler().runTaskTimer(LobbySystem.getInstance(), () -> {
|
Bukkit.getScheduler().runTaskTimer(LobbySystem.getInstance(), () -> {
|
||||||
@@ -161,18 +161,14 @@ public class JumpAndRun implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateJumpAndRunTime(Player player, long time) {
|
private void updateJumpAndRunTime(Player player, long time) {
|
||||||
String jumpAndRunTimeConfig = UserConfig.getConfig(player.getUniqueId(), JUMP_AND_RUN_CONFIG);
|
long best = LEADERBOARD.getPlayerTime(SteamwarUser.get(player.getUniqueId()));
|
||||||
if (jumpAndRunTimeConfig == null) {
|
if (time < best) {
|
||||||
UserConfig.updatePlayerConfig(player.getUniqueId(), JUMP_AND_RUN_CONFIG, time + "");
|
if (best != Long.MAX_VALUE) {
|
||||||
} else {
|
|
||||||
long jumpAndRunTime = Long.parseLong(jumpAndRunTimeConfig);
|
|
||||||
if (time < jumpAndRunTime) {
|
|
||||||
SimpleDateFormat format = new SimpleDateFormat(LobbySystem.getMessage().parse("JUMP_AND_RUN_TIME", player), Locale.ROOT);
|
SimpleDateFormat format = new SimpleDateFormat(LobbySystem.getMessage().parse("JUMP_AND_RUN_TIME", player), Locale.ROOT);
|
||||||
String parsed = format.format(new Date(jumpAndRunTime - time));
|
String parsed = format.format(new Date(best - time));
|
||||||
LobbySystem.getMessage().sendPrefixless("JUMP_AND_RUN_PERSONAL_BEST", player, parsed);
|
LobbySystem.getMessage().sendPrefixless("JUMP_AND_RUN_PERSONAL_BEST", player, parsed);
|
||||||
UserConfig.updatePlayerConfig(player.getUniqueId(), JUMP_AND_RUN_CONFIG, time + "");
|
|
||||||
LEADERBOARD.update();
|
|
||||||
}
|
}
|
||||||
|
LEADERBOARD.updateBestTime(SteamwarUser.get(player.getUniqueId()), time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -97,9 +97,10 @@ public class Present {
|
|||||||
folder = null;
|
folder = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeMember nodeMember = NodeMember.createNodeMember(schematicId, user.getId());
|
|
||||||
if (folder != null) {
|
if (folder != null) {
|
||||||
nodeMember.setParent(Optional.of(folder.getId()));
|
NodeMember.createNodeMember(schematicId, user.getId(), folder);
|
||||||
|
} else {
|
||||||
|
NodeMember.createNodeMember(schematicId, user.getId());
|
||||||
}
|
}
|
||||||
LobbySystem.getMessage().send("ADVENT_CALENDAR_OPEN", player, node.getName());
|
LobbySystem.getMessage().send("ADVENT_CALENDAR_OPEN", player, node.getName());
|
||||||
player.playSound(location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1);
|
player.playSound(location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1);
|
||||||
|
|||||||
+28
-45
@@ -23,9 +23,8 @@ import de.steamwar.entity.RArmorStand;
|
|||||||
import de.steamwar.entity.REntity;
|
import de.steamwar.entity.REntity;
|
||||||
import de.steamwar.entity.REntityServer;
|
import de.steamwar.entity.REntityServer;
|
||||||
import de.steamwar.lobby.LobbySystem;
|
import de.steamwar.lobby.LobbySystem;
|
||||||
|
import de.steamwar.sql.Leaderboard;
|
||||||
import de.steamwar.sql.SteamwarUser;
|
import de.steamwar.sql.SteamwarUser;
|
||||||
import de.steamwar.sql.internal.Statement;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -39,25 +38,18 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class Leaderboard implements Listener {
|
public class LeaderboardManager implements Listener {
|
||||||
|
|
||||||
private static final Statement LEADERBOARD = new Statement("SELECT User, CAST(Value as integer) AS Time from UserConfig WHERE Config = ? ORDER BY CAST(Value as integer) ASC LIMIT ?");
|
|
||||||
private static final Statement PLAYER_TIME = new Statement("SELECT CAST(Value as integer) AS Time FROM UserConfig WHERE Config = ? AND User = ?");
|
|
||||||
private static final Statement PLAYER_PLACEMENT = new Statement("SELECT COUNT(*) AS Placement FROM UserConfig WHERE Config = ? AND CAST(Value as integer) < (SELECT CAST(Value as integer) AS Time FROM UserConfig WHERE Config = ? AND User = ?)");
|
|
||||||
|
|
||||||
private final REntityServer server;
|
private final REntityServer server;
|
||||||
private final String configKey;
|
private final String configKey;
|
||||||
private final Location location;
|
private final Location location;
|
||||||
private final int best;
|
|
||||||
private long bestTime;
|
private long bestTime;
|
||||||
private final List<REntity> entities = new ArrayList<>();
|
private final List<REntity> entities = new ArrayList<>();
|
||||||
private final Map<Integer, REntityServer> playerPlacements = new HashMap<>();
|
private final Map<Integer, REntityServer> playerPlacements = new HashMap<>();
|
||||||
|
|
||||||
public Leaderboard(REntityServer server, String configKey, Location location, int best) {
|
public LeaderboardManager(REntityServer server, String configKey, Location location) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.configKey = configKey;
|
this.configKey = configKey;
|
||||||
this.location = location;
|
this.location = location;
|
||||||
this.best = best;
|
|
||||||
Bukkit.getPluginManager().registerEvents(this, LobbySystem.getInstance());
|
Bukkit.getPluginManager().registerEvents(this, LobbySystem.getInstance());
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
@@ -65,20 +57,23 @@ public class Leaderboard implements Listener {
|
|||||||
public void update() {
|
public void update() {
|
||||||
entities.forEach(REntity::die);
|
entities.forEach(REntity::die);
|
||||||
entities.clear();
|
entities.clear();
|
||||||
List<LeaderboardEntry> leaderboard = getLeaderboard();
|
List<Leaderboard> leaderboard = getLeaderboard();
|
||||||
if (leaderboard.isEmpty()) return;
|
if (leaderboard.isEmpty()) {
|
||||||
bestTime = leaderboard.get(0).time;
|
bestTime = Long.MAX_VALUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bestTime = leaderboard.get(0).getTime();
|
||||||
for (int i = 0; i < leaderboard.size(); i++) {
|
for (int i = 0; i < leaderboard.size(); i++) {
|
||||||
LeaderboardEntry entry = leaderboard.get(i);
|
Leaderboard entry = leaderboard.get(i);
|
||||||
RArmorStand entity = new RArmorStand(server, location.clone().add(0, (leaderboard.size() - i - 1) * 0.32, 0), RArmorStand.Size.MARKER);
|
RArmorStand entity = new RArmorStand(server, location.clone().add(0, (leaderboard.size() - i - 1) * 0.32, 0), RArmorStand.Size.MARKER);
|
||||||
SteamwarUser user = SteamwarUser.byId(entry.user);
|
SteamwarUser user = SteamwarUser.byId(entry.getUser());
|
||||||
String color = "§7";
|
String color = "§7";
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
color = "§6§l";
|
color = "§6§l";
|
||||||
} else if (i < 3) {
|
} else if (i < 3) {
|
||||||
color = "§e";
|
color = "§e";
|
||||||
}
|
}
|
||||||
entity.setDisplayName(calcName(user, color, i + 1, entry.time));
|
entity.setDisplayName(calcName(user, color, i + 1, entry.getTime()));
|
||||||
entity.setInvisible(true);
|
entity.setInvisible(true);
|
||||||
entities.add(entity);
|
entities.add(entity);
|
||||||
}
|
}
|
||||||
@@ -135,32 +130,27 @@ public class Leaderboard implements Listener {
|
|||||||
return st.toString();
|
return st.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<LeaderboardEntry> getLeaderboard() {
|
private boolean isNewBestTime(long time) {
|
||||||
return LEADERBOARD.select(resultSet -> {
|
return time < bestTime;
|
||||||
List<LeaderboardEntry> leaderboard = new ArrayList<>();
|
|
||||||
while (resultSet.next()) {
|
|
||||||
leaderboard.add(new LeaderboardEntry(resultSet.getInt("User"), resultSet.getLong("Time")));
|
|
||||||
}
|
|
||||||
return leaderboard;
|
|
||||||
}, configKey, best);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getPlayerTime(SteamwarUser user) {
|
public void updateBestTime(SteamwarUser user, long time) {
|
||||||
return PLAYER_TIME.select(resultSet -> {
|
Leaderboard.upsert(user.getId(), configKey, time, isNewBestTime(time));
|
||||||
if (!resultSet.next()) {
|
update();
|
||||||
return Long.MAX_VALUE;
|
}
|
||||||
}
|
|
||||||
return resultSet.getLong("Time");
|
private List<Leaderboard> getLeaderboard() {
|
||||||
}, configKey, user.getId());
|
return Leaderboard.getLeaderboard(configKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPlayerTime(SteamwarUser user) {
|
||||||
|
Leaderboard lb = Leaderboard.getPlayerTime(user, configKey);
|
||||||
|
if(lb != null) return lb.getTime();
|
||||||
|
return Long.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getPlayerPlacement(SteamwarUser user) {
|
private int getPlayerPlacement(SteamwarUser user) {
|
||||||
return PLAYER_PLACEMENT.select(resultSet -> {
|
return Leaderboard.getPlayerPlacement(user, configKey);
|
||||||
if (!resultSet.next()) {
|
|
||||||
return Integer.MAX_VALUE;
|
|
||||||
}
|
|
||||||
return resultSet.getInt("Placement");
|
|
||||||
}, configKey, configKey, user.getId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String renderTime(long time) {
|
public static String renderTime(long time) {
|
||||||
@@ -178,13 +168,6 @@ public class Leaderboard implements Listener {
|
|||||||
time % 1000);
|
time % 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AllArgsConstructor
|
|
||||||
private class LeaderboardEntry {
|
|
||||||
|
|
||||||
private final int user;
|
|
||||||
private final long time;
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
SteamwarUser steamwarUser = SteamwarUser.get(event.getPlayer().getUniqueId());
|
SteamwarUser steamwarUser = SteamwarUser.get(event.getPlayer().getUniqueId());
|
||||||
@@ -1,30 +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 jdk.internal.misc;
|
|
||||||
|
|
||||||
public class Unsafe {
|
|
||||||
|
|
||||||
public static Unsafe getUnsafe() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public native Object allocateInstance(Class<?> cls)
|
|
||||||
throws InstantiationException;
|
|
||||||
}
|
|
||||||
@@ -30,7 +30,7 @@ dependencies {
|
|||||||
annotationProcessor(libs.classindex)
|
annotationProcessor(libs.classindex)
|
||||||
compileOnly(project(":CommonCore", "default"))
|
compileOnly(project(":CommonCore", "default"))
|
||||||
compileOnly(project(":CommandFramework", "default"))
|
compileOnly(project(":CommandFramework", "default"))
|
||||||
compileOnly(project(":SpigotCore:CompileDummy", "default"))
|
compileOnly(project(":SpigotCore:CRIUDummy", "default"))
|
||||||
|
|
||||||
compileOnly(libs.worldedit12)
|
compileOnly(libs.worldedit12)
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import java.io.File;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class SQLWrapperImpl implements SQLWrapper<Material> {
|
public class SQLWrapperImpl implements SQLWrapper<Material> {
|
||||||
|
|
||||||
@@ -45,9 +46,11 @@ public class SQLWrapperImpl implements SQLWrapper<Material> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Material> getMaterialWithGreaterBlastResistance(double maxBlastResistance) {
|
public List<Material> getMaterialWithGreaterBlastResistance(double maxBlastResistance) {
|
||||||
return Arrays.stream(Material.values())
|
Stream<Material> stream = Arrays.stream(Material.values());
|
||||||
.filter(material -> !material.isLegacy())
|
if (Core.getVersion() > 12) {
|
||||||
.filter(Material::isBlock)
|
stream = stream.filter(material -> !material.isLegacy());
|
||||||
|
}
|
||||||
|
return stream.filter(Material::isBlock)
|
||||||
.filter(material -> material.getBlastResistance() > maxBlastResistance)
|
.filter(material -> material.getBlastResistance() > maxBlastResistance)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,9 @@
|
|||||||
package de.steamwar
|
package de.steamwar
|
||||||
|
|
||||||
import de.steamwar.plugins.configurePlugins
|
import de.steamwar.plugins.configurePlugins
|
||||||
import de.steamwar.routes.ResponseUser
|
|
||||||
import de.steamwar.routes.SchematicCode
|
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.engine.*
|
import io.ktor.server.engine.*
|
||||||
import de.steamwar.routes.configureRoutes
|
import de.steamwar.routes.configureRoutes
|
||||||
import de.steamwar.sql.SchematicType
|
|
||||||
import de.steamwar.sql.SteamwarUser
|
import de.steamwar.sql.SteamwarUser
|
||||||
import io.ktor.server.netty.*
|
import io.ktor.server.netty.*
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
@@ -47,7 +44,6 @@ fun main() {
|
|||||||
Thread {
|
Thread {
|
||||||
while (true) {
|
while (true) {
|
||||||
Thread.sleep(1000 * 10)
|
Thread.sleep(1000 * 10)
|
||||||
ResponseUser.clearCache()
|
|
||||||
SteamwarUser.clear()
|
SteamwarUser.clear()
|
||||||
}
|
}
|
||||||
}.start()
|
}.start()
|
||||||
|
|||||||
@@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* 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.routes
|
||||||
|
|
||||||
|
import de.steamwar.plugins.SWPermissionCheck
|
||||||
|
import de.steamwar.sql.AuditLog
|
||||||
|
import de.steamwar.sql.AuditLogTable
|
||||||
|
import de.steamwar.sql.SteamwarUserTable
|
||||||
|
import de.steamwar.sql.UserPerm
|
||||||
|
import de.steamwar.sql.internal.useDb
|
||||||
|
import io.ktor.server.application.call
|
||||||
|
import io.ktor.server.application.install
|
||||||
|
import io.ktor.server.response.respond
|
||||||
|
import io.ktor.server.routing.Route
|
||||||
|
import io.ktor.server.routing.get
|
||||||
|
import io.ktor.server.routing.route
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import org.jetbrains.exposed.v1.core.Alias
|
||||||
|
import org.jetbrains.exposed.v1.core.JoinType
|
||||||
|
import org.jetbrains.exposed.v1.core.SortOrder
|
||||||
|
import org.jetbrains.exposed.v1.core.alias
|
||||||
|
import org.jetbrains.exposed.v1.core.greater
|
||||||
|
import org.jetbrains.exposed.v1.core.inList
|
||||||
|
import org.jetbrains.exposed.v1.core.isNull
|
||||||
|
import org.jetbrains.exposed.v1.core.less
|
||||||
|
import org.jetbrains.exposed.v1.core.like
|
||||||
|
import org.jetbrains.exposed.v1.core.or
|
||||||
|
import org.jetbrains.exposed.v1.jdbc.Query
|
||||||
|
import org.jetbrains.exposed.v1.jdbc.andWhere
|
||||||
|
import org.jetbrains.exposed.v1.jdbc.select
|
||||||
|
import org.jetbrains.exposed.v1.jdbc.selectAll
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
fun Route.configureAuditLog() {
|
||||||
|
route("/auditlog") {
|
||||||
|
install(SWPermissionCheck) {
|
||||||
|
mustAuth = true
|
||||||
|
permission = UserPerm.MODERATION
|
||||||
|
}
|
||||||
|
|
||||||
|
get {
|
||||||
|
val text = call.request.queryParameters["fullText"]
|
||||||
|
val actionText = call.request.queryParameters["actionText"]
|
||||||
|
val serverText = call.request.queryParameters["server"]
|
||||||
|
val actor = call.request.queryParameters.getAll("actor")?.map { it.toInt() }?.toSet()
|
||||||
|
val actionType =
|
||||||
|
call.request.queryParameters.getAll("actionType")?.map { AuditLog.Type.valueOf(it) }?.toSet()
|
||||||
|
val timeGreater = call.request.queryParameters["timeGreater"]?.let { Instant.ofEpochMilli(it.toLong()) }
|
||||||
|
val timeLess = call.request.queryParameters["timeLess"]?.let { Instant.ofEpochMilli(it.toLong()) }
|
||||||
|
|
||||||
|
val serverOwner = call.request.queryParameters.getAll("serverOwner")?.map { it.toInt() }?.toSet()
|
||||||
|
val velocity = call.request.queryParameters["velocity"]?.toBoolean()
|
||||||
|
|
||||||
|
val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 0
|
||||||
|
val limit = call.request.queryParameters["limit"]?.toIntOrNull() ?: 100
|
||||||
|
val sorting = call.request.queryParameters["sorting"] ?: "DESC"
|
||||||
|
|
||||||
|
call.respond(
|
||||||
|
PagedAuditLog.filter(
|
||||||
|
actionText,
|
||||||
|
serverText,
|
||||||
|
text,
|
||||||
|
actor,
|
||||||
|
actionType,
|
||||||
|
timeGreater,
|
||||||
|
timeLess,
|
||||||
|
serverOwner,
|
||||||
|
velocity,
|
||||||
|
page,
|
||||||
|
limit,
|
||||||
|
sorting
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class PagedAuditLog(val rows: Long, val entries: List<AuditLogEntry>) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun filter(
|
||||||
|
actionText: String? = null,
|
||||||
|
serverText: String? = null,
|
||||||
|
fullText: String? = null,
|
||||||
|
actor: Set<Int>? = null,
|
||||||
|
actionType: Set<AuditLog.Type>? = null,
|
||||||
|
timeGreater: Instant? = null,
|
||||||
|
timeLess: Instant? = null,
|
||||||
|
serverOwner: Set<Int>? = null,
|
||||||
|
velocity: Boolean? = null,
|
||||||
|
page: Int = 0,
|
||||||
|
limit: Int = 100,
|
||||||
|
sorting: String = "DESC"
|
||||||
|
) = useDb {
|
||||||
|
val actorTable = SteamwarUserTable.alias("actor")
|
||||||
|
val serverOwnerTable = SteamwarUserTable.alias("serverOwner")
|
||||||
|
|
||||||
|
val query = AuditLogTable.join(
|
||||||
|
actorTable,
|
||||||
|
JoinType.INNER,
|
||||||
|
onColumn = actorTable[SteamwarUserTable.id],
|
||||||
|
otherColumn = AuditLogTable.actor
|
||||||
|
)
|
||||||
|
.join(
|
||||||
|
serverOwnerTable,
|
||||||
|
JoinType.LEFT,
|
||||||
|
onColumn = serverOwnerTable[SteamwarUserTable.id],
|
||||||
|
otherColumn = AuditLogTable.serverOwner
|
||||||
|
)
|
||||||
|
.select(
|
||||||
|
actorTable[SteamwarUserTable.username], serverOwnerTable[SteamwarUserTable.username],
|
||||||
|
*AuditLogTable.columns.toTypedArray()
|
||||||
|
)
|
||||||
|
|
||||||
|
PagedAuditLog(
|
||||||
|
AuditLogTable.selectAll().addAuditLogFilters(
|
||||||
|
actionText,
|
||||||
|
serverText,
|
||||||
|
fullText,
|
||||||
|
actor,
|
||||||
|
actionType,
|
||||||
|
timeGreater,
|
||||||
|
timeLess,
|
||||||
|
serverOwner,
|
||||||
|
velocity
|
||||||
|
).count(),
|
||||||
|
query
|
||||||
|
.addAuditLogFilters(
|
||||||
|
actionText,
|
||||||
|
serverText,
|
||||||
|
fullText,
|
||||||
|
actor,
|
||||||
|
actionType,
|
||||||
|
timeGreater,
|
||||||
|
timeLess,
|
||||||
|
serverOwner,
|
||||||
|
velocity
|
||||||
|
)
|
||||||
|
.limit(limit)
|
||||||
|
.offset((page * limit).toLong())
|
||||||
|
.orderBy(AuditLogTable.time, SortOrder.valueOf(sorting.uppercase()))
|
||||||
|
.map {
|
||||||
|
AuditLogEntry(
|
||||||
|
it[AuditLogTable.id].value,
|
||||||
|
it[AuditLogTable.time].toEpochMilli(),
|
||||||
|
it[AuditLogTable.server],
|
||||||
|
it[serverOwnerTable[SteamwarUserTable.username]],
|
||||||
|
it[actorTable[SteamwarUserTable.username]],
|
||||||
|
it[AuditLogTable.action],
|
||||||
|
it[AuditLogTable.actionText]
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Query.addAuditLogFilters(
|
||||||
|
actionText: String? = null,
|
||||||
|
serverText: String? = null,
|
||||||
|
fullText: String? = null,
|
||||||
|
actor: Set<Int>? = null,
|
||||||
|
actionType: Set<AuditLog.Type>? = null,
|
||||||
|
timeGreater: Instant? = null,
|
||||||
|
timeLess: Instant? = null,
|
||||||
|
serverOwner: Set<Int>? = null,
|
||||||
|
velocity: Boolean? = null,
|
||||||
|
): Query {
|
||||||
|
actionText?.let {
|
||||||
|
andWhere { (AuditLogTable.actionText like "%$it%") }
|
||||||
|
}
|
||||||
|
serverText?.let {
|
||||||
|
andWhere { (AuditLogTable.server like "%$it%") }
|
||||||
|
}
|
||||||
|
fullText?.let {
|
||||||
|
andWhere { (AuditLogTable.actionText like "%$it%") or (AuditLogTable.server like "%$it%") }
|
||||||
|
}
|
||||||
|
actor?.let { andWhere { AuditLogTable.actor inList actor } }
|
||||||
|
actionType?.let { andWhere { AuditLogTable.action inList actionType } }
|
||||||
|
timeGreater?.let { andWhere { AuditLogTable.time greater timeGreater } }
|
||||||
|
timeLess?.let { andWhere { AuditLogTable.time less timeLess } }
|
||||||
|
serverOwner?.let { andWhere { AuditLogTable.serverOwner inList serverOwner } }
|
||||||
|
if (velocity == true) andWhere { AuditLogTable.serverOwner.isNull() }
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class AuditLogEntry(
|
||||||
|
val id: Int,
|
||||||
|
val time: Long,
|
||||||
|
val server: String,
|
||||||
|
val serverOwner: String?,
|
||||||
|
val actor: String,
|
||||||
|
val actionType: AuditLog.Type,
|
||||||
|
val actionText: String
|
||||||
|
)
|
||||||
@@ -66,7 +66,7 @@ fun Route.configureAuth() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
call.sessions.set(SWUserSession(user.getId()))
|
call.sessions.set(SWUserSession(user.getId()))
|
||||||
call.respond(ResponseUser.get(user))
|
call.respond(ResponseUser(user))
|
||||||
}
|
}
|
||||||
|
|
||||||
delete {
|
delete {
|
||||||
@@ -100,7 +100,7 @@ fun Route.configureAuth() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
call.sessions.set(SWUserSession(user.getId()))
|
call.sessions.set(SWUserSession(user.getId()))
|
||||||
call.respond(ResponseUser.get(user))
|
call.respond(ResponseUser(user))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import de.steamwar.plugins.SWAuthPrincipal
|
|||||||
import de.steamwar.plugins.SWPermissionCheck
|
import de.steamwar.plugins.SWPermissionCheck
|
||||||
import de.steamwar.sql.SchematicType
|
import de.steamwar.sql.SchematicType
|
||||||
import de.steamwar.sql.SteamwarUser
|
import de.steamwar.sql.SteamwarUser
|
||||||
|
import de.steamwar.sql.SteamwarUserTable
|
||||||
import de.steamwar.sql.Team
|
import de.steamwar.sql.Team
|
||||||
import de.steamwar.sql.UserPerm
|
import de.steamwar.sql.UserPerm
|
||||||
import de.steamwar.sql.internal.useDb
|
import de.steamwar.sql.internal.useDb
|
||||||
@@ -36,6 +37,13 @@ import io.ktor.server.response.*
|
|||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import org.bspfsystems.yamlconfiguration.file.YamlConfiguration
|
import org.bspfsystems.yamlconfiguration.file.YamlConfiguration
|
||||||
|
import org.jetbrains.exposed.v1.core.ResultRow
|
||||||
|
import org.jetbrains.exposed.v1.core.eq
|
||||||
|
import org.jetbrains.exposed.v1.core.inList
|
||||||
|
import org.jetbrains.exposed.v1.core.like
|
||||||
|
import org.jetbrains.exposed.v1.jdbc.Query
|
||||||
|
import org.jetbrains.exposed.v1.jdbc.andWhere
|
||||||
|
import org.jetbrains.exposed.v1.jdbc.selectAll
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -44,28 +52,39 @@ import java.util.*
|
|||||||
data class ResponseSchematicType(val name: String, val db: String)
|
data class ResponseSchematicType(val name: String, val db: String)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ResponseUser(val name: String, val uuid: String, val prefix: String, val perms: List<String>) {
|
data class ResponseUser(
|
||||||
private constructor(user: SteamwarUser) : this(user.userName, user.uuid.toString(), user.prefix().chatPrefix, user.perms().filter { !it.name.startsWith("PREFIX_") }.map { it.name })
|
val name: String, val uuid: String, val id: Int?, val perms: List<String>?, val prefix: String?
|
||||||
|
) {
|
||||||
|
constructor(user: SteamwarUser, includeId: Boolean = false, includePerms: Boolean = false) : this(
|
||||||
|
user.userName,
|
||||||
|
user.uuid.toString(),
|
||||||
|
if (includeId) user.getId() else null,
|
||||||
|
if (includePerms) user.perms().map { it.name } else null,
|
||||||
|
if (includePerms) user.prefix().chatPrefix else null,
|
||||||
|
)
|
||||||
|
|
||||||
companion object {
|
constructor(row: ResultRow, includeId: Boolean = false, includePerms: Boolean = false, prefixes: MutableSet<UserPerm> = mutableSetOf()) : this(
|
||||||
private val cache = mutableMapOf<Int, ResponseUser>()
|
row[SteamwarUserTable.username],
|
||||||
|
row[SteamwarUserTable.uuid],
|
||||||
|
if (includeId) row[SteamwarUserTable.id].value else null,
|
||||||
|
if (includePerms) UserPerm.getPerms(row[SteamwarUserTable.id].value).also { prefixes.addAll(it) }.map { it.name } else null,
|
||||||
|
if (includePerms) prefixes.firstOrNull { UserPerm.prefixes.containsKey(it) }?.let { UserPerm.prefixes[it]!!.chatPrefix } else null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun get(id: Int): ResponseUser {
|
@Serializable
|
||||||
synchronized(cache) {
|
data class ResponseUserList(val entries: List<ResponseUser>, val rows: Long)
|
||||||
return cache[id] ?: ResponseUser(SteamwarUser.byId(id)!!).also { cache[id] = it }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun get(user: SteamwarUser): ResponseUser = synchronized(cache) {
|
private fun Query.addUserFilter(
|
||||||
return cache[user.getId()] ?: ResponseUser(user).also { cache[user.getId()] = it }
|
name: String? = null,
|
||||||
}
|
uuid: UUID? = null,
|
||||||
|
team: Set<Int>? = null,
|
||||||
|
): Query {
|
||||||
|
name?.let { andWhere { (SteamwarUserTable.username like "%$it%") } }
|
||||||
|
uuid?.let { andWhere { (SteamwarUserTable.uuid eq it.toString()) } }
|
||||||
|
team?.let { andWhere { (SteamwarUserTable.team inList team) } }
|
||||||
|
|
||||||
fun clearCache() {
|
return this
|
||||||
synchronized(cache) {
|
|
||||||
cache.clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Route.configureDataRoutes() {
|
fun Route.configureDataRoutes() {
|
||||||
@@ -76,13 +95,33 @@ fun Route.configureDataRoutes() {
|
|||||||
permission = UserPerm.MODERATION
|
permission = UserPerm.MODERATION
|
||||||
}
|
}
|
||||||
get("/users") {
|
get("/users") {
|
||||||
call.respond(useDb { SteamwarUser.all().map { ResponseUser.get(it) } })
|
val name = call.request.queryParameters["name"]
|
||||||
|
val uuid = call.request.queryParameters["uuid"]?.let { catchException { UUID.fromString(it) } }
|
||||||
|
val team = call.request.queryParameters.getAll("team")?.map { it.toInt() }?.toSet()
|
||||||
|
|
||||||
|
val limit = call.request.queryParameters["limit"]?.toIntOrNull() ?: 100
|
||||||
|
val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 0
|
||||||
|
|
||||||
|
val includePerms = call.request.queryParameters["includePerms"]?.toBoolean() ?: false
|
||||||
|
val includeId = call.request.queryParameters["includeId"]?.toBoolean() ?: false
|
||||||
|
|
||||||
|
call.respond(
|
||||||
|
useDb {
|
||||||
|
ResponseUserList(
|
||||||
|
SteamwarUserTable.selectAll().addUserFilter(name, uuid, team).limit(limit)
|
||||||
|
.offset((page * limit).toLong())
|
||||||
|
.map { ResponseUser(it, includeId, includePerms) },
|
||||||
|
SteamwarUserTable.selectAll().addUserFilter(name, uuid, team).count()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
get("/teams") {
|
get("/teams") {
|
||||||
call.respond(Team.getAll().map { ResponseTeam(it) })
|
call.respond(Team.getAll().map { ResponseTeam(it) })
|
||||||
}
|
}
|
||||||
get("/schematicTypes") {
|
get("/schematicTypes") {
|
||||||
call.respond(SchematicType.values().filter { !it.check() }.map { ResponseSchematicType(it.name(), it.toDB()) })
|
call.respond(SchematicType.values().filter { !it.check() }
|
||||||
|
.map { ResponseSchematicType(it.name(), it.toDB()) })
|
||||||
}
|
}
|
||||||
get("/gamemodes") {
|
get("/gamemodes") {
|
||||||
call.respond(
|
call.respond(
|
||||||
@@ -116,11 +155,14 @@ fun Route.configureDataRoutes() {
|
|||||||
}
|
}
|
||||||
get("/team") {
|
get("/team") {
|
||||||
call.respond(
|
call.respond(
|
||||||
listOf(UserPerm.PREFIX_ADMIN, UserPerm.PREFIX_DEVELOPER, UserPerm.PREFIX_MODERATOR, UserPerm.PREFIX_SUPPORTER, UserPerm.PREFIX_BUILDER)
|
listOf(
|
||||||
.associateWith { SteamwarUser.getUsersWithPerm(it) }
|
UserPerm.PREFIX_ADMIN,
|
||||||
.mapKeys { UserPerm.prefixes[it.key]!!.chatPrefix }
|
UserPerm.PREFIX_DEVELOPER,
|
||||||
.mapValues { it.value.map { ResponseUser.get(it) } }
|
UserPerm.PREFIX_MODERATOR,
|
||||||
)
|
UserPerm.PREFIX_SUPPORTER,
|
||||||
|
UserPerm.PREFIX_BUILDER
|
||||||
|
).associateWith { SteamwarUser.getUsersWithPerm(it) }.mapKeys { UserPerm.prefixes[it.key]!!.chatPrefix }
|
||||||
|
.mapValues { it.value.map { ResponseUser(it) } })
|
||||||
}
|
}
|
||||||
get("/skin/{uuid}") {
|
get("/skin/{uuid}") {
|
||||||
val uuid = call.parameters["uuid"]
|
val uuid = call.parameters["uuid"]
|
||||||
@@ -138,7 +180,7 @@ fun Route.configureDataRoutes() {
|
|||||||
route("/me") {
|
route("/me") {
|
||||||
install(SWPermissionCheck)
|
install(SWPermissionCheck)
|
||||||
get {
|
get {
|
||||||
call.respond(ResponseUser.get(call.principal<SWAuthPrincipal>()!!.user))
|
call.respond(ResponseUser(call.principal<SWAuthPrincipal>()!!.user, includePerms = true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ fun Route.configureEventRefereesRouting() {
|
|||||||
route("/referees") {
|
route("/referees") {
|
||||||
get {
|
get {
|
||||||
val event = call.receiveEvent() ?: return@get
|
val event = call.receiveEvent() ?: return@get
|
||||||
call.respond(Referee.get(event.eventID).map { ResponseUser.get(SteamwarUser.byId(it)!!) })
|
call.respond(Referee.get(event.eventID).map { ResponseUser(SteamwarUser.byId(it)!!) })
|
||||||
}
|
}
|
||||||
put {
|
put {
|
||||||
val event = call.receiveEvent() ?: return@put
|
val event = call.receiveEvent() ?: return@put
|
||||||
@@ -39,7 +39,7 @@ fun Route.configureEventRefereesRouting() {
|
|||||||
referees.forEach {
|
referees.forEach {
|
||||||
Referee.add(event.eventID, SteamwarUser.get(UUID.fromString(it))!!.getId())
|
Referee.add(event.eventID, SteamwarUser.get(UUID.fromString(it))!!.getId())
|
||||||
}
|
}
|
||||||
call.respond(Referee.get(event.eventID).map { ResponseUser.get(SteamwarUser.byId(it)!!) })
|
call.respond(Referee.get(event.eventID).map { ResponseUser(SteamwarUser.byId(it)!!) })
|
||||||
}
|
}
|
||||||
delete {
|
delete {
|
||||||
val event = call.receiveEvent() ?: return@delete
|
val event = call.receiveEvent() ?: return@delete
|
||||||
@@ -47,7 +47,7 @@ fun Route.configureEventRefereesRouting() {
|
|||||||
referees.forEach {
|
referees.forEach {
|
||||||
Referee.remove(event.eventID, SteamwarUser.get(UUID.fromString(it))!!.getId())
|
Referee.remove(event.eventID, SteamwarUser.get(UUID.fromString(it))!!.getId())
|
||||||
}
|
}
|
||||||
call.respond(Referee.get(event.eventID).map { ResponseUser.get(SteamwarUser.byId(it)!!) })
|
call.respond(Referee.get(event.eventID).map { ResponseUser(SteamwarUser.byId(it)!!) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ data class ExtendedResponseEvent(
|
|||||||
TeamTeilnahme.getTeams(event.eventID).map { ResponseTeam(it) },
|
TeamTeilnahme.getTeams(event.eventID).map { ResponseTeam(it) },
|
||||||
EventGroup.get(event).map { ResponseGroups(it) },
|
EventGroup.get(event).map { ResponseGroups(it) },
|
||||||
EventFight.getEvent(event.eventID).map { ResponseEventFight(it) },
|
EventFight.getEvent(event.eventID).map { ResponseEventFight(it) },
|
||||||
Referee.get(event.eventID).map { ResponseUser.get(SteamwarUser.byId(it)!!) },
|
Referee.get(event.eventID).map { ResponseUser(SteamwarUser.byId(it)!!) },
|
||||||
EventRelation.get(event).map { ResponseRelation(it) }
|
EventRelation.get(event).map { ResponseRelation(it) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ fun Application.configureRoutes() {
|
|||||||
configurePage()
|
configurePage()
|
||||||
configureSchematic()
|
configureSchematic()
|
||||||
configureAuth()
|
configureAuth()
|
||||||
|
configureAuditLog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,9 +34,7 @@ import io.ktor.server.response.*
|
|||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import java.io.BufferedInputStream
|
import java.io.BufferedInputStream
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
import java.io.InputStream
|
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@@ -49,16 +47,6 @@ data class ResponseSchematic(val name: String, val id: Int, val type: String?, v
|
|||||||
constructor(node: SchematicNode) : this(node.name, node.getId(), node.schemtype?.name(), node.owner, node.item, node.lastUpdate.time, node.rank, node.replaceColor(), node.allowReplay())
|
constructor(node: SchematicNode) : this(node.name, node.getId(), node.schemtype?.name(), node.owner, node.item, node.lastUpdate.time, node.rank, node.replaceColor(), node.allowReplay())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class ResponseSchematicLong(val members: List<ResponseUser>, val path: String, val schem: ResponseSchematic) {
|
|
||||||
constructor(node: SchematicNode, path: String): this(NodeMember.getNodeMembers(node.getId()).map { ResponseUser.get(it.member) }, path, ResponseSchematic(node))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class ResponseSchematicList(val breadcrumbs: List<ResponseBreadcrumb>, val schematics: List<ResponseSchematic>, val players: Map<String, ResponseUser>) {
|
|
||||||
constructor(schematics: List<ResponseSchematic>, breadcrumbs: List<ResponseBreadcrumb>) : this(breadcrumbs, schematics, schematics.map { it.owner }.distinct().map { ResponseUser.get(it) }.associateBy { it.uuid })
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ResponseBreadcrumb(val name: String, val id: Int)
|
data class ResponseBreadcrumb(val name: String, val id: Int)
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,17 @@ import de.steamwar.plugins.SWPermissionCheck
|
|||||||
import de.steamwar.plugins.getUser
|
import de.steamwar.plugins.getUser
|
||||||
import de.steamwar.sql.SteamwarUser
|
import de.steamwar.sql.SteamwarUser
|
||||||
import de.steamwar.sql.UserPerm
|
import de.steamwar.sql.UserPerm
|
||||||
import io.ktor.http.*
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.ApplicationCall
|
||||||
import io.ktor.server.response.*
|
import io.ktor.server.application.call
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.application.install
|
||||||
import kotlinx.serialization.Serializable
|
import io.ktor.server.response.respond
|
||||||
|
import io.ktor.server.routing.Route
|
||||||
|
import io.ktor.server.routing.delete
|
||||||
|
import io.ktor.server.routing.get
|
||||||
|
import io.ktor.server.routing.put
|
||||||
|
import io.ktor.server.routing.route
|
||||||
|
import kotlinx.serialization.Serializable;
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class RespondPrefix(val name: String, val colorCode: String, val chatPrefix: String)
|
data class RespondPrefix(val name: String, val colorCode: String, val chatPrefix: String)
|
||||||
@@ -76,7 +82,12 @@ fun Route.configureUserPerms() {
|
|||||||
|
|
||||||
val prefixs = UserPerm.prefixes[prefix]!!
|
val prefixs = UserPerm.prefixes[prefix]!!
|
||||||
|
|
||||||
call.respond(RespondUserPermsPrefix(RespondPrefix(prefix.name, prefixs.colorCode, prefixs.chatPrefix), perms))
|
call.respond(
|
||||||
|
RespondUserPermsPrefix(
|
||||||
|
RespondPrefix(prefix.name, prefixs.colorCode, prefixs.chatPrefix),
|
||||||
|
perms
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
put("/prefix/{prefix}") {
|
put("/prefix/{prefix}") {
|
||||||
val (user, prefix) = call.receivePermission("prefix", isPrefix = true) ?: return@put
|
val (user, prefix) = call.receivePermission("prefix", isPrefix = true) ?: return@put
|
||||||
@@ -112,7 +123,10 @@ fun Route.configureUserPerms() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun ApplicationCall.receivePermission(fieldName: String = "perm", isPrefix: Boolean = false): Pair<SteamwarUser, UserPerm>? {
|
suspend fun ApplicationCall.receivePermission(
|
||||||
|
fieldName: String = "perm",
|
||||||
|
isPrefix: Boolean = false
|
||||||
|
): Pair<SteamwarUser, UserPerm>? {
|
||||||
val user = request.getUser()
|
val user = request.getUser()
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
respond(HttpStatusCode.BadRequest)
|
respond(HttpStatusCode.BadRequest)
|
||||||
|
|||||||
@@ -25,3 +25,39 @@ allprojects {
|
|||||||
group = "de.steamwar"
|
group = "de.steamwar"
|
||||||
version = ""
|
version = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.register("0_ClearAllGradle") {
|
||||||
|
group = "run"
|
||||||
|
description = "Clears the gradle build caches"
|
||||||
|
|
||||||
|
doLast {
|
||||||
|
File("~/.gradle/").deleteRecursively()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register("1_ClearGradleBuilds") {
|
||||||
|
group = "run"
|
||||||
|
description = "Clears the gradle build caches"
|
||||||
|
|
||||||
|
doLast {
|
||||||
|
File("~/.gradle/build-cache-1/").deleteRecursively()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register("2_ClearAllGradleDependencies") {
|
||||||
|
group = "run"
|
||||||
|
description = "Clears the dependencies in the .gradle folder"
|
||||||
|
|
||||||
|
doLast {
|
||||||
|
File("~/.gradle/modules-2/files-2.1/").deleteRecursively()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register("2_ClearSWGradleDependencies") {
|
||||||
|
group = "run"
|
||||||
|
description = "Clears the dependencies in the .gradle folder"
|
||||||
|
|
||||||
|
doLast {
|
||||||
|
File("~/.gradle/modules-2/files-2.1/de.steamwar/").deleteRecursively()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -234,7 +234,7 @@ include(
|
|||||||
|
|
||||||
include(
|
include(
|
||||||
"SpigotCore",
|
"SpigotCore",
|
||||||
"SpigotCore:CompileDummy",
|
"SpigotCore:CRIUDummy",
|
||||||
"SpigotCore:SpigotCore_8",
|
"SpigotCore:SpigotCore_8",
|
||||||
"SpigotCore:SpigotCore_9",
|
"SpigotCore:SpigotCore_9",
|
||||||
"SpigotCore:SpigotCore_10",
|
"SpigotCore:SpigotCore_10",
|
||||||
|
|||||||
Reference in New Issue
Block a user