Merge branch 'main' into swui/flows

This commit is contained in:
2026-07-26 10:20:35 +02:00
17 changed files with 179 additions and 28 deletions
@@ -19,6 +19,7 @@
package de.steamwar.bausystem.features.simulator; package de.steamwar.bausystem.features.simulator;
import com.destroystokyo.paper.event.server.ServerTickEndEvent;
import de.steamwar.bausystem.BauSystem; import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.Permission; import de.steamwar.bausystem.Permission;
import de.steamwar.bausystem.SWUtils; import de.steamwar.bausystem.SWUtils;
@@ -77,8 +78,16 @@ public class SimulatorCursor implements Listener {
return isSimulatorItem(player.getInventory().getItemInMainHand()) || isSimulatorItem(player.getInventory().getItemInOffHand()); return isSimulatorItem(player.getInventory().getItemInMainHand()) || isSimulatorItem(player.getInventory().getItemInOffHand());
} }
private static Set<Player> scheduledUpdates = new HashSet<>();
private static void scheduleCursorUpdate(Player player) { private static void scheduleCursorUpdate(Player player) {
BauSystem.runTaskLater(BauSystem.getInstance(), () -> calcCursor(player), 1); scheduledUpdates.add(player);
}
@EventHandler
public void onServerTickEnd(ServerTickEndEvent event) {
scheduledUpdates.forEach(SimulatorCursor::calcCursor);
scheduledUpdates.clear();
} }
@EventHandler @EventHandler
@@ -122,6 +131,7 @@ public class SimulatorCursor implements Listener {
public void onPlayerQuit(PlayerQuitEvent event) { public void onPlayerQuit(PlayerQuitEvent event) {
cursorType.remove(event.getPlayer()); cursorType.remove(event.getPlayer());
removeCursor(event.getPlayer()); removeCursor(event.getPlayer());
scheduledUpdates.remove(event.getPlayer());
} }
private static final Map<Player, Long> LAST_SNEAKS = new HashMap<>(); private static final Map<Player, Long> LAST_SNEAKS = new HashMap<>();
@@ -153,7 +153,11 @@ public class TraceCommand extends SWCommand {
@Register(value = "isolate", description = "TRACE_COMMAND_HELP_ISOLATE") @Register(value = "isolate", description = "TRACE_COMMAND_HELP_ISOLATE")
public void isolate(@Validator Player player, Trace trace, @ErrorMessage("TRACE_RECORD_ID_INVALID") TNTPoint... records) { public void isolate(@Validator Player player, Trace trace, @ErrorMessage("TRACE_RECORD_ID_INVALID") TNTPoint... records) {
TraceManager.instance.isolate(player, records); if (records.length == 0) {
TraceManager.instance.isolate(player, trace, trace.getRecords().toArray(TNTPoint[]::new));
} else {
TraceManager.instance.isolate(player, trace, records);
}
BauSystem.MESSAGE.send("TRACE_MESSAGE_ISOLATE", player); BauSystem.MESSAGE.send("TRACE_MESSAGE_ISOLATE", player);
} }
@@ -347,9 +347,10 @@ public class TraceManager implements Listener {
* Toggles the isolated render for the given records and player * Toggles the isolated render for the given records and player
* *
* @param player the player the trace is shown to * @param player the player the trace is shown to
* @param records the record for which isolation is toggled * @param ptrace the trace for whitch isolation is toggled
* @param records the records of the trace for which isolation is toggled
*/ */
public void isolate(Player player, TNTPoint... records) { public void isolate(Player player, Trace ptrace, TNTPoint... records) {
unfollow(player); unfollow(player);
Region region = Region.getRegion(player.getLocation()); Region region = Region.getRegion(player.getLocation());
@@ -374,12 +375,20 @@ public class TraceManager implements Listener {
isolateFlag.toggleId(record.getTntId()); isolateFlag.toggleId(record.getTntId());
} }
if (isolateFlag.isEmpty() && playerTraceShowData.hasViewFlagOnly(IsolateFlag.class) && records.length != 0) {
playerTraceShowData.removeViewFlag(IsolateFlag.class);
}
PlayerTraceShowData finalPlayerTraceShowData = playerTraceShowData; PlayerTraceShowData finalPlayerTraceShowData = playerTraceShowData;
tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> { tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> {
trace.render(player, finalPlayerTraceShowData); if (trace.getUuid() == ptrace.getUuid() || finalPlayerTraceShowData.hasNoViewFlags()) {
followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> { trace.render(player, finalPlayerTraceShowData);
trace.render(follower, finalPlayerTraceShowData); followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> {
}); trace.render(follower, finalPlayerTraceShowData);
});
} else {
trace.hide(player);
}
}); });
} }
@@ -135,6 +135,13 @@ public class TraceRecorder implements Listener {
Iterator<TNTPrimed> iter = trackedTNT.getOrDefault(region, Collections.emptyList()).iterator(); Iterator<TNTPrimed> iter = trackedTNT.getOrDefault(region, Collections.emptyList()).iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
TNTPrimed tnt = iter.next(); TNTPrimed tnt = iter.next();
if (tnt.isDead()) {
iter.remove();
tntSpawnRegion.remove(tnt);
historyMap.remove(tnt);
tntSpawnRegion.remove(tnt);
continue;
}
if (tnt.getFuseTicks() == 80) continue; if (tnt.getFuseTicks() == 80) continue;
TNTPoint record = record(tnt, wrappedTrace, Collections.emptyList()); TNTPoint record = record(tnt, wrappedTrace, Collections.emptyList());
if (record == null) { if (record == null) {
@@ -95,4 +95,8 @@ public class PlayerTraceShowData {
public void addViewFlag(ViewFlag viewFlag) { public void addViewFlag(ViewFlag viewFlag) {
viewFlags.put(viewFlag.getClass(), viewFlag); viewFlags.put(viewFlag.getClass(), viewFlag);
} }
public <T extends ViewFlag> void removeViewFlag(Class<T> clazz) {
viewFlags.remove(clazz);
}
} }
@@ -51,6 +51,10 @@ public class IsolateFlag extends ViewFlag {
} }
} }
public boolean isEmpty() {
return tntToIsolate.isEmpty();
}
@Override @Override
public Stream<TNTPoint> filter(Stream<TNTPoint> records) { public Stream<TNTPoint> filter(Stream<TNTPoint> records) {
if (tntToIsolate.isEmpty()) return records; if (tntToIsolate.isEmpty()) return records;
@@ -237,6 +237,7 @@ class EventFight(id: EntityID<Int>) : IntEntity(id), Comparable<EventFight> {
override fun delete() = override fun delete() =
useDb { useDb {
EventRelation.deleteRelations(this@EventFight)
super.delete() super.delete()
} }
} }
@@ -159,10 +159,13 @@ class EventGroup(id: EntityID<Int>) : IntEntity(id) {
} }
override fun delete() = override fun delete() =
useDb { super.delete() } useDb {
EventRelation.deleteRelations(this@EventGroup)
super.delete()
}
enum class EventGroupType { enum class EventGroupType {
GROUP_STAGE, GROUP_STAGE,
ELIMINATION_STAGE ELIMINATION_STAGE
} }
} }
@@ -24,8 +24,10 @@ import org.jetbrains.exposed.v1.core.and
import org.jetbrains.exposed.v1.core.dao.id.EntityID import org.jetbrains.exposed.v1.core.dao.id.EntityID
import org.jetbrains.exposed.v1.core.dao.id.IntIdTable import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
import org.jetbrains.exposed.v1.core.eq import org.jetbrains.exposed.v1.core.eq
import org.jetbrains.exposed.v1.core.or
import org.jetbrains.exposed.v1.dao.IntEntity import org.jetbrains.exposed.v1.dao.IntEntity
import org.jetbrains.exposed.v1.dao.IntEntityClass import org.jetbrains.exposed.v1.dao.IntEntityClass
import org.jetbrains.exposed.v1.jdbc.deleteWhere
import org.jetbrains.exposed.v1.jdbc.select import org.jetbrains.exposed.v1.jdbc.select
object EventRelationTable : IntIdTable("EventRelation") { object EventRelationTable : IntIdTable("EventRelation") {
@@ -59,6 +61,23 @@ class EventRelation(id: EntityID<Int>) : IntEntity(id) {
fun getGroupRelations(group: EventGroup) = fun getGroupRelations(group: EventGroup) =
useDb { find { (EventRelationTable.fromId eq group.id.value) and (EventRelationTable.fromType eq FromType.GROUP) }.toList() } useDb { find { (EventRelationTable.fromId eq group.id.value) and (EventRelationTable.fromType eq FromType.GROUP) }.toList() }
@JvmStatic
fun deleteRelations(fight: EventFight) =
useDb {
EventRelationTable.deleteWhere {
(EventRelationTable.fightId eq fight.id) or
((EventRelationTable.fromId eq fight.id.value) and (EventRelationTable.fromType eq FromType.FIGHT))
}
}
@JvmStatic
fun deleteRelations(group: EventGroup) =
useDb {
EventRelationTable.deleteWhere {
(EventRelationTable.fromId eq group.id.value) and (EventRelationTable.fromType eq FromType.GROUP)
}
}
@JvmStatic @JvmStatic
fun create(fight: EventFight, fightTeam: FightTeam, fromType: FromType, fromId: Int, fromPlace: Int) = fun create(fight: EventFight, fightTeam: FightTeam, fromType: FromType, fromId: Int, fromPlace: Int) =
useDb { useDb {
@@ -159,4 +178,4 @@ class EventRelation(id: EntityID<Int>) : IntEntity(id) {
enum class FromType { enum class FromType {
FIGHT, GROUP FIGHT, GROUP
} }
} }
@@ -488,6 +488,27 @@ public final class GameModeConfig<M, W> {
*/ */
public final boolean NoFloor; public final boolean NoFloor;
/**
* Allows Wind Charges to cross the Middle.
*
* @implSpec {@code false} by default
*/
public final boolean WindchargesCanCrossMiddle;
/**
* Allows Wind Charge interaction with Blocks.
*
* @implSpec {@code true} by default
*/
public final boolean WindchargesInteractWithBlocks;
/**
* Allows Wind Charge to destroy Water.
*
* @implSpec {@code false} by default
*/
public final boolean WindchargesDestroyWater;
private ArenaConfig(YMLWrapper<M, W> loader, SchematicConfig.SizeConfig Size, List<Integer> EnterStages) { private ArenaConfig(YMLWrapper<M, W> loader, SchematicConfig.SizeConfig Size, List<Integer> EnterStages) {
loaded = loader.canLoad(); loaded = loader.canLoad();
WaterDepth = loader.getInt("WaterDepth", 0); WaterDepth = loader.getInt("WaterDepth", 0);
@@ -505,6 +526,9 @@ public final class GameModeConfig<M, W> {
Leaveable = loader.getBoolean("Leaveable", false); Leaveable = loader.getBoolean("Leaveable", false);
AllowMissiles = loader.getBoolean("AllowMissiles", !EnterStages.isEmpty()); AllowMissiles = loader.getBoolean("AllowMissiles", !EnterStages.isEmpty());
NoFloor = loader.getBoolean("NoFloor", false); NoFloor = loader.getBoolean("NoFloor", false);
WindchargesCanCrossMiddle = loader.getBoolean("WindchargesCanCrossMiddle", false);
WindchargesInteractWithBlocks = loader.getBoolean("WindchargesInteractWithBlocks", true);
WindchargesDestroyWater = loader.getBoolean("WindchargesDestroyWater", false);
} }
@ToString @ToString
@@ -929,6 +953,13 @@ public final class GameModeConfig<M, W> {
*/ */
public final boolean PersonalKits; public final boolean PersonalKits;
/**
* Maximal blast resistance for the blocks in the kit
*
* @implSpec {@code 9.0} by default
*/
public final double MaxBlastResistance;
/** /**
* Items (Valid spigot material values) that are not allowed in the personal kit * Items (Valid spigot material values) that are not allowed in the personal kit
*/ */
@@ -940,7 +971,10 @@ public final class GameModeConfig<M, W> {
MemberDefault = loader.getString("MemberDefault", "default"); MemberDefault = loader.getString("MemberDefault", "default");
LeaderDefault = loader.getString("LeaderDefault", "default"); LeaderDefault = loader.getString("LeaderDefault", "default");
PersonalKits = loader.getBoolean("PersonalKits", false); PersonalKits = loader.getBoolean("PersonalKits", false);
ForbiddenItems = loader.getMaterialList("ForbiddenItems"); MaxBlastResistance = loader.getDouble("MaxBlastResistance", 9.0);
List forbiddenItems = new ArrayList<>(loader.getMaterialList("ForbiddenItems"));
forbiddenItems.addAll(SQLWrapper.impl.getMaterialWithGreaterBlastResistance(MaxBlastResistance));
ForbiddenItems = Collections.unmodifiableList(forbiddenItems);
} }
} }
@@ -64,6 +64,10 @@ Arena:
AllowMissiles: false # defaults to true if EnterStages are present otherwise 'false' AllowMissiles: false # defaults to true if EnterStages are present otherwise 'false'
# Denotes that there is no floor for this GameMode # Denotes that there is no floor for this GameMode
NoFloor: false # defaults to false if missing NoFloor: false # defaults to false if missing
# Allows Wind Charges to cross the Middle.
WindchargesCanCrossMiddle: false # defaults to false if missing
# Allows Wind Charge interaction with Blocks.
WindchargesInteractWithBlocks: false # defaults to false if missing
Schematic: Schematic:
# The size of the schematics # The size of the schematics
@@ -72,6 +72,9 @@ public class WaterRemover implements Listener {
@EventHandler @EventHandler
public void handleEntityExplode(EntityExplodeEvent event) { public void handleEntityExplode(EntityExplodeEvent event) {
if (event.getEntityType() == EntityType.WIND_CHARGE && !Config.GameModeConfig.Arena.WindchargesDestroyWater) {
return;
}
event.setYield(0); //No drops (additionally to world config) event.setYield(0); //No drops (additionally to world config)
FightTeam spawn = tnt.remove(event.getEntity().getEntityId()); FightTeam spawn = tnt.remove(event.getEntity().getEntityId());
@@ -0,0 +1,44 @@
/*
* 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.fightsystem.listener;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.linkage.Linked;
import org.bukkit.entity.EntityType;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityExplodeEvent;
@Linked
public class WindchargeInteractionDisabler implements Listener {
public WindchargeInteractionDisabler() {
new StateDependentListener(!Config.GameModeConfig.Arena.WindchargesInteractWithBlocks, FightState.Running, this);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void handleEntityExplode(EntityExplodeEvent event) {
if (event.getEntityType() != EntityType.WIND_CHARGE) return;
event.blockList().clear();
}
}
@@ -23,14 +23,14 @@ import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentTask; import de.steamwar.fightsystem.states.StateDependentTask;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import net.minecraft.world.entity.projectile.windcharge.WindCharge;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.WindCharge;
@Linked @Linked
public class WindchargeStopper { public class WindchargeStopper {
public WindchargeStopper() { public WindchargeStopper() {
new StateDependentTask(true, FightState.Running, this::run, 1, 1); new StateDependentTask(!Config.GameModeConfig.Arena.WindchargesCanCrossMiddle, FightState.Running, this::run, 1, 1);
} }
private static final int middleLine = Config.SpecSpawn.getBlockZ(); private static final int middleLine = Config.SpecSpawn.getBlockZ();
@@ -39,13 +39,13 @@ public class WindchargeStopper {
private void run() { private void run() {
Recording.iterateOverEntities(windChargeClass::isInstance, entity -> { Recording.iterateOverEntities(windChargeClass::isInstance, entity -> {
Location nextlocation = entity.getLocation().add(entity.getVelocity());
Location location = entity.getLocation(); Location location = entity.getLocation();
Location prevLocation = location.clone().subtract(entity.getVelocity());
boolean passedMiddle = location.getBlockZ() > middleLine && prevLocation.getBlockZ() > middleLine || boolean passedMiddle = nextlocation.getBlockZ() >= middleLine && location.getBlockZ() <= middleLine ||
location.getBlockZ() < middleLine && prevLocation.getBlockZ() < middleLine; nextlocation.getBlockZ() <= middleLine && location.getBlockZ() >= middleLine;
if (!passedMiddle) { if (passedMiddle) {
entity.remove(); entity.remove();
} }
}); });
@@ -73,14 +73,19 @@ public class AutoChecker {
continue; continue;
} }
result.getBlockCounts().merge(material, 1, Integer::sum); BlockPos pos = new BlockPos(x, y, z);
if (AutoCheckerItems.impl.getInventoryMaterials().contains(material)) { if (AutoCheckerItems.impl.getInventoryMaterials().contains(material)) {
checkInventory(result, block, material, new BlockPos(x, y, z), type); checkInventory(result, block, material, pos, type);
if (result.getDispenserItems().getOrDefault(pos, 0) > 0) {
result.getBlockCounts().merge(material, 1, Integer::sum);
}
} else {
result.getBlockCounts().merge(material, 1, Integer::sum);
} }
if (x == min.x() || x == max.x() || y == max.y() || z == min.z() || z == max.z()) { if (x == min.x() || x == max.x() || y == max.y() || z == min.z() || z == max.z()) {
result.getDesignBlocks().computeIfAbsent(material, m -> new ArrayList<>()).add(new BlockPos(x, y, z)); result.getDesignBlocks().computeIfAbsent(material, m -> new ArrayList<>()).add(pos);
} }
} }
} }
+4 -4
View File
@@ -25,15 +25,15 @@ open class FightServer : DevServer() {
@get:Input @get:Input
@get:Optional @get:Optional
var checkSchemID: Int = 0 var checkSchemID: Int? = 0
@get:Input @get:Input
@get:Optional @get:Optional
var prepareSchemID: Int = 0 var prepareSchemID: Int? = 0
@get:Input @get:Input
@get:Optional @get:Optional
var replay: Int = 0 var replay: Int? = 0
@get:Input @get:Input
@get:Optional @get:Optional
@@ -42,7 +42,7 @@ open class FightServer : DevServer() {
// Property: fightID // Property: fightID
@get:Input @get:Input
@get:Optional @get:Optional
var eventKampfID: Int = 0 var eventKampfID: Int? = 0
@get:Input @get:Input
@get:Optional @get:Optional
+2 -2
View File
@@ -24,11 +24,11 @@ open class VelocityServer : DevServer() {
@get:Input @get:Input
@get:Optional @get:Optional
var packetDecodeLogging: Boolean = false var packetDecodeLogging: Boolean? = false
init { init {
doFirst { doFirst {
if (packetDecodeLogging) dParams.put("velocity.packet-decode-logging", "true") if (packetDecodeLogging == true) dParams.put("velocity.packet-decode-logging", "true")
} }
} }
} }