Compare commits

..

4 Commits

Author SHA1 Message Date
D4rkr34lm 99f7610d3d .
Pull Request Build / Build (pull_request) Successful in 1m32s
2026-06-12 19:48:16 +02:00
D4rkr34lm 2c05f06e2b Merge branch 'main' into BauSystem/add-cannon-automation-tool
Pull Request Build / Build (pull_request) Failing after 44s
# Conflicts:
#	BauSystem/BauSystem_Main/build.gradle.kts
2026-06-12 17:21:08 +02:00
D4rkr34lm 9606c6bc0d .
Pull Request Build / Build (pull_request) Successful in 1m19s
2026-06-12 16:50:26 +02:00
D4rkr34lm 34e7c62768 First draft of initial user flow
Pull Request Build / Build (pull_request) Failing after 49s
2026-06-12 13:08:35 +02:00
31 changed files with 418 additions and 1090 deletions
+1 -1
View File
@@ -18,7 +18,7 @@
*/
plugins {
steamwar.java
steamwar.kotlin
widener
}
@@ -22,6 +22,7 @@ package de.steamwar.bausystem;
import de.steamwar.bausystem.config.BauServer;
import de.steamwar.bausystem.configplayer.Config;
import de.steamwar.bausystem.configplayer.ConfigConverter;
import de.steamwar.bausystem.features.cannonCore.CannonCoreRegistrationKt;
import de.steamwar.bausystem.features.gui.BauGUI;
import de.steamwar.bausystem.features.script.lua.SteamWarLuaPlugin;
import de.steamwar.bausystem.features.script.lua.libs.LuaLib;
@@ -135,6 +136,8 @@ public class BauSystem extends JavaPlugin implements Listener {
String identifier = BauServerInfo.getOwnerUser().getUUID().toString().replace("-", "");
WorldIdentifier.set("bau/" + Core.getVersion() + "/" + identifier);
CannonCoreRegistrationKt.register(this);
}
@EventHandler
@@ -17,27 +17,14 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.velocitycore.advancements;
package de.steamwar.bausystem.features.cannonCore
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.bukkit.Location
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URI;
class CannonCore(val location: Location) {
public class Items {
/**
* Loaded from https://github.com/retrooper/packetevents/blob/2.0/mappings/registries/item.json
*/
public static final JsonObject values;
static {
try {
values = new Gson().fromJson(new BufferedReader(new InputStreamReader(URI.create("https://raw.githubusercontent.com/retrooper/packetevents/refs/heads/2.0/mappings/registries/item.json").toURL().openConnection().getInputStream())), JsonObject.class);
} catch (Exception e) {
throw new IllegalStateException(e);
}
companion object Manager {
var activeCores: Observable<List<CannonCore>> = Observable(ArrayList())
}
}
@@ -0,0 +1,35 @@
/*
* 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.bausystem.features.cannonCore
import de.steamwar.bausystem.SWUtils
import de.steamwar.command.SWCommand
import de.steamwar.linkage.Linked
import org.bukkit.entity.Player
object CannonCoreCommand : SWCommand("cannoncore") {
@Register
fun giveCannonCoreWand(player: Player) {
val wandItem = CannonCoreWand.getWandItem()
SWUtils.giveItemToPlayer(player, wandItem)
}
}
@@ -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.bausystem.features.cannonCore
import de.steamwar.entity.RBlockDisplay
import de.steamwar.entity.REntityAction
import de.steamwar.entity.REntityServer
import de.steamwar.entity.RInteraction
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.entity.Player
class CannonCoreEntity: RBlockDisplay {
val entityMaterial = Material.COMMAND_BLOCK
val hitbox: RInteraction
constructor(server: REntityServer, location: Location, onClick: (player: Player, clickAction: REntityAction) -> Unit) : super(server, location) {
setBlock(entityMaterial.createBlockData())
hitbox = RInteraction(server, location)
hitbox.setCallback(onClick)
}
override fun die() {
super.die()
hitbox.die()
}
}
@@ -0,0 +1,29 @@
/*
* 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.bausystem.features.cannonCore
import org.bukkit.plugin.Plugin
fun register(plugin: Plugin) {
CannonCoreCommand.register()
val pluginManager = plugin.server.pluginManager
pluginManager.registerEvents(CannonCoreWand, plugin)
}
@@ -0,0 +1,64 @@
/*
* 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.bausystem.features.cannonCore
import de.steamwar.bausystem.utils.ItemUtils
import de.steamwar.core.SWPlayer
import de.steamwar.inventory.SWItem
import org.bukkit.Material
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.player.PlayerItemHeldEvent
import org.bukkit.inventory.ItemStack
object CannonCoreWand: Listener {
val wandId = "CANNON_CORE_WAND"
val wandMaterial = Material.BREEZE_ROD
fun getWandItem(): ItemStack {
val title = "§eCannon Core Wand"
val lore = listOf(
"§eRight Click §8- §7Create a new cannon core"
)
val wand = SWItem(wandMaterial, title, lore, false, null)
val item = wand.itemStack
return ItemUtils.setItem(item, wandId)
}
fun isWandItem(itemStack: ItemStack): Boolean {
return ItemUtils.isItem(itemStack, wandId)
}
@EventHandler
fun onPlayerEquip(event: PlayerItemHeldEvent) {
val player = event.player
val swPlayer = SWPlayer.of(event.player)
val item = player.inventory.getItem(event.newSlot) ?: return
if(!isWandItem(item)) {
swPlayer.removeComponent(EmptyCannonCoreWandDisplay::class.java)
}
else {
EmptyCannonCoreWandDisplay(player)
}
}
}
@@ -0,0 +1,45 @@
/*
* 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.bausystem.features.cannonCore
import de.steamwar.core.SWPlayer
import de.steamwar.entity.REntityServer
import org.bukkit.entity.Player
class CannonCoresDisplay: SWPlayer.Component {
val displayServer = REntityServer()
val unlisten: () -> Unit
constructor(owner: Player) {
unlisten = CannonCore.activeCores.observe( { cores ->
displayServer.entities.forEach { it.die() }
cores.forEach { CannonCoreEntity(displayServer, it.location) { _, _ -> println("Handler clicked at ${it.location}") } }
})
}
override fun onMount(player: SWPlayer) {
displayServer.addPlayer(player.player)
}
override fun onUnmount(player: SWPlayer?) {
unlisten()
displayServer.close()
}
}
@@ -0,0 +1,49 @@
/*
* 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.bausystem.features.cannonCore
import de.steamwar.core.SWPlayer
import de.steamwar.cursor.Cursor
import org.bukkit.Material
import org.bukkit.entity.Player
class EmptyCannonCoreWandDisplay : SWPlayer.Component {
val coresDisplay: CannonCoresDisplay
val cursor: Cursor
constructor(owner: Player) {
coresDisplay = CannonCoresDisplay(owner)
cursor = Cursor(
coresDisplay.displayServer, owner, Material.GLASS, Material.COMMAND_BLOCK,
listOf(
Cursor.CursorMode.BLOCK_ALIGNED
),
) { location, hitEntity, action ->
print("Hello")
}
SWPlayer.of(owner).setComponent(this)
}
override fun onUnmount(player: SWPlayer) {
player.removeComponent(cursor::class.java)
}
}
@@ -0,0 +1,47 @@
/*
* 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.bausystem.features.cannonCore
typealias Observer<T> = (currentValue: T) -> Unit
class Observable<T>(var value: T) {
private val observers = ArrayList<Observer<T>>()
fun set(value: T) {
val oldValue = this.value
this.value = value
observers.forEach { it.invoke(value) }
}
fun get(): T {
return value
}
fun observe(observer: Observer<T>): () -> Unit {
observers.add(observer)
observer(value)
return {removeObserver(observer)}
}
fun removeObserver(observer: Observer<T>) {
observers.remove(observer)
}
}
@@ -139,7 +139,6 @@ public class NoClipCommand extends SWCommand implements Listener {
@EventHandler(ignoreCancelled = true)
public void onBlock(BlockCanBuildEvent event) {
if (event.getPlayer() == null) return;
if (SWPlayer.of(event.getPlayer()).hasComponent(NoClipData.class)) {
event.setBuildable(true);
}
@@ -20,28 +20,30 @@
package de.steamwar.bausystem.utils;
import de.steamwar.bausystem.SWUtils;
import lombok.experimental.UtilityClass;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
@UtilityClass
public class ItemUtils {
public final class ItemUtils {
private final NamespacedKey ITEM_KEY = SWUtils.getNamespaceKey("bau_item");
private static final NamespacedKey ITEM_KEY = SWUtils.getNamespaceKey("bau_item");
public boolean isItem(ItemStack itemStack, String tag) {
private ItemUtils() {
}
public static boolean isItem(ItemStack itemStack, String tag) {
String value = getTag(itemStack, ITEM_KEY);
return value != null && value.equals(tag);
}
public void setItem(ItemStack itemStack, String tag) {
public static ItemStack setItem(ItemStack itemStack, String tag) {
setTag(itemStack, ITEM_KEY, tag);
return itemStack;
}
public String getTag(ItemStack itemStack, NamespacedKey key) {
public static String getTag(ItemStack itemStack, NamespacedKey key) {
if (itemStack == null) {
return null;
}
@@ -56,7 +58,7 @@ public class ItemUtils {
return container.get(key, PersistentDataType.STRING);
}
public void setTag(ItemStack itemStack, NamespacedKey key, String value) {
public static void setTag(ItemStack itemStack, NamespacedKey key, String value) {
if (itemStack == null) {
return;
}
+1
View File
@@ -38,4 +38,5 @@ tasks.register<DevServer>("DevBau21") {
dependsOn(":BauSystem:shadowJar")
dependsOn(":SchematicSystem:shadowJar")
template = "Bau21"
debug = true
}
@@ -86,24 +86,6 @@ class CheckedSchematic(id: EntityID<CompositeID>) : CompositeEntity(id) {
useDb {
find { (CheckedSchematicTable.nodeOwner eq owner.id) and (CheckedSchematicTable.seen eq false) }.orderBy(CheckedSchematicTable.endTime to SortOrder.DESC).toList()
}
@JvmStatic
fun countAccepted(owner: SteamwarUser) =
useDb {
find { (CheckedSchematicTable.nodeOwner eq owner.id) and (CheckedSchematicTable.declineReason eq "freigegeben") }.count()
}
@JvmStatic
fun countAccepted(owner: SteamwarUser, type: String) =
useDb {
find { (CheckedSchematicTable.nodeOwner eq owner.id) and (CheckedSchematicTable.declineReason eq "freigegeben") and (CheckedSchematicTable.nodeType like "$type%") }.count()
}
@JvmStatic
fun countChecked(validator: SteamwarUser) =
useDb {
find { CheckedSchematicTable.validator eq validator.id }.count()
}
}
val node by CheckedSchematicTable.nodeId.transform({ it?.let { EntityID(it, SchematicNodeTable) } }, { it?.value })
@@ -130,43 +130,6 @@ class EventFight(id: EntityID<Int>) : IntEntity(id), Comparable<EventFight> {
}
)
}
@JvmStatic
fun countEventFights(fighter: SteamwarUser) =
useDb {
exec(
"SELECT COUNT(DISTINCT F.FightID) AS FightCount FROM FightPlayer INNER JOIN Fight F on FightPlayer.FightID = F.FightID INNER JOIN EventFight EF on F.FightID = EF.Fight WHERE UserID = ?",
args = listOf(IntegerColumnType() to fighter.id.value)
) {
if (it.next()) {
it.getLong("FightCount")
} else {
0
}
}
?: 0
}
@JvmStatic
fun countPlacement(fighter: SteamwarUser, placement: Int) =
useDb {
exec(
"""
SELECT COUNT(DISTINCT EventFight.EventID) AS PlacementCount FROM TeamTeilnahme
INNER JOIN EventFight ON EventFight.EventID = TeamTeilnahme.EventID
INNER JOIN FightPlayer ON FightPlayer.FightID = EventFight.Fight
WHERE (IF(FightPlayer.Team = 1, EventFight.TeamBlue, EventFight.TeamRed)) = TeamTeilnahme.TeamID AND UserID = ? AND Placement = ?
""".trimIndent(),
args = listOf(IntegerColumnType() to fighter.id.value, IntegerColumnType() to placement)
) {
if (it.next()) {
it.getInt("PlacementCount")
} else {
0
}
}
?: 0
}
}
val fightID by EventFightTable.id.transform({ EntityID(it, EventFightTable) }, { it.value })
@@ -20,12 +20,9 @@
package de.steamwar.sql
import de.steamwar.sql.internal.useDb
import org.jetbrains.exposed.v1.core.IntegerColumnType
import org.jetbrains.exposed.v1.core.VarCharColumnType
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.inList
import org.jetbrains.exposed.v1.dao.CompositeEntity
import org.jetbrains.exposed.v1.dao.CompositeEntityClass
@@ -72,28 +69,6 @@ class FightPlayer(id: EntityID<CompositeID>) : CompositeEntity(id) {
useDb {
find { FightPlayerTable.fightId inList fightIds.toList() }.toList()
}
@JvmStatic
fun countFights(userId: Int) =
useDb {
find { FightPlayerTable.userId eq userId }.count()
}
@JvmStatic
fun countFights(userId: Int, type: String) =
useDb {
exec(
"SELECT COUNT(*) AS FightCount FROM FightPlayer INNER JOIN Fight F on FightPlayer.FightID = F.FightID WHERE UserID = ? AND GameMode LIKE ?",
args = listOf(IntegerColumnType() to userId, VarCharColumnType() to "$type%")
) {
if (it.next()) {
it.getInt("FightCount")
} else {
0
}
}
?: 0
}
}
val fightID by FightPlayerTable.fightId.transform({ EntityID(it, FightTable) }, { it.value })
@@ -146,12 +146,12 @@ public final class GameModeConfig<M, W> {
public final List<String> CheckQuestions;
/**
* The allowed checkers to check this schematic type denoted by a list of SteamwarUser ids.
* The allowed checkers to check this schematic type denoted by a list of SteamWar ids.
* The people need the {@link UserPerm#CHECK} to be able to check though.
*
* @implSpec {@code []} by default -> denoting every person with {@link UserPerm#CHECK} can check it
*/
public final Set<Integer> Checkers;
public final List<Integer> Checkers;
/**
* Bundle for countdowns during the fight
@@ -246,7 +246,7 @@ public final class GameModeConfig<M, W> {
}
CheckQuestions = loader.getStringList("CheckQuestions");
Checkers = loader.getIntSet("Checkers");
Checkers = loader.getIntList("Checkers");
Times = new TimesConfig(loader.with("Times"));
// Arena would be here to be in config order but needs Schematic.Size and EnterStages loaded afterwards
Schematic = new SchematicConfig<>(loader.with("Schematic"));
@@ -139,12 +139,6 @@ final class YMLWrapper<M, W> {
return get(path, o -> (List<Integer>) o);
}
public Set<Integer> getIntSet(String path) {
List<Integer> list = get(path, o -> (List<Integer>) o);
if (list.isEmpty()) return Collections.emptySet();
return Collections.unmodifiableSet(new HashSet<>(list));
}
public List<SchematicType> getSchematicTypeList(String path) {
List<String> list = getStringList(path);
if (list.isEmpty()) {
@@ -42,10 +42,7 @@ import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.Month;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
public class CustomMap implements Listener {
@@ -59,7 +56,7 @@ public class CustomMap implements Listener {
new Vector(2346, 45, 1297), new Vector(2345, 45, 1297), new Vector(2344, 45, 1297), new Vector(2343, 45, 1297), new Vector(2342, 45, 1297), new Vector(2341, 45, 1297), new Vector(2340, 45, 1297)
);
private static final CustomMap RIGHT = new CustomMap(new File(System.getProperty("user.home") + "/lobbyBanner/right/"),
private static final CustomMap RIGHT = new CustomMap(new File(System.getProperty("user.home") + "/lobbyBanner/right.png"),
new Vector(2330, 48, 1297), new Vector(2329, 48, 1297), new Vector(2328, 48, 1297), new Vector(2327, 48, 1297), new Vector(2326, 48, 1297), new Vector(2325, 48, 1297), new Vector(2324, 48, 1297),
new Vector(2330, 47, 1297), new Vector(2329, 47, 1297), new Vector(2328, 47, 1297), new Vector(2327, 47, 1297), new Vector(2326, 47, 1297), new Vector(2325, 47, 1297), new Vector(2324, 47, 1297),
new Vector(2330, 46, 1297), new Vector(2329, 46, 1297), new Vector(2328, 46, 1297), new Vector(2327, 46, 1297), new Vector(2326, 46, 1297), new Vector(2325, 46, 1297), new Vector(2324, 46, 1297),
@@ -69,49 +66,30 @@ public class CustomMap implements Listener {
private File mapFile;
private Map<Vector, Integer> itemFrameIndex = new HashMap<>();
private ItemFrame[] itemFrames;
private boolean update = true;
private long lastModified = Long.MAX_VALUE;
public CustomMap(File mapFileOrDirectory, Vector... itemFrames) {
this.mapFile = mapFileOrDirectory;
public CustomMap(File mapFile, Vector... itemFrames) {
this.mapFile = mapFile;
this.itemFrames = new ItemFrame[itemFrames.length];
for (int i = 0; i < itemFrames.length; i++) {
itemFrameIndex.put(itemFrames[i], i);
}
if (mapFileOrDirectory.isDirectory()) {
AtomicReference<Month> lastMonth = new AtomicReference<>(LocalDateTime.now().getMonth());
Bukkit.getScheduler().runTaskTimer(LobbySystem.getInstance(), () -> {
Month current = LocalDateTime.now().getMonth();
if (!current.equals(lastMonth.get()) || update) {
lastMonth.set(current);
update = false;
this.mapFile = new File(mapFileOrDirectory, current.getValue() + ".png");
update();
}
}, 200L, 1200L);
} else {
AtomicReference<Long> lastModified = new AtomicReference<>(Long.MAX_VALUE);
Bukkit.getScheduler().runTaskTimer(LobbySystem.getInstance(), () -> {
long modified = mapFileOrDirectory.lastModified();
if (modified > lastModified.get() || update) {
lastModified.set(modified);
update = false;
update();
}
}, 200L, 200L);
}
Bukkit.getPluginManager().registerEvents(this, LobbySystem.getInstance());
}
private void update() {
System.out.println("Updating Banner: " + mapFile.getName());
Bukkit.getScheduler().runTaskAsynchronously(LobbySystem.getInstance(), () -> {
try {
run();
} catch (IOException e) {
// Ignore
Bukkit.getScheduler().runTaskTimer(LobbySystem.getInstance(), () -> {
long modified = mapFile.lastModified();
if (modified > lastModified) {
lastModified = modified;
System.out.println("Updating Banner: " + mapFile.getName());
Bukkit.getScheduler().runTaskAsynchronously(LobbySystem.getInstance(), () -> {
try {
run();
} catch (IOException e) {
// Ignore
}
});
}
});
}, 200L, 200L);
Bukkit.getPluginManager().registerEvents(this, LobbySystem.getInstance());
}
@EventHandler
@@ -123,7 +101,7 @@ public class CustomMap implements Listener {
if (itemFrameIndex.containsKey(vector)) {
if (itemFrames[itemFrameIndex.get(vector)] != null) continue;
itemFrames[itemFrameIndex.get(vector)] = itemFrame;
update = true;
lastModified = 0;
ItemStack itemStack = new ItemStack(Material.FILLED_MAP, 1);
MapMeta mapMeta = (MapMeta) itemStack.getItemMeta();
+1 -11
View File
@@ -29,15 +29,5 @@ dependencies {
compileOnly(libs.paperapi)
compileOnly(libs.nms)
compileOnly(libs.fawe)
}
tasks.register<FightServer>("MissileWars21") {
group = "run"
description = "Run a 1.21 Dev MissileWars"
dependsOn(":SpigotCore:shadowJar")
dependsOn(":MissileWars:jar")
template = "MissileWars"
worldName = "Great_Wall"
jar = "/jars/paper-1.21.6.jar"
compileOnly(libs.worldedit)
}
@@ -30,8 +30,6 @@ import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockTypes;
import de.steamwar.misslewars.MissileWars;
@@ -111,17 +109,11 @@ public class Missile extends SpecialItem {
v = aT.apply(v.toVector3()).toBlockPoint();
v = v.add(location.getBlockX(), location.getBlockY(), location.getBlockZ());
EditSession e = WorldEdit.getInstance().getEditSessionFactory()
.getEditSession(world, -1);
e.setSideEffectApplier(SideEffectSet.defaults()
.with(SideEffect.NEIGHBORS, SideEffect.State.ON)
.with(SideEffect.LIGHTING, SideEffect.State.ON)
.with(SideEffect.UPDATE, SideEffect.State.ON));
EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, -1);
ClipboardHolder ch = new ClipboardHolder(clipboard);
ch.setTransform(aT);
Operations.completeBlindly(ch.createPaste(e).to(v).ignoreAirBlocks(true).build());
e.flushSession();
return true;
}
@@ -37,27 +37,17 @@ public class AutoChecker {
public static final AutoChecker impl = new AutoChecker();
public AutoCheckerResult check(Clipboard clipboard, GameModeConfig<Material, String> type) {
return AutoCheckerResult.builder()
.type(type)
.height(clipboard.getDimensions().y())
.width(clipboard.getDimensions().x())
.depth(clipboard.getDimensions().z())
.blockScanResult(scan(clipboard, type))
.entities(
clipboard.getEntities().stream()
.map(Entity::getLocation)
.map(blockVector3 -> new BlockPos(blockVector3.getBlockX(), blockVector3.getBlockY(), blockVector3.getBlockZ()))
.collect(Collectors.toList()))
return AutoCheckerResult.builder().type(type).height(clipboard.getDimensions().x()).width(clipboard.getDimensions().x())
.depth(clipboard.getDimensions().z()).blockScanResult(scan(clipboard, type))
.entities(clipboard.getEntities().stream().map(Entity::getLocation)
.map(blockVector3 -> new BlockPos(blockVector3.getBlockX(), blockVector3.getBlockY(), blockVector3.getBlockZ()))
.collect(Collectors.toList()))
.build();
}
public AutoCheckerResult sizeCheck(Clipboard clipboard, GameModeConfig<Material, String> type) {
return AutoCheckerResult.builder()
.type(type)
.height(clipboard.getDimensions().y())
.width(clipboard.getDimensions().x())
.depth(clipboard.getDimensions().z())
.build();
return AutoCheckerResult.builder().type(type).height(clipboard.getDimensions().y()).width(clipboard.getDimensions().x())
.depth(clipboard.getDimensions().z()).build();
}
public AutoChecker.BlockScanResult scan(Clipboard clipboard, GameModeConfig<Material, String> type) {
@@ -20,7 +20,6 @@
package de.steamwar.command;
import com.velocitypowered.api.command.SimpleCommand;
import com.velocitypowered.api.command.SimpleCommand.Invocation;
import de.steamwar.messages.Chatter;
import de.steamwar.messages.Message;
import de.steamwar.sql.UserPerm;
@@ -92,15 +91,11 @@ public class SWCommand extends AbstractSWCommand<Chatter> {
@Override
public boolean hasPermission(Invocation invocation) {
return SWCommand.this.hasPermission(invocation);
return permission == null || Chatter.of(invocation.source()).user().perms().contains(permission);
}
};
}
protected boolean hasPermission(Invocation invocation) {
return permission == null || Chatter.of(invocation.source()).user().perms().contains(permission);
}
@Override
public void unregister() {
if (command == null) return;
@@ -201,8 +201,8 @@ public class ServerStarter {
private void tempWorld(String template) {
worldDir = TEMP_WORLD_PATH;
worldSetup = () -> copyWorld(node, template, new File(worldDir, worldName).getPath());
worldCleanup = () -> SubserverSystem.deleteFolder(node, new File(worldDir, worldName).getPath());
worldSetup = () -> copyWorld(node, template, worldDir + worldName);
worldCleanup = () -> SubserverSystem.deleteFolder(node, worldDir + worldName);
}
private void buildWithTemp(Player owner) {
@@ -396,4 +396,4 @@ public class ServerStarter {
}
}
}
}
@@ -1,340 +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.velocitycore.advancements;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
import de.steamwar.messages.Chatter;
import de.steamwar.sql.SteamwarUser;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import net.kyori.adventure.text.Component;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
@RequiredArgsConstructor
public class Advancement {
protected static final Map<SteamwarUser, Map<Advancement.Value.Key, Advancement.Value>> values = new HashMap<>();
{
Advancements.all.add(this);
}
protected final Map<SteamwarUser, Advancement.Data> data = new HashMap<>();
protected final Map<SteamwarUser, Advancement.Value> value = new HashMap<>();
public Advancement.Data get(SteamwarUser user) {
return get(user, Data::new);
}
public Advancement.Data get(SteamwarUser user, BiFunction<Advancement, SteamwarUser, Data> function) {
if (data.containsKey(user)) return data.get(user);
return function.apply(this, user);
}
private final String identifier;
private final Optional<Advancement> parent;
private final Display display;
private final HidePolicy hidePolicy;
private final int total;
private final Function<SteamwarUser, Integer> progressCalculator;
@Override
public String toString() {
StringBuilder st = new StringBuilder();
st.append("Advancement(");
parent.ifPresent(advancement -> st.append(advancement.identifier).append("<-"));
st.append(identifier);
st.append(", total=").append(total);
st.append(")");
return st.toString();
}
@RequiredArgsConstructor
@AllArgsConstructor
public static class Display {
private final Component title;
private final Component description;
private final String item;
private final FrameType frameType;
private Optional<String> background = Optional.empty();
private final float xCoord;
private final float yCoord;
public enum FrameType {
TASK,
CHALLENGE,
GOAL
}
}
public enum HidePolicy {
NEVER {
@Override
public boolean hidden(Data data) {
return false;
}
},
NO_PROGRESS {
@Override
public boolean hidden(Data data) {
return data.progress == 0;
}
},
PREVIOUS_UNFINISHED {
@Override
public boolean hidden(Data data) {
if (data.advancement.parent.isPresent()) {
Advancement parent = data.advancement.parent.get();
Advancement.Data parentData = parent.get(data.user);
return parentData.progress != parentData.advancement.total;
} else {
return false;
}
}
},
WITH_PREVIOUS {
@Override
public boolean hidden(Data data) {
if (data.advancement.parent.isPresent()) {
Advancement parent = data.advancement.parent.get();
Advancement.Data parentData = parent.get(data.user);
return parentData.hidden;
} else {
return false;
}
}
},
;
public abstract boolean hidden(Data data);
}
public static class Value<T extends Number> {
@AllArgsConstructor
public static class Key<T extends Number> {
public static final List<Key> keys = new ArrayList<>();
{
keys.add(this);
}
private final Function<SteamwarUser, T> valueFunction;
private Advancement.Value get(SteamwarUser user) {
Key self = this;
return values.computeIfAbsent(user, __ -> new HashMap<>()).computeIfAbsent(self, __ -> {
Value data = new Advancement.Value();
data.update(user, self);
return data;
});
}
public Function<SteamwarUser, Integer> max(int neededValue) {
return user -> {
double value = get(user).value.doubleValue();
if (value > neededValue) return Math.min(neededValue, 100);
return (int) (value / Math.max(neededValue / 100.0, 1));
};
}
public Function<SteamwarUser, Integer> reached(int neededValue) {
return user -> {
double value = get(user).value.doubleValue();
return value >= neededValue ? 1 : 0;
};
}
}
@Getter
private T value;
public void update(SteamwarUser user, Key<T> key) {
this.value = key.valueFunction.apply(user);
}
}
@ToString
public static class Data {
private final Advancement advancement;
private final SteamwarUser user;
private int progress;
private boolean showToast = true;
private boolean hidden = false;
public Data(Advancement advancement, SteamwarUser user) {
this.advancement = advancement;
advancement.data.put(user, this);
this.user = user;
this.progress = advancement.progressCalculator.apply(user);
checkHidden();
checkFinished();
new Packet(this, showToast).send();
}
public Data(Advancement advancement, SteamwarUser user, int progress) {
this.advancement = advancement;
advancement.data.put(user, this);
this.user = user;
this.progress = progress;
checkHidden();
checkFinished();
new Packet(this, showToast).send();
}
public void update() {
this.progress = advancement.progressCalculator.apply(user);
checkHidden();
new Packet(this, showToast).send();
// Update Advancements that have this as parent
Advancements.getAll()
.stream()
.filter(advancement -> advancement.parent.filter(value -> value == this.advancement).isPresent())
.map(advancement -> advancement.get(user))
.forEach(Advancement.Data::update);
checkFinished();
}
private void checkHidden() {
hidden = advancement.hidePolicy.hidden(this);
}
private void checkFinished() {
if (progress == advancement.total) {
showToast = false;
}
}
private void encodeAdvancement(ByteBuf byteBuf, ProtocolVersion protocolVersion, boolean showToast) {
ProtocolUtils.writeString(byteBuf, advancement.identifier);
if (advancement.parent.isPresent()) {
byteBuf.writeBoolean(true);
ProtocolUtils.writeString(byteBuf, advancement.parent.get().identifier);
} else {
byteBuf.writeBoolean(false);
}
{ // Display
byteBuf.writeBoolean(true);
new ComponentHolder(protocolVersion, advancement.display.title).write(byteBuf);
new ComponentHolder(protocolVersion, advancement.display.description).write(byteBuf);
{ // Slot
ProtocolUtils.writeVarInt(byteBuf, 1);
int itemId = Items.values
.get(protocolVersion.name().replace("MINECRAFT_", "V_"))
.getAsJsonObject()
.get(advancement.display.item)
.getAsInt();
ProtocolUtils.writeVarInt(byteBuf, itemId);
ProtocolUtils.writeVarInt(byteBuf, 0);
ProtocolUtils.writeVarInt(byteBuf, 0);
}
ProtocolUtils.writeVarInt(byteBuf, advancement.display.frameType.ordinal());
if (advancement.display.background.isPresent()) {
byteBuf.writeInt(0x01 | (showToast ? 0x02 : 0x00) | (hidden ? 0x04 : 0x00));
ProtocolUtils.writeString(byteBuf, advancement.display.background.get());
} else {
byteBuf.writeInt((showToast ? 0x02 : 0x00) | (hidden ? 0x04 : 0x00));
}
byteBuf.writeFloat(advancement.display.xCoord);
byteBuf.writeFloat(advancement.display.yCoord);
}
ProtocolUtils.writeVarInt(byteBuf, advancement.total);
for (int i = 0; i < advancement.total; i++) {
ProtocolUtils.writeVarInt(byteBuf, 1);
ProtocolUtils.writeString(byteBuf, advancement.identifier + "_" + i);
}
byteBuf.writeBoolean(false); // No Telemetry
}
private void encodeProgress(ByteBuf byteBuf) {
ProtocolUtils.writeString(byteBuf, this.advancement.identifier);
ProtocolUtils.writeVarInt(byteBuf, advancement.total);
for (int i = 0; i < advancement.total; i++) {
ProtocolUtils.writeString(byteBuf, advancement.identifier + "_" + i);
if (i == advancement.total - 1 && advancement.total == progress) {
byteBuf.writeBoolean(true);
byteBuf.writeLong(new Date().getTime());
} else if (i < progress) {
byteBuf.writeBoolean(true);
byteBuf.writeLong(0);
} else {
byteBuf.writeBoolean(false);
}
}
}
}
protected record Packet(Data data, boolean showToast) implements MinecraftPacket {
public void send() {
Player player = Chatter.of(data.user).getPlayer();
((ConnectedPlayer) player).getConnection().write(this);
}
@Override
public void decode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
throw new UnsupportedOperationException();
}
@Override
public void encode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
byteBuf.writeBoolean(false); // Clear
if (!data.hidden) {
ProtocolUtils.writeVarInt(byteBuf, 1);
data.encodeAdvancement(byteBuf, protocolVersion, showToast);
ProtocolUtils.writeVarInt(byteBuf, 0); // No Advancements to remove
ProtocolUtils.writeVarInt(byteBuf, 1);
data.encodeProgress(byteBuf);
} else {
ProtocolUtils.writeVarInt(byteBuf, 0); // No Advancements to update
ProtocolUtils.writeVarInt(byteBuf, 1);
ProtocolUtils.writeString(byteBuf, data.advancement.identifier);
ProtocolUtils.writeVarInt(byteBuf, 0); // No Advancements Progress to update
}
byteBuf.writeBoolean(true); // Show Advancements
}
@Override
public boolean handle(MinecraftSessionHandler minecraftSessionHandler) {
return false;
}
}
}
@@ -1,315 +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.velocitycore.advancements;
import de.steamwar.messages.Chatter;
import de.steamwar.persistent.Storage;
import de.steamwar.sql.CheckedSchematic;
import de.steamwar.sql.EventFight;
import de.steamwar.sql.FightPlayer;
import lombok.Getter;
import lombok.experimental.UtilityClass;
import net.kyori.adventure.text.Component;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@UtilityClass
public class Advancements {
@Getter
static final List<Advancement> all = new ArrayList<>();
@Getter
private static final List<Advancement> playtime = new ArrayList<>();
public static final Advancement.Value.Key<Double> PLAY_TIME_KEY = new Advancement.Value.Key<>(user -> {
double playtime = user.getOnlinetime();
playtime += Instant.now().getEpochSecond() - Storage.sessions.get(Chatter.of(user).getPlayer()).toInstant().getEpochSecond();
playtime /= 60d * 60d;
return playtime;
});
public static final Advancement.Value.Key<Long> FIGHT_COUNT = new Advancement.Value.Key<>(user -> {
return FightPlayer.countFights(user.getId());
});
public static final Advancement.Value.Key<Integer> FIGHT_COUNT_WAR_GEAR = new Advancement.Value.Key<>(user -> {
return FightPlayer.countFights(user.getId(), "WarGear");
});
public static final Advancement.Value.Key<Integer> FIGHT_COUNT_MINI_WAR_GEAR = new Advancement.Value.Key<>(user -> {
return FightPlayer.countFights(user.getId(), "MiniWarGear");
});
public static final Advancement.Value.Key<Integer> FIGHT_COUNT_WAR_SHIP = new Advancement.Value.Key<>(user -> {
return FightPlayer.countFights(user.getId(), "WarShip");
});
public static final Advancement.Value.Key<Long> EVENT_FIGHT_COUNT = new Advancement.Value.Key<>(user -> {
return EventFight.countEventFights(user);
});
public static final Advancement.Value.Key<Integer> EVENT_FIGHT_FIRST_PLACE_COUNT = new Advancement.Value.Key<>(user -> {
return EventFight.countPlacement(user, 1);
});
public static final Advancement.Value.Key<Integer> EVENT_FIGHT_SECOND_PLACE_COUNT = new Advancement.Value.Key<>(user -> {
return EventFight.countPlacement(user, 2);
});
public static final Advancement.Value.Key<Integer> EVENT_FIGHT_THIRDPLACE_COUNT = new Advancement.Value.Key<>(user -> {
return EventFight.countPlacement(user, 3);
});
public static final Advancement.Value.Key<Long> CHECKED_SCHEMATIC_COUNT = new Advancement.Value.Key<>(user -> {
return CheckedSchematic.countChecked(user);
});
public static final Advancement.Value.Key<Long> ACCEPTED_SCHEMATIC_COUNT = new Advancement.Value.Key<>(user -> {
return CheckedSchematic.countAccepted(user);
});
public static final Advancement.Value.Key<Long> ACCEPTED_SCHEMATIC_COUNT_WAR_GEAR = new Advancement.Value.Key<>(user -> {
return CheckedSchematic.countAccepted(user, "WarGear");
});
public static final Advancement.Value.Key<Long> ACCEPTED_SCHEMATIC_COUNT_MINI_WAR_GEAR = new Advancement.Value.Key<>(user -> {
return CheckedSchematic.countAccepted(user, "MiniWarGear");
});
public static final Advancement.Value.Key<Long> ACCEPTED_SCHEMATIC_COUNT_WAR_SHIP = new Advancement.Value.Key<>(user -> {
return CheckedSchematic.countAccepted(user, "WarShip");
});
public static final Advancement ROOT = new Advancement(
"steamwar:advancements/root",
Optional.empty(),
new Advancement.Display(
Component.text("SteamWar"),
Component.text("Join SteamWar for the first time!"),
"cactus_flower",
Advancement.Display.FrameType.CHALLENGE,
Optional.of("minecraft:gui/advancements/backgrounds/adventure"),
0f,
3f
),
Advancement.HidePolicy.NEVER,
1,
user -> 1
);
static {
Advancement previous = ROOT;
int[] playTimes = new int[]{1, 10, 100, 500, 1000, 2500, 5000, 7500, 10000, 15000, 20000};
for (int i = 0; i < playTimes.length; i++) {
int neededPlayTime = playTimes[i];
previous = new Advancement(
"steamwar:advancements/playtime_" + neededPlayTime + "_hour",
Optional.of(previous),
new Advancement.Display(
Component.text("Play " + neededPlayTime + " Hour" + (neededPlayTime > 1 ? "s" : "")),
Component.text("Play " + neededPlayTime + " hour" + (neededPlayTime > 1 ? "s" : "") + " on SteamWar"),
"clock",
Advancement.Display.FrameType.TASK,
i + 1f,
3f
),
Advancement.HidePolicy.PREVIOUS_UNFINISHED,
Math.min(neededPlayTime, 100),
PLAY_TIME_KEY.max(neededPlayTime)
);
playtime.add(previous);
}
}
static {
Advancement previous = ROOT;
int[] fightCounts = new int[]{1, 10, 50, 100, 200, 500, 1000, 2500, 5000, 7500, 10000, 15000, 20000};
for (int i = 0; i < fightCounts.length; i++) {
int fightCount = fightCounts[i];
previous = new Advancement(
"steamwar:advancements/fights_" + fightCount,
Optional.of(previous),
new Advancement.Display(
Component.text(fightCount + " Fight" + (fightCount > 1 ? "s" : "")),
Component.text(fightCount + " Fight" + (fightCount > 1 ? "s" : "")),
"iron_sword",
Advancement.Display.FrameType.TASK,
i + 1f,
4f
),
Advancement.HidePolicy.PREVIOUS_UNFINISHED,
Math.min(fightCount, 100),
FIGHT_COUNT.max(fightCount)
);
if (i == 0) {
fightsPerType(previous, 5f, "WarGear", FIGHT_COUNT_WAR_GEAR, "stone_bricks");
fightsPerType(previous, 6f, "MiniWarGear", FIGHT_COUNT_MINI_WAR_GEAR, "stone_brick_slab");
fightsPerType(previous, 7f, "WarShip", FIGHT_COUNT_WAR_SHIP, "dark_oak_boat");
}
}
}
private static void fightsPerType(Advancement previous, float yCoord, String type, Advancement.Value.Key<Integer> typeKey, String item) {
int[] fightCounts = new int[]{1, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000};
for (int i = 0; i < fightCounts.length; i++) {
int fightCount = fightCounts[i];
previous = new Advancement(
"steamwar:advancements/fights_" + type + "_" + fightCount,
Optional.of(previous),
new Advancement.Display(
Component.text(type + " " + fightCount + " Fight" + (fightCount > 1 ? "s" : "")),
Component.text(type + " " + fightCount + " Fight" + (fightCount > 1 ? "s" : "")),
item,
Advancement.Display.FrameType.TASK,
i + 2f,
yCoord
),
i == 0 ? Advancement.HidePolicy.WITH_PREVIOUS : Advancement.HidePolicy.PREVIOUS_UNFINISHED,
Math.min(fightCount, 100),
typeKey.max(fightCount)
);
}
}
static {
Advancement previous = ROOT;
int[] eventFightCounts = new int[]{1, 5, 10, 15, 25, 50, 100, 150, 200, 250};
for (int i = 0; i < eventFightCounts.length; i++) {
int eventFightCount = eventFightCounts[i];
previous = new Advancement(
"steamwar:advancements/event_fights_" + eventFightCount,
Optional.of(previous),
new Advancement.Display(
Component.text(eventFightCount + " Event-Fight" + (eventFightCount > 1 ? "s" : "")),
Component.text(eventFightCount + " Event-Fight" + (eventFightCount > 1 ? "s" : "")),
"golden_sword",
Advancement.Display.FrameType.TASK,
i + 1f,
8f
),
Advancement.HidePolicy.PREVIOUS_UNFINISHED,
Math.min(eventFightCount, 100),
EVENT_FIGHT_COUNT.max(eventFightCount)
);
if (i == 0) {
placementsCounts(previous, 9f, 1, "gold_block", EVENT_FIGHT_FIRST_PLACE_COUNT, Advancement.Display.FrameType.CHALLENGE);
placementsCounts(previous, 10f, 2, "iron_block", EVENT_FIGHT_SECOND_PLACE_COUNT, Advancement.Display.FrameType.GOAL);
placementsCounts(previous, 11f, 3, "copper_block", EVENT_FIGHT_THIRDPLACE_COUNT, Advancement.Display.FrameType.TASK);
}
}
}
private static void placementsCounts(Advancement previous, float yCoord, int placement, String item, Advancement.Value.Key<Integer> typeKey, Advancement.Display.FrameType frameType) {
for (int placementCount = 1; placementCount <= 10; placementCount++) {
int finalPlacementCount = placementCount;
previous = new Advancement(
"steamwar:advancements/event_placement_" + placement + "_" + placementCount,
Optional.of(previous),
new Advancement.Display(
Component.text(placementCount + "x " + placement + ". Place in Event"),
Component.text(""),
item,
frameType,
2f + (placementCount - 1f),
yCoord
),
placementCount == 1 ? Advancement.HidePolicy.WITH_PREVIOUS : Advancement.HidePolicy.PREVIOUS_UNFINISHED,
1,
typeKey.reached(placementCount)
);
}
}
static {
Advancement previous = ROOT;
int[] checkedCounts = new int[]{1, 10, 100, 250, 500, 750, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000};
for (int i = 0; i < checkedCounts.length; i++) {
int checkedCount = checkedCounts[i];
previous = new Advancement(
"steamwar:advancements/checked_" + checkedCount,
Optional.of(previous),
new Advancement.Display(
Component.text(checkedCount + " Check Session" + (checkedCount > 1 ? "s" : "")),
Component.text(checkedCount + " Check Session" + (checkedCount > 1 ? "s" : "")),
"paper",
Advancement.Display.FrameType.TASK,
i + 1f,
0f
),
i == 0 ? Advancement.HidePolicy.NO_PROGRESS : Advancement.HidePolicy.PREVIOUS_UNFINISHED,
Math.min(checkedCount, 100),
CHECKED_SCHEMATIC_COUNT.max(checkedCount)
);
}
}
static {
Advancement previous = ROOT;
int[] acceptedCounts = new int[]{1, 5, 10, 15, 25, 50, 100, 150, 200, 250, 500, 750, 1000};
for (int i = 0; i < acceptedCounts.length; i++) {
int acceptedCount = acceptedCounts[i];
previous = new Advancement(
"steamwar:advancements/accepted_" + acceptedCount,
Optional.of(previous),
new Advancement.Display(
Component.text(acceptedCount + " Accepted Schematic" + (acceptedCount > 1 ? "s" : "")),
Component.text(acceptedCount + " Accepted Schematic" + (acceptedCount > 1 ? "s" : "")),
"cauldron",
Advancement.Display.FrameType.TASK,
i + 1f,
2f
),
Advancement.HidePolicy.PREVIOUS_UNFINISHED,
Math.min(acceptedCount, 100),
ACCEPTED_SCHEMATIC_COUNT.max(acceptedCount)
);
if (i == 0) {
acceptedPerType(previous, 2f, "WarGear", ACCEPTED_SCHEMATIC_COUNT_WAR_GEAR, "end_stone_bricks");
acceptedPerType(previous, 3f, "MiniWarGear", ACCEPTED_SCHEMATIC_COUNT_MINI_WAR_GEAR, "end_stone_brick_slab");
acceptedPerType(previous, 4f, "WarShip", ACCEPTED_SCHEMATIC_COUNT_WAR_SHIP, "oak_boat");
}
}
}
private static void acceptedPerType(Advancement previous, float xCoord, String type, Advancement.Value.Key<Long> typeKey, String item) {
new Advancement(
"steamwar:advancements/accepted_" + type,
Optional.of(previous),
new Advancement.Display(
Component.text(type + " Accepted"),
Component.text(""),
item,
Advancement.Display.FrameType.GOAL,
xCoord,
1f
),
Advancement.HidePolicy.WITH_PREVIOUS,
1,
typeKey.reached(1)
);
}
}
@@ -1,99 +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.velocitycore.advancements;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.DisconnectEvent;
import com.velocitypowered.api.event.connection.PostLoginEvent;
import com.velocitypowered.api.event.player.ServerPostConnectEvent;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.StateRegistry;
import de.steamwar.linkage.Linked;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.velocitycore.listeners.BasicListener;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import java.lang.reflect.Field;
import java.util.Optional;
@Linked
public class AdvancementsManager extends BasicListener {
private static SelectAdvancementTabPacket selectAdvancementTabPacket;
static {
selectAdvancementTabPacket = new SelectAdvancementTabPacket(Optional.of("steamwar:advancements/root"));
registerPacketId(ProtocolVersion.MINECRAFT_1_21_9, 0x53, 0x80);
registerPacketId(ProtocolVersion.MINECRAFT_1_21_7, 0x4E, 0x7B);
registerPacketId(ProtocolVersion.MINECRAFT_1_21_6, 0x4E, 0x7B);
registerPacketId(ProtocolVersion.MINECRAFT_1_21_5, 0x4E, 0x7B);
registerPacketId(ProtocolVersion.MINECRAFT_1_21_4, 0x4F, 0x7B);
}
private static void registerPacketId(ProtocolVersion version, int selectAdvancementTabPacket, int advancementPacket) {
try {
StateRegistry.PacketRegistry.ProtocolRegistry registry = StateRegistry.PLAY.getProtocolRegistry(ProtocolUtils.Direction.CLIENTBOUND, version);
Field field = StateRegistry.PacketRegistry.ProtocolRegistry.class.getDeclaredField("packetClassToId");
field.setAccessible(true);
Object2IntMap<Class<? extends MinecraftPacket>> map = (Object2IntMap) field.get(registry);
map.put(SelectAdvancementTabPacket.class, selectAdvancementTabPacket);
map.put(Advancement.Packet.class, advancementPacket);
} catch (Exception e) {
// Ignore
}
}
@Subscribe(priority = -1000)
public void onPostLogin(PostLoginEvent event) {
sendAdvancements(event.getPlayer());
}
@Subscribe(priority = -1000)
public void onServerPostConnect(ServerPostConnectEvent event) {
sendAdvancements(event.getPlayer());
}
private void sendAdvancements(Player player) {
// Only enable for 1.21.4 or higher
if (player.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_21_4)) {
return;
}
((ConnectedPlayer) player).getConnection().write(selectAdvancementTabPacket);
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
for (Advancement advancement : Advancements.getAll()) {
advancement.get(user).update();
}
}
@Subscribe
public void onDisconnect(DisconnectEvent event) {
SteamwarUser user = SteamwarUser.get(event.getPlayer().getUniqueId());
for (Advancement advancement : Advancements.getAll()) {
advancement.data.remove(user);
}
Advancement.values.remove(user);
}
}
@@ -1,55 +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.velocitycore.advancements;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
import java.util.Optional;
@AllArgsConstructor
public class SelectAdvancementTabPacket implements MinecraftPacket {
private Optional<String> identifier;
@Override
public void decode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
throw new UnsupportedOperationException("Packet is not implemented");
}
@Override
public void encode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
if (this.identifier.isPresent()) {
byteBuf.writeBoolean(true);
ProtocolUtils.writeString(byteBuf, this.identifier.get());
} else {
byteBuf.writeBoolean(false);
}
}
@Override
public boolean handle(MinecraftSessionHandler minecraftSessionHandler) {
return false;
}
}
@@ -19,7 +19,6 @@
package de.steamwar.velocitycore.commands;
import com.velocitypowered.api.command.SimpleCommand;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ServerConnection;
import de.steamwar.command.SWCommand;
@@ -63,89 +62,61 @@ public class CheckCommand extends SWCommand {
public static Message getWaitTime(SchematicNode schematic) {
long waitedMillis = Timestamp.from(Instant.now()).getTime() - schematic.getLastUpdate().getTime();
String color;
if (waitedMillis > 48L * 60 * 60 * 1000) color = "4";
else if (waitedMillis > 24L * 60 * 60 * 1000) color = "c";
else if (waitedMillis > 12L * 60 * 60 * 1000) color = "6";
else if (waitedMillis > 4L * 60 * 60 * 1000) color = "e";
else color = "a";
String ce = waitedMillis > 86400000 ? "c" : "e";
String color = waitedMillis > 14400000 ? ce : "a";
long hours = waitedMillis / 3600000;
long minutes = (waitedMillis - hours * 3600000) / 60000;
return new Message("CHECK_LIST_WAIT", color, hours, (minutes < 10) ? "0" + minutes : minutes);
}
public CheckCommand() {
super("check");
VelocityCore.schedule(() -> Chatter.allStream().forEach(CheckCommand::sendReminder)).delay(10, TimeUnit.MINUTES).repeat(10, TimeUnit.MINUTES).schedule();
}
super("check", UserPerm.CHECK);
@Override
protected boolean hasPermission(SimpleCommand.Invocation invocation) {
SteamwarUser user = Chatter.of(invocation.source()).user();
if (user.perms().contains(UserPerm.CHECK)) return true;
return GameModeConfig.getAll()
.stream()
.filter(GameModeConfig::isActive)
.anyMatch(gameMode -> gameMode.Checkers.contains(user.getId()));
}
private static Map<SchematicNode, SteamwarUser> getSchematics(SteamwarUser user) {
Map<SchematicNode, SteamwarUser> map = new HashMap<>();
for (SchematicNode schematicNode : getSchemsToCheck()) {
if (!mayCheck(user, schematicNode)) continue;
CheckSession checkSession = currentSchems.get(schematicNode.getId());
map.put(schematicNode, checkSession == null ? null : checkSession.checker.user());
}
return map;
}
private static boolean mayCheck(SteamwarUser user, SchematicNode schematic) {
GameModeConfig<String, String> gameModeConfig = ArenaMode.getBySchemType(schematic.getSchemtype());
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());
VelocityCore.schedule(() -> sendReminder(Chatter.serverteam())).repeat(10, TimeUnit.MINUTES).schedule();
}
public static void sendReminder(Chatter chatter) {
Map<SchematicNode, SteamwarUser> schematics = getSchematics(chatter.user());
if (schematics.isEmpty()) return;
long needsChecking = schematics.entrySet().stream().filter(entry -> entry.getValue() == null).count();
if (needsChecking == 0) return;
chatter.system("CHECK_REMINDER", new Message("CHECK_REMINDER_HOVER"), ClickEvent.runCommand("/check list"), needsChecking);
List<SchematicNode> schematics = getSchemsToCheck();
if (schematics.size() == currentCheckers.size()) return;
chatter.system("CHECK_REMINDER", new Message("CHECK_REMINDER_HOVER"), ClickEvent.runCommand("/check list"), schematics.size() - currentCheckers.size());
}
@Register(value = "list", description = "CHECK_HELP_LIST")
public void list(Chatter sender) {
Map<SchematicNode, SteamwarUser> schematics = getSchematics(sender.user());
List<SchematicNode> schematicList = getSchemsToCheck();
sender.system("CHECK_LIST_HEADER", schematics.size());
sender.system("CHECK_LIST_HEADER", schematicList.size());
for (Map.Entry<SchematicNode, SteamwarUser> entry : schematics.entrySet()) {
String message;
ClickEvent clickEvent;
Message hoverMessage;
String checker;
if (entry.getValue() == null) {
message = "CHECK_LIST_TO_CHECK";
clickEvent = ClickEvent.runCommand("/check schematic " + entry.getKey().getId());
hoverMessage = new Message("CHECK_LIST_TO_CHECK_HOVER");
checker = "";
} else {
message = "CHECK_LIST_CHECKING";
clickEvent = ClickEvent.runCommand("/join " + entry.getValue().getUserName());
hoverMessage = new Message("CHECK_LIST_CHECKING_HOVER");
checker = entry.getValue().getUserName();
for (SchematicNode schematic : schematicList) {
GameModeConfig<String, String> gameModeConfig = ArenaMode.getBySchemType(schematic.getSchemtype());
if (gameModeConfig == null) gameModeConfig = GameModeConfig.getDefaults();
CheckSession current = currentSchems.get(schematic.getId());
ClickEvent clickEvent = null;
Message hoverMessage = null;
if (gameModeConfig.Checkers.isEmpty() || gameModeConfig.Checkers.contains(sender.user().getId())) {
if (current == null) {
clickEvent = ClickEvent.runCommand("/check schematic " + schematic.getId());
hoverMessage = new Message("CHECK_LIST_TO_CHECK_HOVER");
} else {
clickEvent = ClickEvent.runCommand("/join " + current.checker.user().getUserName());
hoverMessage = new Message("CHECK_LIST_CHECKING_HOVER");
}
}
sender.prefixless(message,
hoverMessage,
clickEvent,
getWaitTime(entry.getKey()),
entry.getKey().getSchemtype().getKuerzel(),
SteamwarUser.byId(entry.getKey().getOwner()).getUserName(),
entry.getKey().getName(),
checker);
if (current == null) {
sender.prefixless("CHECK_LIST_TO_CHECK",
hoverMessage,
clickEvent,
getWaitTime(schematic),
schematic.getSchemtype().getKuerzel(), SteamwarUser.byId(schematic.getOwner()).getUserName(), schematic.getName());
} else {
sender.prefixless("CHECK_LIST_CHECKING",
hoverMessage,
clickEvent,
getWaitTime(schematic),
schematic.getSchemtype().getKuerzel(), SteamwarUser.byId(schematic.getOwner()).getUserName(), schematic.getName(), current.checker.user().getUserName());
}
}
}
@@ -171,7 +142,8 @@ public class CheckCommand extends SWCommand {
}
int playerTeam = sender.user().hasPerm(UserPerm.MODERATION) ? 0 : sender.user().getTeam();
if (playerTeam != 0 && SteamwarUser.byId(schem.getOwner()).getTeam() == playerTeam) {
// Ignore 795 SteamWar Team
if (playerTeam != 0 && playerTeam != 795 && SteamwarUser.byId(schem.getOwner()).getTeam() == playerTeam) {
sender.system("CHECK_SCHEMATIC_OWN_TEAM");
return;
}
@@ -237,6 +209,11 @@ public class CheckCommand extends SWCommand {
return schematicList;
}
public static String getChecker(SchematicNode schematic) {
if (currentSchems.get(schematic.getId()) == null) return null;
return currentSchems.get(schematic.getId()).checker.user().getUserName();
}
private static boolean notChecking(Player player) {
if (!isChecking(player)) {
Chatter.of(player).system("CHECK_NOT_CHECKING");
@@ -35,9 +35,6 @@ import de.steamwar.sql.CheckedSchematic;
import de.steamwar.sql.SchematicType;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.UserPerm;
import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.advancements.Advancement;
import de.steamwar.velocitycore.advancements.Advancements;
import de.steamwar.velocitycore.commands.*;
import de.steamwar.velocitycore.discord.DiscordBot;
import de.steamwar.velocitycore.discord.util.DiscordRanks;
@@ -48,7 +45,6 @@ import net.kyori.adventure.text.event.ClickEvent;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Linked
public class ConnectionListener extends BasicListener {
@@ -84,7 +80,8 @@ public class ConnectionListener extends BasicListener {
Player player = event.getPlayer();
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
Chatter chatter = Chatter.of(player);
CheckCommand.sendReminder(chatter);
if (user.hasPerm(UserPerm.CHECK)) CheckCommand.sendReminder(chatter);
for (Subserver subserver : Subserver.getServerList()) {
if (Subserver.isArena(subserver)) {
@@ -105,12 +102,8 @@ public class ConnectionListener extends BasicListener {
}
if (newPlayers.contains(player.getUniqueId())) {
Advancements.ROOT.get(user, (advancement, __) -> new Advancement.Data(advancement, user, 0));
Chatter.broadcast().system("JOIN_FIRST", player);
newPlayers.remove(player.getUniqueId());
VelocityCore.schedule(() -> {
Advancements.ROOT.get(user).update();
}).delay(1, TimeUnit.SECONDS).schedule();
}
if (!StreamingCommand.isNotStreaming(user)) {
+1
View File
@@ -118,6 +118,7 @@ dependencyResolutionManagement {
library("nms", "de.steamwar:spigot:1.21.6")
library("axiom", "de.steamwar:axiompaper:RELEASE")
library("worldedit", "com.sk89q.worldedit:worldedit-bukkit:7.3.16")
library("fawe", "de.steamwar:fastasyncworldedit:1.21")
library("velocity", "de.steamwar:velocity:RELEASE")