Compare commits

...
Author SHA1 Message Date
Jaki 7132bbdfd6 merge upstream 2026-08-17 01:16:43 +02:00
YoyoNow 397b10c319 Merge pull request 'Velocity core /event command' (#465) from VelocityCore/EventCommand into main
Deploy / Build (push) Successful in 2m12s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #465
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-08-14 07:53:43 +02:00
YoyoNow 32569f19d9 Closes: #468
Deploy / Build (push) Successful in 2m15s
Deploy / Deploy (push) Successful in 11s
2026-08-13 10:09:13 +02:00
YoyoNow f19e4158e7 Fix Check
Deploy / Build (push) Successful in 2m19s
Deploy / Deploy (push) Successful in 13s
2026-08-13 10:01:55 +02:00
YoyoNow 6c46b5b2a2 Fix Check
Deploy / Build (push) Successful in 2m20s
Deploy / Deploy (push) Successful in 11s
2026-08-13 09:51:56 +02:00
YoyoNow 58516448d9 Merge pull request 'Add deletion of PlayerData on /bau delmember' (#454) from VelocityCore/DeleteMemberOfBauDeletingPlayerData into main
Deploy / Build (push) Successful in 2m17s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #454
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-08-13 09:50:14 +02:00
YoyoNow 683236bb59 Fix TexturePackSystem for newer versions
Deploy / Build (push) Successful in 2m11s
Deploy / Deploy (push) Successful in 10s
2026-08-13 09:39:42 +02:00
YoyoNow 8dc101639d Add alias of /tick rate to /tick rate 20
Deploy / Build (push) Successful in 2m23s
Deploy / Deploy (push) Successful in 15s
2026-08-11 21:48:28 +02:00
YoyoNow 792620804a Improve TPSSystem
Deploy / Build (push) Successful in 2m26s
Deploy / Deploy (push) Successful in 11s
2026-08-11 21:46:38 +02:00
YoyoNow 4aa7c99a6e Fix Check and CheckCommand permission
Deploy / Build (push) Successful in 3m30s
Deploy / Deploy (push) Successful in 11s
2026-08-11 21:05:36 +02:00
Sakziea cce18124f2 Remove unused translation
Pull Request Build / Build (pull_request) Successful in 3m33s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Failing after 8s
2026-08-05 20:30:36 +02:00
Sakziea 18ad0ad90c Add Clickevents to EventPage 2026-08-05 20:30:28 +02:00
Sakziea a58de898bb Add Clickevents to EventPage 2026-08-05 20:30:25 +02:00
Sakziea 507b7c2569 Add event showtable 2026-08-05 20:30:20 +02:00
Sakziea a18098b8f4 Fix Pull request comments 2026-08-05 20:30:15 +02:00
Sakziea 97773f292d Remove unused import 2026-08-05 20:30:09 +02:00
Sakziea 5fdfc03587 Fix /event [Team] move to /event team [Team] 2026-08-05 20:30:00 +02:00
Sakziea 493e66cc98 Add current event uses eventpage 2026-08-05 20:29:37 +02:00
Sakziea 2be3a136ae Add funktion to show next events and formatet the fights in pages 2026-08-05 20:29:28 +02:00
Sakziea c62a566447 Fix pull Request comment 2026-08-05 20:29:18 +02:00
Sakziea 0684765a76 Remove unused imports 2026-08-05 20:29:09 +02:00
Sakziea c40f29c3c1 Add Wind charge config 2026-08-05 20:28:53 +02:00
Sakziea 72dc4eee9e Fix Wind charges cross middle and interact with Blocks 2026-08-05 20:28:24 +02:00
Sakziea c7a949322e Fix Windcharge remove Water 2026-08-05 20:27:39 +02:00
Chaoscaot 9d5b7893f1 Merge pull request 'Replace Custom Observer with kotlinx StateFlows' (#444) from swui/flows into main
Deploy / Build (push) Successful in 2m47s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #444
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-07-26 10:22:42 +02:00
Chaoscaot ae898e14c2 Merge branch 'main' into swui/flows
Pull Request Build / Build (pull_request) Successful in 1m56s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 8s
2026-07-26 10:20:35 +02:00
Chaoscaot 726f73cc45 Merge branch 'main' into VelocityCore/DeleteMemberOfBauDeletingPlayerData
Pull Request Build / Build (pull_request) Successful in 1m32s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 9s
2026-07-26 03:04:45 +02:00
YoyoNow 64e627514d Add deletion of PlayerData on /bau delmember
Pull Request Build / Build (pull_request) Successful in 1m29s
2026-07-17 09:47:40 +02:00
Chaoscaot 3a247de43d Replace Custom Observer with kotlinx StateFlows
Pull Request Build / Build (pull_request) Successful in 1m50s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-07-06 01:13:05 +02:00
Jaki bf50b30460 merge upstream 2026-05-26 22:39:05 +02:00
Jaki 6cef6d1f68 merge upstream 2026-05-22 22:27:20 +02:00
Jakob Schulz 776b0b1f9f fix: allow ISE in team prefix command for improved flexibility 2026-05-20 22:53:34 +02:00
19 changed files with 382 additions and 159 deletions
@@ -290,7 +290,7 @@ public class KillcheckerVisualizer {
}
rEntities.get(point).die();
}
RBlockDisplay entity = new RBlockDisplay(outlinePoints.contains(point) ? outline : inner, point.toLocation(WORLD, 0.5, 0, 0.5));
RBlockDisplay entity = new RBlockDisplay(outlinePoints.contains(point) ? outline : inner, point.toLocation(WORLD, 0, 0, 0));
entity.setBlock(MATERIALS[Math.min(count - 1, MATERIALS.length) - 1].createBlockData());
rEntities.put(point, entity);
if (outlinePoints.contains(point)) outlinePointsCache.add(point);
@@ -165,6 +165,7 @@ public class TPSSystem implements Listener {
}
@Register(value = "default", description = "TPSLIMIT_DEFAULT_HELP")
@Register(value = "rate")
public void reset(@Validator Player player) {
TickManager.impl.setTickRate(20.0F);
sendTickRateChange();
@@ -187,15 +188,18 @@ public class TPSSystem implements Listener {
}
@Register(value = {"rate", "0"}, description = "TICK_FREEZE_HELP")
@Register(value = "freeze", description = "TICK_FREEZE_HELP_2")
public void freeze(@Validator Player player) {
public void rate(@Validator Player player) {
TickManager.impl.setFreeze(true);
sendTickRateChange();
}
@Register(value = "unfreeze", description = "TICK_UNFREEZE_HELP")
public void unfreeze(@Validator Player player) {
TickManager.impl.setTickRate(20.0F);
@Register(value = "freeze", description = "TICK_FREEZE_HELP_2")
public void freezeToggle(@Validator Player player) {
if (TickManager.impl.isFrozen()) {
TickManager.impl.setTickRate(20.0F);
} else {
TickManager.impl.setFreeze(true);
}
sendTickRateChange();
}
}
@@ -25,6 +25,7 @@ import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.linkage.Linked;
import de.steamwar.sql.GameModeConfig;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.UserPerm;
@@ -44,14 +45,24 @@ public class Check implements Listener {
new StateDependentListener(ArenaMode.Check, FightState.All, this);
}
private boolean checkPermission(SteamwarUser user, SchematicNode schematic) {
GameModeConfig<Object, String> gameModeConfig = GameModeConfig.getAll().stream()
.filter(gmc -> gmc.Schematic.Type != null && gmc.Schematic.Type.equals(schematic.getSchemtype()))
.findFirst()
.orElse(null);
if (gameModeConfig == null) gameModeConfig = GameModeConfig.getDefaults();
if (user.hasPerm(UserPerm.ADMINISTRATION)) return true;
if (gameModeConfig.Checkers.isEmpty() && user.hasPerm(UserPerm.CHECK)) return true;
return gameModeConfig.Checkers.contains(user.getId());
}
@EventHandler
public void onJoin(PlayerJoinEvent e) {
Player player = e.getPlayer();
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
if (user.hasPerm(UserPerm.CHECK)) return;
SchematicNode schem = SchematicNode.getSchematicNode(Config.CheckSchemID);
if (checkPermission(user, schem)) return;
if (user.getId() == schem.getOwner()) return;
FightSystem.getMessage().send("CHECK_JOIN_DENIED", player);
+2 -1
View File
@@ -36,6 +36,7 @@ dependencies {
compileOnly(libs.paperapi)
compileOnly(project(":SpigotCore"))
implementation(libs.coroutinesCore)
implementation(libs.exposedCore)
implementation(libs.exposedDao)
implementation(libs.exposedJdbc)
@@ -47,4 +48,4 @@ val compileKotlin: KotlinCompile by tasks
compileKotlin.compilerOptions {
freeCompilerArgs.set(listOf("-XXLanguage:+ContextParameters"))
}
}
@@ -1,101 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.kotlin.ui
import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
abstract class Observable<T> {
internal val listeners = mutableSetOf<ObserverListener>()
open fun removeListener(render: ObserverListener) {
listeners.remove(render)
}
internal fun notifyListeners() {
listeners.forEach { it.update() }
}
context(render: ObserverListener)
fun listen(): Observable<T> {
listeners.add(render)
render.observers.add(this)
return this
}
fun listen(callback: (T) -> Unit): () -> Unit {
val listener = object: ObserverListener() {
override fun update() = callback(get())
}
listeners.add(listener)
callback(get())
return { removeListener(listener) }
}
abstract fun get(): T
fun <R> map(mapper: (T) -> R): Observable<R> = Delegate(mapper, this)
class Delegate<T, R>(val mapper: (T) -> R, val parent: Observable<T>): Observable<R>(), ReadOnlyProperty<Any?, R> {
var value: R? = null
var unsubParent = parent.listen {
val old = value
value = mapper(it)
if (old != value) {
notifyListeners()
}
}
override fun removeListener(render: ObserverListener) {
super.removeListener(render)
if (listeners.isEmpty()) {
unsubParent()
}
}
override fun get(): R = value!!
override fun getValue(thisRef: Any?, property: KProperty<*>): R = value!!
}
}
class Observer<T>(private var value: T): ReadWriteProperty<Any?, T>, Observable<T>() {
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
notifyListeners()
}
fun set(value: T) {
this.value = value
notifyListeners()
}
override fun get() = value
fun update(update: (T) -> T) {
this.value = update(value)
notifyListeners()
}
}
@@ -0,0 +1,90 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.kotlin.ui
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalForInheritanceCoroutinesApi
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlin.reflect.KProperty
private val uiStateScope = CoroutineScope(SupervisorJob() + Dispatchers.Unconfined)
context(render: StateFlowListener)
fun <T> StateFlow<T>.listen(): StateFlow<T> {
render.track(this) {
drop(1).onEach { render.update() }.launchIn(uiStateScope)
}
return this
}
context(render: StateFlowListener)
fun <T> MutableStateFlow<T>.listen(): MutableStateFlow<T> {
render.track(this) {
drop(1).onEach { render.update() }.launchIn(uiStateScope)
}
return this
}
fun <T> StateFlow<T>.listen(callback: (T) -> Unit): () -> Unit {
callback(value)
val job = drop(1).onEach { callback(it) }.launchIn(uiStateScope)
return { job.cancel() }
}
operator fun <T> StateFlow<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
operator fun <T> MutableStateFlow<T>.setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
fun <T, R> StateFlow<T>.map(mapper: (T) -> R): StateFlow<R> = MappedStateFlow(this, mapper)
@OptIn(ExperimentalForInheritanceCoroutinesApi::class)
private class MappedStateFlow<T, R>(
private val parent: StateFlow<T>,
private val mapper: (T) -> R,
): StateFlow<R> {
override val replayCache: List<R>
get() = listOf(value)
override val value: R
get() = mapper(parent.value)
override suspend fun collect(collector: FlowCollector<R>): Nothing {
var initialized = false
var previous: Any? = null
parent.collect {
val mapped = mapper(it)
if (!initialized || previous != mapped) {
initialized = true
previous = mapped
collector.emit(mapped)
}
}
}
}
@@ -19,13 +19,23 @@
package de.steamwar.kotlin.ui
abstract class ObserverListener {
val observers = mutableSetOf<Observable<*>>()
import kotlinx.coroutines.Job
abstract class StateFlowListener {
private val jobs = mutableMapOf<Any, Job>()
internal fun track(key: Any, createJob: () -> Job) {
if (key in jobs) return
val job = createJob()
jobs[key] = job
job.invokeOnCompletion { jobs.remove(key) }
}
abstract fun update()
open fun destroy() {
observers.forEach { it.removeListener(this) }
observers.clear()
jobs.values.toList().forEach { it.cancel() }
jobs.clear()
}
}
}
@@ -0,0 +1,46 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.kotlin.ui
import de.steamwar.kotlin.ui.components.item
import de.steamwar.kotlin.util.count
import kotlinx.coroutines.flow.MutableStateFlow
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
val Counter = MutableStateFlow(0)
class TestInv(player: Player): UIInventory(player) {
override fun view() {
inventory(3, "") {
item {
val amount by Counter.map { it + 1 }.listen()
item = ItemStack.of(Material.STONE)
.count(amount)
x = 0
y = 0
onClick {
Counter.value += 1
}
}
}
}
}
@@ -23,7 +23,7 @@ import de.steamwar.kotlin.ui.context.WindowContext
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryType
abstract class UIInventory(val player: Player): ObserverListener() {
abstract class UIInventory(val player: Player): StateFlowListener() {
var window: UIWindow? = null
abstract fun view()
@@ -52,4 +52,4 @@ abstract class UIInventory(val player: Player): ObserverListener() {
protected fun inventory(type: InventoryType, title: String, init: WindowContext.() -> Unit) {
window = UIWindow(type, title, player, init)
}
}
}
@@ -19,7 +19,7 @@
package de.steamwar.kotlin.ui.components
import de.steamwar.kotlin.ui.ObserverListener
import de.steamwar.kotlin.ui.StateFlowListener
import de.steamwar.kotlin.ui.RenderMarker
import de.steamwar.kotlin.ui.RenderObject
import de.steamwar.kotlin.ui.context.GroupContext
@@ -29,7 +29,7 @@ import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.ItemStack
@RenderMarker
class ItemContext(val parent: RenderParent, val renderFunc: ItemContext.() -> Unit): RenderObject, ObserverListener() {
class ItemContext(val parent: RenderParent, val renderFunc: ItemContext.() -> Unit): RenderObject, StateFlowListener() {
override fun update() {
val oldX = x
val oldY = y
@@ -40,6 +40,7 @@ class ItemContext(val parent: RenderParent, val renderFunc: ItemContext.() -> Un
}
override fun destroy() {
super.destroy()
parent.resetSlot(x, y)
}
@@ -19,14 +19,14 @@
package de.steamwar.kotlin.ui.context
import de.steamwar.kotlin.ui.ObserverListener
import de.steamwar.kotlin.ui.StateFlowListener
import de.steamwar.kotlin.ui.RenderMarker
import de.steamwar.kotlin.ui.RenderObject
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.ItemStack
@RenderMarker
open class GroupContext(val parent: RenderParent?, val init: GroupContext.() -> Unit): ObserverListener(), RenderObject, RenderParent {
open class GroupContext(val parent: RenderParent?, val init: GroupContext.() -> Unit): StateFlowListener(), RenderObject, RenderParent {
val children = mutableListOf<RenderObject>()
val updatedSlots = mutableSetOf<Pair<Int, Int>>()
@@ -62,4 +62,4 @@ open class GroupContext(val parent: RenderParent?, val init: GroupContext.() ->
init(this)
(oldUpdatedSlots - updatedSlots).forEach { resetSlot(it.first, it.second) }
}
}
}
@@ -271,7 +271,8 @@ CHALLENGE_ACCEPT_HOVER = §aAccept challenge
#EventCommand
EVENT_TIME_FORMAT = HH:mm
EVENT_DATE_FORMAT = dd.MM.
EVENT_USAGE = §8/§7event §8[§eTeam§8] - §7To teleport to a fight
EVENT_TEAM_USAGE = §8/§7event team §8[§eTeam§8] - §7To teleport to a fight
EVENT_SHOW_FIGHTS_USAGE = §8/§7event showfights §8[§eEvent§8] - §7To show the fights of that Event
EVENT_NO_TEAM = §cThis team does not exist
EVENT_NO_FIGHT_TEAM = §cThis team has no current fight
EVENT_NO_CURRENT = §cThere is no event taking place currently
@@ -282,9 +283,13 @@ EVENT_COMING_SCHEM_DEADLINE = §7 Submission deadline§8: §7{0}
EVENT_COMING_TEAMS = §7 With§8: {0}
EVENT_COMING_TEAM = §{0}{1}
EVENT_CURRENT_EVENT = §e§l{0}
EVENT_CURRENT_FIGHT = §7{0} §{1}{2}§8 vs §{3}{4}
EVENT_CURRENT_FIGHT_1 = §7{0} §{1}{2}
EVENT_CURRENT_FIGHT_VS = §8 vs
EVENT_CURRENT_FIGHT_2 = §{1}{2}
EVENT_CURRENT_FIGHT_WIN = §8: §7Victory §{0}{1}
EVENT_CURRENT_FIGHT_DRAW = §8: §7Draw
EVENT_TEAM_TABLE = §{0}{1}{2} §8 with §e{3} §7points
EVENT_SHOW_TABLE_USAGE = §8/§7event showtable §8[§eEvent§8] - §7To show the table of that Event
#EventRescheduleCommand
EVENTRESCHEDULE_USAGE = §8/§7eventreschedule §8[§eTeam1§8] [§eTeam2§8]
@@ -751,3 +756,9 @@ DC_SCHEMUPLOAD_IGNORED = Skipping `{0}`, not a schematic file.
DC_SCHEMUPLOAD_INVCHAR = `{0}` has invalid characters in its name.
DC_SCHEMUPLOAD_SUCCESS = `{0}` was uploaded successfully.
DC_SCHEMUPLOAD_ERROR = An error has occured during the upload of `{0}`. For more information ask a Developer.
UTIL_LIST_BACK_ARROW = §8««
UTIL_LIST_BACK_ARROW_HOVER = §ePrevious page
UTIL_LIST_PAGE = §e Page §7({0}/{1})
UTIL_LIST_NEXT = §8 »»
UTIL_LIST_NEXT_HOVER = §eNext page
@@ -253,7 +253,8 @@ CHALLENGE_ACCEPT_HOVER = §aHerausforderung annehmen
#EventCommand
EVENT_TIME_FORMAT = HH:mm
EVENT_DATE_FORMAT = dd.MM.
EVENT_USAGE = §8/§7event §8[§eTeam§8] - §7Um dich zum Kampf zu teleportieren
EVENT_TEAM_USAGE=§8/§7event team §8[§eTeam§8] - §7Um dich zum Kampf zu teleportieren
EVENT_SHOW_FIGHTS_USAGE = §8/§7event showfights §8[§eEvent§8] - §7Um die fights des Events zu zeigen
EVENT_NO_TEAM = §cDieses Team gibt es nicht
EVENT_NO_FIGHT_TEAM = §cDas Team kämpft derzeit nicht
EVENT_NO_CURRENT = §cDerzeit findet kein Event statt
@@ -264,9 +265,10 @@ EVENT_COMING_SCHEM_DEADLINE = §7 Einsendeschluss§8: §7{0}
EVENT_COMING_TEAMS = §7 Mit§8: {0}
EVENT_COMING_TEAM = §{0}{1}
EVENT_CURRENT_EVENT = §e§l{0}
EVENT_CURRENT_FIGHT = §7{0} §{1}{2}§8 vs §{3}{4}
EVENT_CURRENT_FIGHT_WIN = §8: §7Sieg §{0}{1}
EVENT_CURRENT_FIGHT_DRAW = §8: §7Unentschieden
EVENT_TEAM_TABLE = §{0}{1}{2} §8 mit §e{3} §7Punkten
EVENT_SHOW_TABLE_USAGE = §8/§7event showtable §8[§eEvent§8] - §7Um die Tabelle des Events zu zeigen.
#EventRescheduleCommand
EVENTRESCHEDULE_USAGE = §8/§7eventreschedule §8[§eTeam1§8] [§eTeam2§8]
@@ -55,7 +55,7 @@ public class ServerStarter {
public static final String WORLDS_BASE_PATH = WORLDS_FOLDER + "/userworlds";
public static final String BUILDER_BASE_PATH = WORLDS_FOLDER + "/builder";
private static final String WORLDS_STORAGE_BASE_PATH = "/mnt/storage/worlds/userworlds";
public static final String WORLDS_STORAGE_BASE_PATH = "/mnt/storage/worlds/userworlds";
private File directory = null;
private String worldDir = null;
@@ -44,6 +44,7 @@ import de.steamwar.velocitycore.inventory.SWItem;
import de.steamwar.velocitycore.network.NetworkSender;
import de.steamwar.velocitycore.util.BauLock;
import java.io.File;
import java.util.Collection;
import java.util.function.Consumer;
@@ -187,11 +188,35 @@ public class BauCommand extends SWCommand {
bauserver.getRegisteredServer().getPlayersConnected().stream().findAny().ifPresent(player -> NetworkSender.send(player, new BaumemberUpdatePacket()));
}
try {
deletePlayerData(owner, user);
} catch (Exception e) {
// Ignore this silently since it does not matter in any way if the data is not deleted properly.
}
member.system("BAU_DELMEMBER_DELETED_TARGET", owner);
owner.system("BAU_DELMEMBER_DELETED");
});
}
private void deletePlayerData(Chatter owner, SteamwarUser user) {
String worldName = String.valueOf(owner.user().getId());
String targetDat = user.getUUID().toString().toLowerCase() + ".dat";
String targetDatOld = user.getUUID().toString().toLowerCase() + ".dat_old";
for (ServerVersion version : ServerVersion.values()) {
File playerData = new File(new File(version.getWorldFolder(ServerStarter.WORLDS_BASE_PATH), worldName), "playerdata");
if (playerData.exists()) {
new File(playerData, targetDat).delete();
new File(playerData, targetDatOld).delete();
}
File playerDataStorage = new File(new File(version.getWorldFolder(ServerStarter.WORLDS_STORAGE_BASE_PATH), worldName), "playerdata");
if (playerDataStorage.exists()) {
new File(playerDataStorage, targetDat).delete();
new File(playerDataStorage, targetDatOld).delete();
}
}
}
@Mapper(value = "addedUsers", local = true)
public TypeMapper<SteamwarUser> addedUsers() {
return new TypeMapper<SteamwarUser>() {
@@ -85,7 +85,6 @@ public class CheckCommand extends SWCommand {
if (user.perms().contains(UserPerm.CHECK)) return true;
return GameModeConfig.getAll()
.stream()
.filter(GameModeConfig::isActive)
.anyMatch(gameMode -> gameMode.Checkers.contains(user.getId()));
}
@@ -19,6 +19,7 @@
package de.steamwar.velocitycore.commands;
import com.google.protobuf.MapEntry;
import de.steamwar.command.PreviousArguments;
import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeMapper;
@@ -28,13 +29,18 @@ import de.steamwar.messages.Chatter;
import de.steamwar.messages.PlayerChatter;
import de.steamwar.persistent.Subserver;
import de.steamwar.sql.*;
import de.steamwar.sql.Event;
import de.steamwar.velocitycore.EventStarter;
import de.steamwar.velocitycore.SubserverSystem;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import java.awt.*;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -82,35 +88,84 @@ public class EventCommand extends SWCommand {
@Register
public void eventOverview(@Validator(value = "noEvent", invert = true) Chatter sender) {
sender.system("EVENT_USAGE");
sender.system("EVENT_TEAM_USAGE");
Event currentEvent = Event.get();
sender.system("EVENT_CURRENT_EVENT", currentEvent.getEventName());
eventShowFightsPage(sender, currentEvent, 1);
}
DateTimeFormatter format = DateTimeFormatter.ofPattern(sender.parseToPlain("EVENT_TIME_FORMAT"));
for (EventFight fight : EventFight.getEvent(currentEvent.getEventID())) {
Team blue = Team.byId(fight.getTeamBlue());
Team red = Team.byId(fight.getTeamRed());
StringBuilder fline = new StringBuilder(sender.parseToLegacy("EVENT_CURRENT_FIGHT", fight.getStartTime().toLocalDateTime().format(format), blue.getTeamColor(), blue.getTeamKuerzel(), red.getTeamColor(), red.getTeamKuerzel()));
@Register(value = "showtable", description = "EVENT_SHOW_TABLE_USAGE")
public void eventtable(Chatter sender, Event event) {
if (!Instant.now().isBefore(event.getEnd().toInstant())) return;
if (fight.hasFinished()) {
switch (fight.getErgebnis()) {
Map<Integer, Integer> Teampoints = new HashMap<>();
EventFight.getEvent(event.getEventID()).forEach(eventFight -> {
if (eventFight.hasFinished() && eventFight.getGroup().isPresent()) {
switch (eventFight.getErgebnis()) {
case 1:
fline.append(sender.parseToLegacy("EVENT_CURRENT_FIGHT_WIN", blue.getTeamColor(), blue.getTeamKuerzel()));
//win blue
Teampoints.put(eventFight.getTeamBlue(), Teampoints.getOrDefault(eventFight.getTeamBlue(), 0) + eventFight.getGroup().get().getPointsPerWin());
Teampoints.put(eventFight.getTeamRed(), Teampoints.getOrDefault(eventFight.getTeamRed(),0) + eventFight.getGroup().get().getPointsPerLoss());
break;
case 2:
fline.append(sender.parseToLegacy("EVENT_CURRENT_FIGHT_WIN", red.getTeamColor(), red.getTeamKuerzel()));
//win red
Teampoints.put(eventFight.getTeamBlue(), Teampoints.getOrDefault(eventFight.getTeamBlue(),0) + eventFight.getGroup().get().getPointsPerLoss());
Teampoints.put(eventFight.getTeamRed(), Teampoints.getOrDefault(eventFight.getTeamRed(),0) + eventFight.getGroup().get().getPointsPerWin());
break;
default:
fline.append(sender.parseToLegacy("EVENT_CURRENT_FIGHT_DRAW"));
//draw
Teampoints.put(eventFight.getTeamBlue(), Teampoints.getOrDefault(eventFight.getTeamBlue(),0) + eventFight.getGroup().get().getPointsPerDraw());
Teampoints.put(eventFight.getTeamRed(), Teampoints.getOrDefault(eventFight.getTeamRed(),0) + eventFight.getGroup().get().getPointsPerDraw());
}
}
});
Map<Integer, Integer> Teampointssortet = Teampoints.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(a , b) -> a,
LinkedHashMap::new
));
sender.prefixless("PLAIN_STRING", fline.toString());
for (Map.Entry<Integer, Integer> entry : Teampointssortet.entrySet()) {
Component finalmessage = sender.parse("EVENT_TEAM_TABLE",Team.byId(entry.getKey()).getTeamColor(), Team.byId(entry.getKey()).getTeamKuerzel(), Team.byId(entry.getKey()).getTeamName(), entry.getValue());
finalmessage = finalmessage.clickEvent(ClickEvent.runCommand("/team info " + Team.byId(entry.getKey()).getTeamName()));
sender.sendMessage(finalmessage);
}
}
@Register
@Register(value = "showfights", description = "EVENT_SHOW_FIGHTS_USAGE")
public void eventShowFightsPage(Chatter sender, Event event, @AllowNull @OptionalValue("1") int page) {
if (!Instant.now().isBefore(event.getEnd().toInstant())) return;
int pagecount = sendEventPage(sender, event, page);
Integer nextpage = page + 1;
Integer prevpage = page - 1;
Component finalmessage;
Component pagenumber = sender.parse("UTIL_LIST_PAGE", page, pagecount);
if (pagecount != 0 && page != 1) {
finalmessage = sender.parse("UTIL_LIST_BACK_ARROW");
finalmessage = finalmessage.clickEvent(ClickEvent.runCommand("/event showfights " + event.getEventName() + " " + prevpage));
finalmessage = finalmessage.append(pagenumber);
} else {
finalmessage = pagenumber;
}
if (pagecount != 0 && pagecount > page) {
Component nextbutton = sender.parse("UTIL_LIST_NEXT");
nextbutton = nextbutton.clickEvent(ClickEvent.runCommand("/event showfights " + event.getEventName() + " " + nextpage));
finalmessage = finalmessage.append(nextbutton);
}
sender.sendMessage(finalmessage);
}
@Register(value = "team", description = "EVENT_TEAM_USAGE")
public void eventWithTeam(@Validator(value = "noEvent", invert = true) PlayerChatter sender, @ErrorMessage("EVENT_NO_TEAM") Team team) {
Subserver eventArena = EventStarter.getEventServer().get(team.getTeamId());
if (eventArena == null || !Subserver.getServerList().contains(eventArena)) {
@@ -122,6 +177,69 @@ public class EventCommand extends SWCommand {
}
}
private int sendEventPage(Chatter sender, Event event, int page) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(sender.parseToPlain("EVENT_DATE_FORMAT"));
Map<String, List<EventFight>> dates = EventFight.getEvent(event.getEventID()).stream().collect(Collectors.groupingBy(p -> p.getStartTime().toLocalDateTime().format(dateTimeFormatter)));
if (dates.size() >= page) {
sender.system("EVENT_CURRENT_EVENT", event.getEventName());
DateTimeFormatter format = DateTimeFormatter.ofPattern(sender.parseToPlain("EVENT_TIME_FORMAT"));
for (EventFight eventFight : dates.get(dates.keySet().toArray()[page - 1])) {
Team blue = Team.byId(eventFight.getTeamBlue());
Team red = Team.byId(eventFight.getTeamRed());
Component finalfightline = sender.parse("EVENT_CURRENT_FIGHT_1", eventFight.getStartTime().toLocalDateTime().format(format), blue.getTeamColor(), blue.getTeamKuerzel());
finalfightline = finalfightline.clickEvent(ClickEvent.runCommand("/team info " + blue.getTeamName()));
Component vs = sender.parse("EVENT_CURRENT_FIGHT_VS");
finalfightline = finalfightline.append(vs);
Component redteam = sender.parse("EVENT_CURRENT_FIGHT_2", red.getTeamColor(), red.getTeamKuerzel());
redteam = redteam.clickEvent(ClickEvent.runCommand("/team info " + red.getTeamName()));
finalfightline = finalfightline.append(redteam);
if (eventFight.hasFinished()) {
Component ergebnis;
switch (eventFight.getErgebnis()) {
case 1:
ergebnis = sender.parse("EVENT_CURRENT_FIGHT_WIN", blue.getTeamColor(), blue.getTeamKuerzel());
break;
case 2:
ergebnis = sender.parse("EVENT_CURRENT_FIGHT_WIN", red.getTeamColor(), red.getTeamKuerzel());
break;
default:
ergebnis = sender.parse("EVENT_CURRENT_FIGHT_DRAW");
}
finalfightline = finalfightline.append(ergebnis);
}
sender.sendMessage(finalfightline);
}
}
return dates.size();
}
protected static TypeMapper<Event> eventTypeMapper() {
return new TypeMapper<>() {
@Override
public Event map(Chatter sender, PreviousArguments previousArguments, String s) {
return Event.get(s);
}
@Override
public Collection<String> tabCompletes(Chatter sender, PreviousArguments previousArguments, String s) {
Set<String> events = new HashSet<>();
List<Event> allevents = Event.getAll();
for (Event event : allevents) {
if (!Instant.now().isAfter(event.getEnd().toInstant())) {
events.add(event.getEventName());
}
}
return events;
}
};
}
@ClassMapper(value = Event.class, local = true)
public TypeMapper<Event> eventMapper() {
return eventTypeMapper();
}
protected static TypeMapper<Team> eventTeam(Function<EventFight, List<Integer>> teamMapper) {
return new TypeMapper<>() {
@Override
@@ -39,22 +39,28 @@ public class TexturePackSystem extends BasicListener {
private static final File PACKS_DIR = new File("/var/www/packs");
private static final String BASE_ULR = "https://packs.steamwar.de/";
private TreeMap<Integer, Integer> protocolVersionToPackVersion = new TreeMap<>();
private TreeMap<Integer, String> protocolVersionToPackVersion = new TreeMap<>();
public TexturePackSystem() {
// https://minecraft.wiki/w/Pack_format#List_of_resource_pack_formats
// https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol_version_numbers
protocolVersionToPackVersion.put(759, 9);
protocolVersionToPackVersion.put(761, 12);
protocolVersionToPackVersion.put(762, 13);
protocolVersionToPackVersion.put(763, 15);
protocolVersionToPackVersion.put(764, 18);
protocolVersionToPackVersion.put(765, 22);
protocolVersionToPackVersion.put(766, 32);
protocolVersionToPackVersion.put(767, 34);
protocolVersionToPackVersion.put(768, 42);
protocolVersionToPackVersion.put(769, 46);
protocolVersionToPackVersion.put(770, 55);
protocolVersionToPackVersion.put(759, "9");
protocolVersionToPackVersion.put(761, "12");
protocolVersionToPackVersion.put(762, "13");
protocolVersionToPackVersion.put(763, "15");
protocolVersionToPackVersion.put(764, "18");
protocolVersionToPackVersion.put(765, "22");
protocolVersionToPackVersion.put(766, "32");
protocolVersionToPackVersion.put(767, "34");
protocolVersionToPackVersion.put(768, "42");
protocolVersionToPackVersion.put(769, "46");
protocolVersionToPackVersion.put(770, "55");
protocolVersionToPackVersion.put(771, "63");
protocolVersionToPackVersion.put(772, "64");
protocolVersionToPackVersion.put(773, "69.0");
protocolVersionToPackVersion.put(774, "75.0");
protocolVersionToPackVersion.put(775, "84.0");
protocolVersionToPackVersion.put(776, "88.0");
}
@Subscribe
@@ -63,20 +69,19 @@ public class TexturePackSystem extends BasicListener {
return;
}
VelocityCore.schedule(() -> {
TreeMap<Integer, File> fileTreeMap = new TreeMap<>();
TreeMap<String, File> fileTreeMap = new TreeMap<>();
for (File fileEntry : PACKS_DIR.listFiles()) {
try {
int packVersion = Integer.parseInt(fileEntry.getName().split("_")[0]);
fileTreeMap.put(packVersion, fileEntry);
fileTreeMap.put(fileEntry.getName().split("_")[0], fileEntry);
} catch (NumberFormatException e) {
// Ignore
}
}
int playerVersion = event.getPlayer().getProtocolVersion().getProtocol();
Map.Entry<Integer, Integer> packVersionEntry = protocolVersionToPackVersion.floorEntry(playerVersion);
Map.Entry<Integer, String> packVersionEntry = protocolVersionToPackVersion.floorEntry(playerVersion);
if (packVersionEntry == null) return;
Map.Entry<Integer, File> selectedPackEntry = fileTreeMap.floorEntry(packVersionEntry.getValue());
Map.Entry<String, File> selectedPackEntry = fileTreeMap.floorEntry(packVersionEntry.getValue());
if (selectedPackEntry == null) return;
File selectedPack = selectedPackEntry.getValue();
+1
View File
@@ -128,6 +128,7 @@ dependencyResolutionManagement {
library("msgpack", "org.msgpack:msgpack-core:0.9.8")
library("logback", "ch.qos.logback:logback-classic:1.5.6")
library("coroutinesCore", "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
val ktorVersion = "2.3.12"