Merge remote-tracking branch 'origin/FightSystem/fix-tech-and-hull-hider' into FightSystem/fix-tech-and-hull-hider

This commit is contained in:
D4rkr34lm
2026-05-21 15:08:41 +02:00
70 changed files with 798 additions and 1011 deletions
+6 -2
View File
@@ -129,8 +129,12 @@ jobs:
ssh-keyscan -p "$port" "$DEPLOY_HOST" >> ~/.ssh/known_hosts ssh-keyscan -p "$port" "$DEPLOY_HOST" >> ~/.ssh/known_hosts
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "mkdir -p '$DEPLOY_PATH'" ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "mkdir -p '$DEPLOY_PATH'"
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "rm -f '$DEPLOY_PATH/*'" ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "mkdir -p '$DEPLOY_PATH/upload'"
scp -i ~/.ssh/deploy_key -P "$port" deploy/* "${DEPLOY_USER}@${DEPLOY_HOST}:$DEPLOY_PATH/" scp -i ~/.ssh/deploy_key -P "$port" deploy/* "${DEPLOY_USER}@${DEPLOY_HOST}:$DEPLOY_PATH/upload"
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "rm -f '$DEPLOY_PATH'/*.jar '$DEPLOY_PATH'/*.zip"
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "mv '$DEPLOY_PATH'/upload/* '$DEPLOY_PATH'"
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "rm -r '$DEPLOY_PATH/upload'"
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "chmod o-w '$DEPLOY_PATH'/*"
- name: Restart Services - name: Restart Services
shell: bash shell: bash
env: env:
+15
View File
@@ -0,0 +1,15 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Remote JVM Debugger" type="Remote">
<option name="USE_SOCKET_TRANSPORT" value="true" />
<option name="SERVER_MODE" value="false" />
<option name="SHMEM_ADDRESS" />
<option name="HOST" value="localhost" />
<option name="PORT" value="5005" />
<option name="AUTO_RESTART" value="false" />
<RunnerSettings RunnerId="Debug">
<option name="DEBUG_PORT" value="5005" />
<option name="LOCAL" value="false" />
</RunnerSettings>
<method v="2" />
</configuration>
</component>
@@ -80,7 +80,7 @@ public class SimulatorCursor implements Listener {
} }
public SimulatorCursor() { public SimulatorCursor() {
BiFunction<Player, Object, Object> function = (player, object) -> { BiFunction<Player, ServerboundMovePlayerPacket, Object> function = (player, object) -> {
calcCursor(player); calcCursor(player);
return object; return object;
}; };
@@ -21,7 +21,6 @@ package de.steamwar.bausystem.features.slaves.laufbau;
import com.sk89q.worldedit.blocks.SkullBlock; import com.sk89q.worldedit.blocks.SkullBlock;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import de.steamwar.bausystem.utils.NMSWrapper;
import de.steamwar.inventory.SWItem; import de.steamwar.inventory.SWItem;
import lombok.Getter; import lombok.Getter;
import lombok.ToString; import lombok.ToString;
@@ -99,7 +98,7 @@ public class BlockBoundingBox {
// addPixel(Material.COBWEB.createBlockData(), 0, 0, 0, 0, 0, 0, createItem("LAUFBAU_BLOCK_COBWEB", Material.COBWEB)); // addPixel(Material.COBWEB.createBlockData(), 0, 0, 0, 0, 0, 0, createItem("LAUFBAU_BLOCK_COBWEB", Material.COBWEB));
addPixel(Material.END_STONE.createBlockData(), 0, 0, 0, 16, 16, 16, null); addPixel(Material.END_STONE.createBlockData(), 0, 0, 0, 16, 16, 16, null);
addPixel(NMSWrapper.impl.pathMaterial().createBlockData(), 0, 0, 0, 16, 15, 16, createItem("LAUFBAU_BLOCK_GRASS_PATH", NMSWrapper.impl.pathMaterial())); addPixel(Material.DIRT_PATH.createBlockData(), 0, 0, 0, 16, 15, 16, createItem("LAUFBAU_BLOCK_GRASS_PATH", Material.DIRT_PATH));
addPixel(Material.MUD.createBlockData(), 0, 0, 0, 16, 14, 16, createItem("LAUFBAU_BLOCK_SOUL_SAND", Material.SOUL_SAND)); addPixel(Material.MUD.createBlockData(), 0, 0, 0, 16, 14, 16, createItem("LAUFBAU_BLOCK_SOUL_SAND", Material.SOUL_SAND));
Cocoa cocoaNorth = (Cocoa) Material.COCOA.createBlockData(); Cocoa cocoaNorth = (Cocoa) Material.COCOA.createBlockData();
@@ -21,17 +21,22 @@ package de.steamwar.bausystem.features.util;
import com.comphenix.tinyprotocol.TinyProtocol; import com.comphenix.tinyprotocol.TinyProtocol;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import de.steamwar.Reflection;
import de.steamwar.bausystem.BauSystem; import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.features.tpslimit.TPSUtils; import de.steamwar.bausystem.features.tpslimit.TPSUtils;
import de.steamwar.bausystem.utils.BauMemberUpdateEvent; import de.steamwar.bausystem.utils.BauMemberUpdateEvent;
import de.steamwar.bausystem.utils.NMSWrapper;
import de.steamwar.command.SWCommand; import de.steamwar.command.SWCommand;
import de.steamwar.core.ProtocolWrapper; import de.steamwar.core.ProtocolWrapper;
import de.steamwar.core.SWPlayer; import de.steamwar.core.SWPlayer;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import net.minecraft.network.protocol.game.*; import net.minecraft.network.protocol.game.*;
import net.minecraft.server.level.ServerPlayerGameMode;
import net.minecraft.world.entity.player.Abilities;
import net.minecraft.world.level.GameType;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@@ -57,11 +62,11 @@ public class NoClipCommand extends SWCommand implements Listener {
public NoClipCommand() { public NoClipCommand() {
super("noclip", "nc"); super("noclip", "nc");
BiFunction<Player, Object, Object> first = (player, o) -> { BiFunction<Player, ServerboundMovePlayerPacket, Object> first = (player, o) -> {
NoClipData noClipData = SWPlayer.of(player).getComponent(NoClipData.class).orElse(null); NoClipData noClipData = SWPlayer.of(player).getComponent(NoClipData.class).orElse(null);
if (noClipData == null) return o; if (noClipData == null) return o;
if (noClipData.lastTick == TPSUtils.currentTick.get()) return o; if (noClipData.lastTick == TPSUtils.currentTick.get()) return o;
NMSWrapper.impl.setInternalGameMode(player, GameMode.SPECTATOR); setInternalGameMode(player, GameMode.SPECTATOR);
noClipData.lastTick = TPSUtils.currentTick.get(); noClipData.lastTick = TPSUtils.currentTick.get();
return o; return o;
}; };
@@ -71,7 +76,7 @@ public class NoClipCommand extends SWCommand implements Listener {
BiFunction<Player, Object, Object> second = (player, o) -> { BiFunction<Player, Object, Object> second = (player, o) -> {
NoClipData noClipData = SWPlayer.of(player).getComponent(NoClipData.class).orElse(null); NoClipData noClipData = SWPlayer.of(player).getComponent(NoClipData.class).orElse(null);
if (noClipData == null) return o; if (noClipData == null) return o;
NMSWrapper.impl.setInternalGameMode(player, GameMode.CREATIVE); setInternalGameMode(player, GameMode.CREATIVE);
noClipData.lastTick = TPSUtils.currentTick.get(); noClipData.lastTick = TPSUtils.currentTick.get();
return o; return o;
}; };
@@ -79,15 +84,31 @@ public class NoClipCommand extends SWCommand implements Listener {
TinyProtocol.instance.addFilter(ServerboundPlayerActionPacket.class, second); TinyProtocol.instance.addFilter(ServerboundPlayerActionPacket.class, second);
TinyProtocol.instance.addFilter(ServerboundContainerClickPacket.class, second); TinyProtocol.instance.addFilter(ServerboundContainerClickPacket.class, second);
BiFunction<Player, Object, Object> third = (player, o) -> { BiFunction<Player, ServerboundSetCreativeModeSlotPacket, Object> third = (player, o) -> {
if (SWPlayer.of(player).hasComponent(NoClipData.class)) { if (SWPlayer.of(player).hasComponent(NoClipData.class)) {
NMSWrapper.impl.setSlotToItemStack(player, o); int index = o.slotNum();
if (index >= 36 && index <= 44) {
index -= 36;
} else if (index > 44) {
index -= 5;
} else if (index <= 8) {
index = index - 8 + 36;
}
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(o.itemStack()));
if (index < 9) player.getInventory().setHeldItemSlot(index);
player.updateInventory();
} }
return o; return o;
}; };
TinyProtocol.instance.addFilter(ServerboundSetCreativeModeSlotPacket.class, third); TinyProtocol.instance.addFilter(ServerboundSetCreativeModeSlotPacket.class, third);
} }
private static final Reflection.Field<GameType> playerGameMode = Reflection.getField(ServerPlayerGameMode.class, GameType.class, 0);
private void setInternalGameMode(Player player, GameMode gameMode) {
playerGameMode.set(((CraftPlayer) player).getHandle().gameMode, GameType.byId(gameMode.getValue()));
}
@Register(help = true) @Register(help = true)
public void genericCommand(@Validator Player player) { public void genericCommand(@Validator Player player) {
SWPlayer swPlayer = SWPlayer.of(player); SWPlayer swPlayer = SWPlayer.of(player);
@@ -95,7 +116,9 @@ public class NoClipCommand extends SWCommand implements Listener {
swPlayer.removeComponent(NoClipData.class); swPlayer.removeComponent(NoClipData.class);
} else { } else {
player.setGameMode(GameMode.SPECTATOR); player.setGameMode(GameMode.SPECTATOR);
NMSWrapper.impl.setPlayerBuildAbilities(player); Abilities abilities = (((CraftPlayer) player).getHandle()).getAbilities();
abilities.mayBuild = true;
abilities.mayfly = true;
swPlayer.setComponent(new NoClipData()); swPlayer.setComponent(new NoClipData());
BauSystem.MESSAGE.send("OTHER_NOCLIP_SLOT_INFO", player); BauSystem.MESSAGE.send("OTHER_NOCLIP_SLOT_INFO", player);
@@ -19,8 +19,9 @@
package de.steamwar.bausystem.features.world; package de.steamwar.bausystem.features.world;
import de.steamwar.bausystem.utils.NMSWrapper;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import io.papermc.paper.datacomponent.DataComponentTypes;
import io.papermc.paper.datacomponent.item.ItemContainerContents;
import org.bukkit.attribute.Attribute; import org.bukkit.attribute.Attribute;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -32,6 +33,8 @@ import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import java.util.List;
@Linked @Linked
public class InventoryListener implements Listener { public class InventoryListener implements Listener {
@@ -57,7 +60,7 @@ public class InventoryListener implements Listener {
} }
stack.setItemMeta(meta); stack.setItemMeta(meta);
} }
if (NMSWrapper.impl.checkItemStack(stack)) { if (checkItemStack(stack)) {
e.setCurrentItem(null); e.setCurrentItem(null);
e.setCancelled(true); e.setCancelled(true);
return; return;
@@ -73,7 +76,7 @@ public class InventoryListener implements Listener {
for (int i = 0; i < content.length; i++) { for (int i = 0; i < content.length; i++) {
if (content[i] == null) continue; if (content[i] == null) continue;
int finalI = i; int finalI = i;
if (NMSWrapper.impl.checkItemStack(content[finalI])) { if (checkItemStack(content[finalI])) {
p.getInventory().setItem(i, null); p.getInventory().setItem(i, null);
} }
} }
@@ -82,11 +85,44 @@ public class InventoryListener implements Listener {
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
public void onBlockPlace(BlockPlaceEvent event) { public void onBlockPlace(BlockPlaceEvent event) {
Player p = event.getPlayer(); Player p = event.getPlayer();
if (NMSWrapper.impl.checkItemStack(event.getItemInHand())) { if (checkItemStack(event.getItemInHand())) {
event.setCancelled(true); event.setCancelled(true);
event.setBuild(false); event.setBuild(false);
p.getInventory().setItemInMainHand(null); p.getInventory().setItemInMainHand(null);
p.getInventory().setItemInOffHand(null); p.getInventory().setItemInOffHand(null);
} }
} }
private static final int threshold = 2048;
private boolean checkItemStack(ItemStack item) {
ItemContainerContents data = item.getData(DataComponentTypes.CONTAINER);
if (data == null) {
return false;
}
return drillDown(data.contents(), 0, 0) > threshold;
}
private int drillDown(List<ItemStack> items, int layer, int start) {
if (layer > 2) return start + threshold;
int invalid = start;
for (int i = start; i < items.size(); i++) {
ItemStack item = items.get(i);
if (item.isEmpty()) continue;
invalid += item.getAmount();
ItemContainerContents data = item.getData(DataComponentTypes.CONTAINER);
if (data == null) {
continue;
}
List<ItemStack> subItems = data.contents();
if (subItems.size() > 1) {
invalid = drillDown(subItems, layer + 1, invalid);
}
}
return invalid;
}
} }
@@ -20,18 +20,24 @@
package de.steamwar.bausystem.features.world; package de.steamwar.bausystem.features.world;
import com.comphenix.tinyprotocol.TinyProtocol; import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.bausystem.utils.NMSWrapper;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import net.minecraft.network.protocol.game.ClientboundExplodePacket; import net.minecraft.network.protocol.game.ClientboundExplodePacket;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import java.util.Optional;
@Linked @Linked
public class NoCreativeKnockback { public class NoCreativeKnockback {
public NoCreativeKnockback() { public NoCreativeKnockback() {
TinyProtocol.instance.addFilter(ClientboundExplodePacket.class, (player, o) -> { TinyProtocol.instance.addFilter(ClientboundExplodePacket.class, (player, o) -> {
if (player.getGameMode() != GameMode.CREATIVE) return o; if (player.getGameMode() != GameMode.CREATIVE) return o;
return NMSWrapper.impl.resetExplosionKnockback(o); return new ClientboundExplodePacket(
o.center(),
Optional.empty(),
o.explosionParticle(),
o.explosionSound()
);
}); });
} }
} }
@@ -101,7 +101,7 @@ public class SignEdit implements Listener {
} }
{ {
TinyProtocol.instance.addTypedFilter(ServerboundSignUpdatePacket.class, (player, o) -> { TinyProtocol.instance.addFilter(ServerboundSignUpdatePacket.class, (player, o) -> {
Bukkit.getScheduler().runTask(BauSystem.getInstance(), () -> { Bukkit.getScheduler().runTask(BauSystem.getInstance(), () -> {
ServerLevel serverLevel = ((CraftWorld) player.getWorld()).getHandle(); ServerLevel serverLevel = ((CraftWorld) player.getWorld()).getHandle();
Block signLoc = CraftBlock.at(serverLevel, o.getPos()); Block signLoc = CraftBlock.at(serverLevel, o.getPos());
@@ -114,8 +114,8 @@ public class XrayCommand extends SWCommand implements Listener, ScoreboardElemen
return packet; return packet;
}; };
TinyProtocol.instance.addTypedFilter(ServerboundMovePlayerPacket.Pos.class, positionSetter); TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.Pos.class, positionSetter);
TinyProtocol.instance.addTypedFilter(ServerboundMovePlayerPacket.PosRot.class, positionSetter); TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.PosRot.class, positionSetter);
} }
@EventHandler @EventHandler
@@ -1,117 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bausystem.utils;
import de.steamwar.Reflection;
import io.papermc.paper.datacomponent.DataComponentTypes;
import io.papermc.paper.datacomponent.item.ItemContainerContents;
import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
import net.minecraft.network.protocol.game.ClientboundExplodePacket;
import net.minecraft.server.level.ServerPlayerGameMode;
import net.minecraft.world.entity.player.Abilities;
import net.minecraft.world.level.GameType;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.Optional;
public class NMSWrapper {
public static final NMSWrapper impl = new NMSWrapper();
private static final Reflection.Field<GameType> playerGameMode = Reflection.getField(ServerPlayerGameMode.class, GameType.class, 0);
public void setInternalGameMode(Player player, GameMode gameMode) {
playerGameMode.set(((CraftPlayer) player).getHandle().gameMode, GameType.byId(gameMode.getValue()));
}
public void setSlotToItemStack(Player player, Object o) {
ClientboundContainerSetSlotPacket packetPlayInSetCreativeSlot = (ClientboundContainerSetSlotPacket) o;
int index = packetPlayInSetCreativeSlot.getSlot();
if (index >= 36 && index <= 44) {
index -= 36;
} else if (index > 44) {
index -= 5;
} else if (index <= 8) {
index = index - 8 + 36;
}
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.getItem()));
if (index < 9) player.getInventory().setHeldItemSlot(index);
player.updateInventory();
}
public void setPlayerBuildAbilities(Player player) {
Abilities abilities = (((CraftPlayer) player).getHandle()).getAbilities();
abilities.mayBuild = true;
abilities.mayfly = true;
}
public Material pathMaterial() {
return Material.DIRT_PATH;
}
private static final int threshold = 2048;
public boolean checkItemStack(ItemStack item) {
ItemContainerContents data = item.getData(DataComponentTypes.CONTAINER);
if (data == null) {
return false;
}
return drillDown(data.contents(), 0, 0) > threshold;
}
private int drillDown(List<ItemStack> items, int layer, int start) {
if (layer > 2) return start + threshold;
int invalid = start;
for (int i = start; i < items.size(); i++) {
ItemStack item = items.get(i);
if (item.isEmpty()) continue;
invalid += item.getAmount();
ItemContainerContents data = item.getData(DataComponentTypes.CONTAINER);
if (data == null) {
continue;
}
List<ItemStack> subItems = data.contents();
if (subItems.size() > 1) {
invalid = drillDown(subItems, layer + 1, invalid);
}
}
return invalid;
}
public Object resetExplosionKnockback(Object packet) {
ClientboundExplodePacket explosion = (ClientboundExplodePacket) packet;
return new ClientboundExplodePacket(
explosion.center(),
Optional.empty(),
explosion.explosionParticle(),
explosion.explosionSound()
);
}
}
@@ -42,7 +42,7 @@ public class TickManager implements Listener {
TinyProtocol.instance.addFilter(ClientboundTickingStatePacket.class, this::blockPacket); TinyProtocol.instance.addFilter(ClientboundTickingStatePacket.class, this::blockPacket);
} }
private Object blockPacket(Player player, Object packet) { private Object blockPacket(Player player, ClientboundTickingStatePacket packet) {
if (blockTpsPacket) { if (blockTpsPacket) {
return new ClientboundTickingStatePacket(20, manager.isFrozen()); return new ClientboundTickingStatePacket(20, manager.isFrozen());
} else { } else {
-9
View File
@@ -31,15 +31,6 @@ dependencies {
implementation(project(":BauSystem:BauSystem_Main")) implementation(project(":BauSystem:BauSystem_Main"))
} }
tasks.register<DevServer>("DevBau20") {
group = "run"
description = "Run a 1.20 Dev Bau"
dependsOn(":SpigotCore:shadowJar")
dependsOn(":BauSystem:shadowJar")
dependsOn(":SchematicSystem:shadowJar")
template = "Bau20"
}
tasks.register<DevServer>("DevBau21") { tasks.register<DevServer>("DevBau21") {
group = "run" group = "run"
description = "Run a 1.21 Dev Bau" description = "Run a 1.21 Dev Bau"
@@ -411,7 +411,7 @@ public final class GameModeConfig<M, W> {
} }
@ToString @ToString
public static final class ArenaConfig { public static final class ArenaConfig<M, W> {
public final boolean loaded; public final boolean loaded;
@@ -461,11 +461,11 @@ public final class GameModeConfig<M, W> {
public final boolean DisableSnowMelt; public final boolean DisableSnowMelt;
/** /**
* Disable ice forming * Disable the forming of certain blocks
* *
* @implSpec {@code false} by default * @implSpec {@code empty} by default
*/ */
public final boolean DisableIceForm; public final Set<M> DisabledBlockForms;
/** /**
* Allow leaving the arena area as spectator * Allow leaving the arena area as spectator
@@ -488,7 +488,7 @@ public final class GameModeConfig<M, W> {
*/ */
public final boolean NoFloor; public final boolean NoFloor;
private ArenaConfig(YMLWrapper 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);
WaterDamage = loader.getBoolean("WaterDamage", true); WaterDamage = loader.getBoolean("WaterDamage", true);
@@ -497,7 +497,11 @@ public final class GameModeConfig<M, W> {
BorderFromSchematic = loader.getInt("BorderFromSchematic", 21); BorderFromSchematic = loader.getInt("BorderFromSchematic", 21);
GroundWalkable = loader.getBoolean("GroundWalkable", true); GroundWalkable = loader.getBoolean("GroundWalkable", true);
DisableSnowMelt = loader.getBoolean("DisableSnowMelt", false); DisableSnowMelt = loader.getBoolean("DisableSnowMelt", false);
DisableIceForm = loader.getBoolean("DisableIceForm", false); Set<M> disabledBlockForms = new HashSet<>(loader.getMaterialList("DisabledBlockForms"));
if (loader.getBoolean("DisableIceForm", false)) {
disabledBlockForms.add(loader.materialMapper.apply("ICE"));
}
DisabledBlockForms = Collections.unmodifiableSet(disabledBlockForms);
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);
@@ -434,7 +434,7 @@ class SchematicNode(id: EntityID<Int>) : IntEntity(id) {
private var nodeItem by SchematicNodeTable.item private var nodeItem by SchematicNodeTable.item
var item: String var item: String
get() = nodeItem.ifEmpty { get() = nodeItem.ifEmpty {
if (isDir()) "CHEST" else "CAULDRON_ITEM" if (isDir()) "CHEST" else "CAULDRON"
} }
set(value) = useDb { set(value) = useDb {
nodeItem = value nodeItem = value
@@ -25,6 +25,7 @@ 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.inList import org.jetbrains.exposed.v1.core.inList
import org.jetbrains.exposed.v1.core.neq
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.insert import org.jetbrains.exposed.v1.jdbc.insert
@@ -136,6 +137,12 @@ class SteamwarUser(id: EntityID<Int>) : IntEntity(id) {
.select(SteamwarUserTable.fields).where { UserPermTable.perm eq perm }.map { wrapRow(it) } .select(SteamwarUserTable.fields).where { UserPermTable.perm eq perm }.map { wrapRow(it) }
} }
@JvmStatic
fun getUsersWithDiscordId() =
useDb {
find { SteamwarUserTable.discordId neq null }.toList()
}
@JvmStatic @JvmStatic
fun getServerTeam() = fun getServerTeam() =
useDb { useDb {
@@ -175,6 +182,9 @@ class SteamwarUser(id: EntityID<Int>) : IntEntity(id) {
leaderInternal = false leaderInternal = false
} }
fun hasTeam() =
team != 0
private var leaderInternal by SteamwarUserTable.leader private var leaderInternal by SteamwarUserTable.leader
var leader: Boolean var leader: Boolean
get() = leaderInternal get() = leaderInternal
@@ -63,11 +63,11 @@ enum class UserPerm {
PREFIX_NONE to emptyPrefix, PREFIX_NONE to emptyPrefix,
PREFIX_YOUTUBER to Prefix("§x§8§A§2§B§E§5", "CC"), // 8A2BE5 PREFIX_YOUTUBER to Prefix("§x§8§A§2§B§E§5", "CC"), // 8A2BE5
PREFIX_GUIDE to Prefix("§x§e§7§6§2§e§d", "Guide"), // E762ED PREFIX_GUIDE to Prefix("§x§e§7§6§2§e§d", "Guide"), // E762ED
PREFIX_SUPPORTER to Prefix("§x§6§0§9§5§F§B", "Sup"), // 6095FB PREFIX_SUPPORTER to Prefix("§x§6§0§9§5§F§B", "Sup", true), // 6095FB
PREFIX_MODERATOR to Prefix("§x§F§F§A§2§5§C", "Mod"), // FFA25C PREFIX_MODERATOR to Prefix("§x§F§F§A§2§5§C", "Mod", true), // FFA25C
PREFIX_BUILDER to Prefix("§x§6§0§F§F§6§A", "Arch"), // 60FF6A PREFIX_BUILDER to Prefix("§x§6§0§F§F§6§A", "Arch", true), // 60FF6A
PREFIX_DEVELOPER to Prefix("§x§0§B§B§C§B§3", "Dev"), // 0BBCB3 PREFIX_DEVELOPER to Prefix("§x§0§B§B§C§B§3", "Dev", true), // 0BBCB3
PREFIX_ADMIN to Prefix("§x§F§F§2§B§2§4", "Admin"), // FF2B24 PREFIX_ADMIN to Prefix("§x§F§F§2§B§2§4", "Admin", true), // FF2B24
) )
@JvmStatic @JvmStatic
@@ -94,5 +94,5 @@ enum class UserPerm {
} }
} }
data class Prefix(val colorCode: String, val chatPrefix: String) data class Prefix(val colorCode: String, val chatPrefix: String, val teamPrefix: Boolean = false)
} }
@@ -48,6 +48,16 @@ Arena:
GroundWalkable: true # defaults to true if missing GroundWalkable: true # defaults to true if missing
# Disable snow and ice melting # Disable snow and ice melting
DisableSnowMelt: false # defaults to false if missing DisableSnowMelt: false # defaults to false if missing
# Disabled blocks from forming
DisabledBlockForms:
# For Cobble Generators
# - COBBLESTONE
# - BASALT
# - STONE
# - OBSIDIAN
# Disable ice specifically from forming
# Deprecated, add ICE to DisabledBlockForms list instead
DisableIceForm: false
# Allow leaving the arena area as spectator # Allow leaving the arena area as spectator
Leaveable: false # defaults to false if missing Leaveable: false # defaults to false if missing
# Allow missiles to fly to the enemy and not stop at the schem border. # Allow missiles to fly to the enemy and not stop at the schem border.
@@ -41,6 +41,9 @@ import de.steamwar.sql.SchematicNode;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.GameRule; import org.bukkit.GameRule;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerPickupArrowEvent;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
public class FightSystem extends JavaPlugin { public class FightSystem extends JavaPlugin {
@@ -95,7 +98,12 @@ public class FightSystem extends JavaPlugin {
getMessage().broadcast("PISTON_PUSHED_OUTSIDE"); getMessage().broadcast("PISTON_PUSHED_OUTSIDE");
shutdown(); shutdown();
}); });
new StateDependentListener(ArenaMode.All, FightState.All, BountifulWrapper.impl.newDenyArrowPickupListener()); new StateDependentListener(ArenaMode.All, FightState.All, new Listener() {
@EventHandler
public void onArrowPickup(PlayerPickupArrowEvent e) {
if (Fight.fighting(e.getPlayer())) e.setCancelled(true);
}
});
new OneShotStateDependent(ArenaMode.All, FightState.PreSchemSetup, () -> Fight.playSound(SWSound.BLOCK_NOTE_PLING.getSound(), 100.0f, 2.0f)); new OneShotStateDependent(ArenaMode.All, FightState.PreSchemSetup, () -> Fight.playSound(SWSound.BLOCK_NOTE_PLING.getSound(), 100.0f, 2.0f));
new OneShotStateDependent(ArenaMode.Test, FightState.All, WorldEditRendererCUIEditor::new); new OneShotStateDependent(ArenaMode.Test, FightState.All, WorldEditRendererCUIEditor::new);
Config.world.setGameRule(GameRule.REDUCED_DEBUG_INFO, ArenaMode.AntiTest.contains(Config.mode)); Config.world.setGameRule(GameRule.REDUCED_DEBUG_INFO, ArenaMode.AntiTest.contains(Config.mode));
@@ -121,7 +129,7 @@ public class FightSystem extends JavaPlugin {
Fight.getUnrotated().setSchem(SchematicNode.getSchematicNode(Config.PrepareSchemID)); Fight.getUnrotated().setSchem(SchematicNode.getSchematicNode(Config.PrepareSchemID));
} }
CraftbukkitWrapper.impl.setupGamerule(); Config.world.setGameRule(GameRule.LOCATOR_BAR, false);
} }
@Override @Override
@@ -21,8 +21,8 @@ import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand; import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.fightsystem.utils.TpsWarper;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import net.minecraft.server.MinecraftServer;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@@ -45,8 +45,7 @@ public class TPSWarpCommand implements CommandExecutor {
return false; return false;
} }
TpsWarper warper = TpsWarper.impl; MinecraftServer.getServer().tickRateManager().setTickRate(tps);
warper.warp(tps);
FightSystem.getMessage().broadcastActionbar("TPSWARP_SET", tps); FightSystem.getMessage().broadcastActionbar("TPSWARP_SET", tps);
return false; return false;
@@ -44,6 +44,8 @@ import de.steamwar.sql.SteamwarUser;
import lombok.Getter; import lombok.Getter;
import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.ChatMessageType;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.scoreboard.NameTagVisibility; import org.bukkit.scoreboard.NameTagVisibility;
@@ -151,8 +153,8 @@ public class FightTeam {
new TeamArea(this); new TeamArea(this);
team = FightScoreboard.getBukkitTeam(name); team = FightScoreboard.getBukkitTeam(name);
WorldOfColorWrapper.impl.setTeamColor(team, color); team.setColor(color);
BountifulWrapper.impl.setNametagVisibility(team); team.setOption(Team.Option.NAME_TAG_VISIBILITY, Team.OptionStatus.FOR_OWN_TEAM);
team.setNameTagVisibility(NameTagVisibility.HIDE_FOR_OTHER_TEAMS); team.setNameTagVisibility(NameTagVisibility.HIDE_FOR_OTHER_TEAMS);
if (!Config.GameModeConfig.WinConditions.contains(Winconditions.AMONG_US)) { if (!Config.GameModeConfig.WinConditions.contains(Winconditions.AMONG_US)) {
team.setAllowFriendlyFire(false); team.setAllowFriendlyFire(false);
@@ -284,7 +286,8 @@ public class FightTeam {
entity.teleport(spawn); entity.teleport(spawn);
fightPlayer.ifPlayer(player -> { fightPlayer.ifPlayer(player -> {
BountifulWrapper.impl.setAttackSpeed(player); AttributeInstance attribute = player.getAttribute(Attribute.ATTACK_SPEED);
attribute.setBaseValue(16);
player.setFoodLevel(20); player.setFoodLevel(20);
player.getInventory().clear(); player.getInventory().clear();
FightSystem.getHullHider().updatePlayer(player); FightSystem.getHullHider().updatePlayer(player);
@@ -26,7 +26,6 @@ import de.steamwar.fightsystem.listener.Recording;
import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependent; import de.steamwar.fightsystem.states.StateDependent;
import de.steamwar.fightsystem.utils.CraftbukkitWrapper; import de.steamwar.fightsystem.utils.CraftbukkitWrapper;
import de.steamwar.fightsystem.utils.FlatteningWrapper;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@@ -64,7 +63,7 @@ public class FightWorld extends StateDependent {
public static void forceLoad() { public static void forceLoad() {
Config.ArenaRegion.forEachChunk((cX, cZ) -> { Config.ArenaRegion.forEachChunk((cX, cZ) -> {
Config.world.loadChunk(cX, cZ); Config.world.loadChunk(cX, cZ);
FlatteningWrapper.impl.forceLoadChunk(Config.world, cX, cZ); Config.world.setChunkForceLoaded(cX, cZ, true);
}); });
} }
@@ -20,7 +20,6 @@
package de.steamwar.fightsystem.fight; package de.steamwar.fightsystem.fight;
import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.utils.BountifulWrapper;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
@@ -30,19 +29,16 @@ import org.bukkit.event.block.*;
import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.event.inventory.InventoryMoveItemEvent; import org.bukkit.event.inventory.InventoryMoveItemEvent;
import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerSwapHandItemsEvent;
public class FreezeWorld implements Listener { public class FreezeWorld implements Listener {
private final Listener denyHandSwap = BountifulWrapper.impl.newDenyHandSwapListener();
public FreezeWorld() { public FreezeWorld() {
Bukkit.getPluginManager().registerEvents(this, FightSystem.getPlugin()); Bukkit.getPluginManager().registerEvents(this, FightSystem.getPlugin());
Bukkit.getPluginManager().registerEvents(denyHandSwap, FightSystem.getPlugin());
} }
public void disable() { public void disable() {
HandlerList.unregisterAll(this); HandlerList.unregisterAll(this);
HandlerList.unregisterAll(denyHandSwap);
} }
@EventHandler @EventHandler
@@ -94,4 +90,9 @@ public class FreezeWorld implements Listener {
public void handlePlayerInteract(PlayerInteractEvent event) { public void handlePlayerInteract(PlayerInteractEvent event) {
event.setCancelled(true); event.setCancelled(true);
} }
@EventHandler
public void onSwapItems(PlayerSwapHandItemsEvent event) {
if (Fight.fighting(event.getPlayer())) event.setCancelled(true);
}
} }
@@ -24,12 +24,12 @@ import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.commands.Commands; import de.steamwar.fightsystem.commands.Commands;
import de.steamwar.fightsystem.commands.GUI; import de.steamwar.fightsystem.commands.GUI;
import de.steamwar.fightsystem.listener.PersonalKitCreator; import de.steamwar.fightsystem.listener.PersonalKitCreator;
import de.steamwar.fightsystem.utils.FlatteningWrapper;
import de.steamwar.fightsystem.utils.ReflectionWrapper;
import de.steamwar.inventory.SWInventory; import de.steamwar.inventory.SWInventory;
import de.steamwar.inventory.SWItem; import de.steamwar.inventory.SWItem;
import de.steamwar.sql.PersonalKit; import de.steamwar.sql.PersonalKit;
import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.SteamwarUser;
import io.papermc.paper.datacomponent.DataComponentType;
import io.papermc.paper.datacomponent.DataComponentTypes;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
@@ -39,6 +39,7 @@ import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BlockDataMeta;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
@@ -193,13 +194,13 @@ public class Kit {
if (Config.GameModeConfig.Kits.ForbiddenItems.contains(stack.getType())) return true; if (Config.GameModeConfig.Kits.ForbiddenItems.contains(stack.getType())) return true;
//Check for attribute modifiers //Check for attribute modifiers
if (FlatteningWrapper.impl.hasAttributeModifier(stack)) { if (stack.hasItemMeta() && stack.getItemMeta() != null && stack.getItemMeta().hasAttributeModifiers()) {
return true; return true;
} }
if (stack.hasItemMeta()) { if (stack.hasItemMeta()) {
ItemMeta meta = stack.getItemMeta(); ItemMeta meta = stack.getItemMeta();
if (FlatteningWrapper.impl.containsBlockMeta(meta)) return true; //Blocks always upwards slabs etc. if (meta instanceof BlockDataMeta && ((BlockDataMeta) meta).hasBlockData()) return true; //Blocks always upwards slabs etc.
if (hasItems(stack)) return true; //Blocks prefilled inventories if (hasItems(stack)) return true; //Blocks prefilled inventories
} }
@@ -208,8 +209,42 @@ public class Kit {
return !normal.isEnchantmentInKit(stack) && !stack.getEnchantments().isEmpty(); return !normal.isEnchantmentInKit(stack) && !stack.getEnchantments().isEmpty();
} }
private static final Set<DataComponentType> FORBIDDEN_TYPES = new HashSet<>();
static {
FORBIDDEN_TYPES.add(DataComponentTypes.CUSTOM_NAME);
FORBIDDEN_TYPES.add(DataComponentTypes.PROFILE);
FORBIDDEN_TYPES.add(DataComponentTypes.UNBREAKABLE);
FORBIDDEN_TYPES.add(DataComponentTypes.BLOCK_DATA);
FORBIDDEN_TYPES.add(DataComponentTypes.BLOCKS_ATTACKS);
FORBIDDEN_TYPES.add(DataComponentTypes.BUNDLE_CONTENTS);
FORBIDDEN_TYPES.add(DataComponentTypes.CUSTOM_MODEL_DATA);
FORBIDDEN_TYPES.add(DataComponentTypes.ATTRIBUTE_MODIFIERS);
FORBIDDEN_TYPES.add(DataComponentTypes.TOOL);
FORBIDDEN_TYPES.add(DataComponentTypes.WEAPON);
FORBIDDEN_TYPES.add(DataComponentTypes.FOOD);
FORBIDDEN_TYPES.add(DataComponentTypes.CONSUMABLE);
FORBIDDEN_TYPES.add(DataComponentTypes.POTION_CONTENTS);
FORBIDDEN_TYPES.add(DataComponentTypes.STORED_ENCHANTMENTS);
FORBIDDEN_TYPES.add(DataComponentTypes.CAN_BREAK);
FORBIDDEN_TYPES.add(DataComponentTypes.CAN_PLACE_ON);
FORBIDDEN_TYPES.add(DataComponentTypes.MAX_DAMAGE);
FORBIDDEN_TYPES.add(DataComponentTypes.USE_REMAINDER);
FORBIDDEN_TYPES.add(DataComponentTypes.USE_COOLDOWN);
FORBIDDEN_TYPES.add(DataComponentTypes.SUSPICIOUS_STEW_EFFECTS);
FORBIDDEN_TYPES.add(DataComponentTypes.CHARGED_PROJECTILES);
FORBIDDEN_TYPES.add(DataComponentTypes.INTANGIBLE_PROJECTILE);
FORBIDDEN_TYPES.add(DataComponentTypes.FIREWORKS);
FORBIDDEN_TYPES.add(DataComponentTypes.FIREWORK_EXPLOSION);
FORBIDDEN_TYPES.add(DataComponentTypes.EQUIPPABLE);
FORBIDDEN_TYPES.add(DataComponentTypes.REPAIR_COST);
FORBIDDEN_TYPES.add(DataComponentTypes.ENCHANTABLE);
}
public static boolean hasItems(ItemStack stack) { public static boolean hasItems(ItemStack stack) {
return ReflectionWrapper.impl.hasItems(stack); FORBIDDEN_TYPES.forEach(stack::resetData);
return false;
} }
private boolean isEnchantmentInKit(ItemStack stack) { private boolean isEnchantmentInKit(ItemStack stack) {
@@ -22,12 +22,12 @@ package de.steamwar.fightsystem.listener;
import de.steamwar.fightsystem.Config; 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.fightsystem.utils.WorldOfColorWrapper;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import net.minecraft.world.entity.projectile.AbstractArrow; import net.minecraft.world.entity.projectile.AbstractArrow;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile; import org.bukkit.entity.Projectile;
import org.bukkit.projectiles.ProjectileSource; import org.bukkit.projectiles.ProjectileSource;
@@ -93,8 +93,12 @@ public class ArrowStopper {
boolean teamFrom = entity.getVelocity().getZ() > 0; boolean teamFrom = entity.getVelocity().getZ() > 0;
boolean overMid = location.getZ() > Config.SpecSpawn.getZ(); boolean overMid = location.getZ() > Config.SpecSpawn.getZ();
boolean otherSide = teamFrom == overMid; boolean otherSide = teamFrom == overMid;
return otherSide || !Config.ArenaRegion.inRegion(location) || if (otherSide || !Config.ArenaRegion.inRegion(location)) return true;
WorldOfColorWrapper.impl.isInBlock(entity) || boolean result = false;
if (entity instanceof Arrow arrow) {
result = arrow.isInBlock();
}
return result ||
entity.getVelocity().equals(NULL_VECTOR); entity.getVelocity().equals(NULL_VECTOR);
} }
} }
@@ -32,12 +32,16 @@ import org.bukkit.event.block.BlockFormEvent;
public class BlockFormListener implements Listener { public class BlockFormListener implements Listener {
public BlockFormListener() { public BlockFormListener() {
new StateDependentListener(Config.GameModeConfig.Arena.DisableIceForm, FightState.All, this); boolean enabled = !Config.GameModeConfig.Arena.DisabledBlockForms.isEmpty();
new StateDependentListener(enabled, FightState.All, this);
} }
@EventHandler @EventHandler
public void onBlockForm(BlockFormEvent event) { public void onBlockForm(BlockFormEvent event) {
if (Config.ArenaRegion.inRegion(event.getBlock()) && event.getNewState().getType() == Material.ICE) { if (!Config.ArenaRegion.inRegion(event.getBlock())) return;
Material material = event.getNewState().getType();
if (Config.GameModeConfig.Arena.DisabledBlockForms.contains(material)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@@ -22,11 +22,11 @@ package de.steamwar.fightsystem.listener;
import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentListener; import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.utils.FlatteningWrapper;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Pose;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.BlockPlaceEvent;
@@ -46,7 +46,7 @@ public class BlockPlaceCollision implements Listener {
// Hitbox size: 0.6xz, 1.8y, 1.5y when sneaking // Hitbox size: 0.6xz, 1.8y, 1.5y when sneaking
Player player = event.getPlayer(); Player player = event.getPlayer();
Location min = player.getLocation().add(-0.3, 0, -0.3); Location min = player.getLocation().add(-0.3, 0, -0.3);
Location max = player.getLocation().add(0.3, FlatteningWrapper.impl.isCrouching(player) ? 0.6 : (player.isSneaking() ? 1.5 : 1.8), 0.3); Location max = player.getLocation().add(0.3, player.getPose() == Pose.SWIMMING ? 0.6 : (player.isSneaking() ? 1.5 : 1.8), 0.3);
Location blockmin = block.getLocation(); Location blockmin = block.getLocation();
Location blockmax = block.getLocation().add(1.0, 1.0, 1.0); Location blockmax = block.getLocation().add(1.0, 1.0, 1.0);
@@ -24,7 +24,6 @@ import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.FightSystem;
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.fightsystem.utils.FlatteningWrapper;
import de.steamwar.fightsystem.utils.Region; import de.steamwar.fightsystem.utils.Region;
import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.ChatMessageType;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@@ -141,7 +140,7 @@ public class Border {
private void sendChange(Player player, Block block, Material type) { private void sendChange(Player player, Block block, Material type) {
if (block.getType() == Material.AIR) { if (block.getType() == Material.AIR) {
FlatteningWrapper.impl.sendBlockChange(player, block, type); player.sendBlockChange(block.getLocation(), type.createBlockData());
} }
} }
} }
@@ -20,24 +20,22 @@
package de.steamwar.fightsystem.listener; package de.steamwar.fightsystem.listener;
import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentListener; import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.utils.BountifulWrapper;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryDragEvent; import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.player.PlayerPickupItemEvent; import org.bukkit.event.player.PlayerPickupItemEvent;
import org.bukkit.event.player.PlayerSwapHandItemsEvent;
@Linked @Linked
public class DenyInventoryMovement implements Listener { public class DenyInventoryMovement implements Listener {
public DenyInventoryMovement() { public DenyInventoryMovement() {
new StateDependentListener(ArenaMode.AntiTest, FightState.AntiIngame, this); new StateDependentListener(ArenaMode.AntiTest, FightState.AntiIngame, this);
Listener listener = BountifulWrapper.impl.newDenyHandSwapListener();
new StateDependentListener(ArenaMode.AntiTest, FightState.AntiIngame, listener);
} }
@EventHandler @EventHandler
@@ -54,4 +52,9 @@ public class DenyInventoryMovement implements Listener {
public void onItemPickup(PlayerPickupItemEvent event) { public void onItemPickup(PlayerPickupItemEvent event) {
event.setCancelled(true); event.setCancelled(true);
} }
@EventHandler
public void onSwapItems(PlayerSwapHandItemsEvent event) {
if (Fight.fighting(event.getPlayer())) event.setCancelled(true);
}
} }
@@ -27,13 +27,12 @@ import de.steamwar.fightsystem.fight.FightPlayer;
import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentListener; import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.utils.BountifulWrapper;
import de.steamwar.fightsystem.utils.FlatteningWrapper;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.ChatMessageType;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.data.type.Dispenser;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.TNTPrimed; import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@@ -62,7 +61,7 @@ public class Permanent implements Listener {
private static final Team spectatorTeam = FightScoreboard.getBukkitTeam("Spectator"); private static final Team spectatorTeam = FightScoreboard.getBukkitTeam("Spectator");
static { static {
BountifulWrapper.impl.setNametagVisibility(spectatorTeam); spectatorTeam.setOption(Team.Option.NAME_TAG_VISIBILITY, Team.OptionStatus.FOR_OWN_TEAM);
spectatorTeam.setNameTagVisibility(NameTagVisibility.NEVER); spectatorTeam.setNameTagVisibility(NameTagVisibility.NEVER);
} }
@@ -234,7 +233,7 @@ public class Permanent implements Listener {
return; return;
} }
if (e.getItem().getType() == Material.TNT || FlatteningWrapper.impl.isFacingWater(block)) { if (e.getItem().getType() == Material.TNT || block.getRelative(((Dispenser) block.getBlockData()).getFacing()).isLiquid()) {
e.setCancelled(true); e.setCancelled(true);
} }
} }
@@ -28,12 +28,12 @@ import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.OneShotStateDependent; import de.steamwar.fightsystem.states.OneShotStateDependent;
import de.steamwar.fightsystem.states.StateDependentListener; import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.utils.FlatteningWrapper;
import de.steamwar.fightsystem.utils.Region; import de.steamwar.fightsystem.utils.Region;
import de.steamwar.fightsystem.utils.WorldeditWrapper; import de.steamwar.fightsystem.utils.WorldeditWrapper;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import de.steamwar.sql.SchematicNode; import de.steamwar.sql.SchematicNode;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@@ -52,7 +52,7 @@ public class PrepareSchem implements Listener {
new OneShotStateDependent(ArenaMode.Prepare, FightState.PostSchemSetup, () -> Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> { new OneShotStateDependent(ArenaMode.Prepare, FightState.PostSchemSetup, () -> Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> {
stationaryMovingPistons.clear(); stationaryMovingPistons.clear();
Fight.getUnrotated().getSchemRegion().forEach((x, y, z) -> { Fight.getUnrotated().getSchemRegion().forEach((x, y, z) -> {
if (FlatteningWrapper.impl.checkPistonMoving(Config.world.getBlockAt(x, y, z))) { if (Config.world.getBlockAt(x, y, z).getType() == Material.MOVING_PISTON) {
stationaryMovingPistons.add(new Vector(x, y, z)); stationaryMovingPistons.add(new Vector(x, y, z));
} }
}); });
@@ -76,7 +76,7 @@ public class PrepareSchem implements Listener {
try { try {
region.forEach((x, y, z) -> { region.forEach((x, y, z) -> {
if (FlatteningWrapper.impl.checkPistonMoving(Config.world.getBlockAt(x, y, z)) && !stationaryMovingPistons.contains(new Vector(x, y, z))) { if (Config.world.getBlockAt(x, y, z).getType() == Material.MOVING_PISTON && !stationaryMovingPistons.contains(new Vector(x, y, z))) {
FightSystem.getMessage().broadcast("PREPARE_ACTIVE_PISTON"); FightSystem.getMessage().broadcast("PREPARE_ACTIVE_PISTON");
Bukkit.shutdown(); Bukkit.shutdown();
throw new IllegalStateException(); throw new IllegalStateException();
@@ -22,6 +22,7 @@ package de.steamwar.fightsystem.listener;
import com.comphenix.tinyprotocol.TinyProtocol; import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.Reflection; import de.steamwar.Reflection;
import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.events.TeamDeathEvent; import de.steamwar.fightsystem.events.TeamDeathEvent;
import de.steamwar.fightsystem.events.TeamLeaveEvent; import de.steamwar.fightsystem.events.TeamLeaveEvent;
@@ -34,17 +35,16 @@ import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependent; import de.steamwar.fightsystem.states.StateDependent;
import de.steamwar.fightsystem.states.StateDependentListener; import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.states.StateDependentTask; import de.steamwar.fightsystem.states.StateDependentTask;
import de.steamwar.fightsystem.utils.BountifulWrapper;
import de.steamwar.fightsystem.utils.CraftbukkitWrapper;
import de.steamwar.fightsystem.utils.FlatteningWrapper;
import de.steamwar.fightsystem.utils.SWSound; import de.steamwar.fightsystem.utils.SWSound;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket;
import net.minecraft.network.protocol.game.ServerboundUseItemPacket; import net.minecraft.network.protocol.game.ServerboundUseItemPacket;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.item.PrimedTnt; import net.minecraft.world.entity.item.PrimedTnt;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
@@ -63,6 +63,7 @@ import java.util.Random;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.StreamSupport;
@Linked @Linked
public class Recording implements Listener { public class Recording implements Listener {
@@ -83,12 +84,22 @@ public class Recording implements Listener {
public static final Class<?> primedTnt = PrimedTnt.class; public static final Class<?> primedTnt = PrimedTnt.class;
public static void iterateOverEntities(Predicate<Object> filter, Consumer<Entity> consumer) { public static void iterateOverEntities(Predicate<Object> filter, Consumer<Entity> consumer) {
CraftbukkitWrapper.impl.entityIterator().filter(filter).map(net.minecraft.world.entity.Entity::getBukkitEntity).forEach(consumer); StreamSupport.stream(((CraftWorld) Config.world).getHandle().getEntities().getAll().spliterator(), false).filter(filter).map(net.minecraft.world.entity.Entity::getBukkitEntity).forEach(consumer);
} }
public Recording() { public Recording() {
new StateDependentListener(ArenaMode.AntiReplay, FightState.All, this); new StateDependentListener(ArenaMode.AntiReplay, FightState.All, this);
new StateDependentListener(ArenaMode.AntiReplay, FightState.All, BountifulWrapper.impl.newHandSwapRecorder()); new StateDependentListener(ArenaMode.AntiReplay, FightState.All, new Listener() {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onItemSwap(PlayerSwapHandItemsEvent e) {
if (isNotSent(e.getPlayer()))
return;
Player player = e.getPlayer();
GlobalRecorder.getInstance().item(player, disarmNull(e.getMainHandItem()), "MAINHAND");
GlobalRecorder.getInstance().item(player, disarmNull(e.getOffHandItem()), "OFFHAND");
}
});
new StateDependent(ArenaMode.AntiReplay, FightState.Ingame) { new StateDependent(ArenaMode.AntiReplay, FightState.Ingame) {
@Override @Override
public void enable() { public void enable() {
@@ -102,12 +113,12 @@ public class Recording implements Listener {
} }
}.register(); }.register();
new StateDependent(ArenaMode.AntiReplay, FightState.Ingame) { new StateDependent(ArenaMode.AntiReplay, FightState.Ingame) {
private final BiFunction<Player, Object, Object> place = Recording.this::blockPlace; private final BiFunction<Player, ServerboundUseItemPacket, Object> place = Recording.this::blockPlace;
private final BiFunction<Player, Object, Object> dig = Recording.this::blockDig; private final BiFunction<Player, Object, Object> dig = Recording.this::blockDig;
@Override @Override
public void enable() { public void enable() {
TinyProtocol.instance.addFilter(blockPlacePacket, place); TinyProtocol.instance.addFilter(ServerboundUseItemPacket.class, place);
TinyProtocol.instance.addFilter(blockDigPacket, dig); TinyProtocol.instance.addFilter(blockDigPacket, dig);
} }
@@ -145,9 +156,9 @@ public class Recording implements Listener {
public static final Class<?> blockPlacePacket = ServerboundUseItemPacket.class; public static final Class<?> blockPlacePacket = ServerboundUseItemPacket.class;
private Object blockPlace(Player p, Object packet) { private Object blockPlace(Player p, ServerboundUseItemPacket packet) {
boolean mainHand = BountifulWrapper.impl.mainHand(packet); boolean mainHand = packet.getHand() == InteractionHand.MAIN_HAND;
if (!isNotSent(p) && BountifulWrapper.impl.bowInHand(mainHand, p)) { if (!isNotSent(p) && (mainHand ? p.getInventory().getItemInMainHand() : p.getInventory().getItemInOffHand()).getType() == Material.BOW) {
GlobalRecorder.getInstance().bowSpan(p, true, !mainHand); GlobalRecorder.getInstance().bowSpan(p, true, !mainHand);
} }
return packet; return packet;
@@ -177,7 +188,7 @@ public class Recording implements Listener {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onBlockPhysics(BlockPhysicsEvent e) { public void onBlockPhysics(BlockPhysicsEvent e) {
if (FlatteningWrapper.impl.doRecord(e)) { if (e.getBlock() == e.getSourceBlock() || e.getChangedType() == Material.AIR) {
GlobalRecorder.getInstance().blockChange(e.getBlock()); GlobalRecorder.getInstance().blockChange(e.getBlock());
} }
} }
@@ -285,7 +296,8 @@ public class Recording implements Listener {
if (!fp.isLiving()) continue; if (!fp.isLiving()) continue;
fp.ifPlayer(player -> { fp.ifPlayer(player -> {
BountifulWrapper.impl.recordHandItems(player); GlobalRecorder.getInstance().item(player, disarmNull(player.getInventory().getItemInMainHand()), "MAINHAND");
GlobalRecorder.getInstance().item(player, disarmNull(player.getInventory().getItemInOffHand()), "OFFHAND");
GlobalRecorder.getInstance().item(player, disarmNull(player.getInventory().getHelmet()), "HEAD"); GlobalRecorder.getInstance().item(player, disarmNull(player.getInventory().getHelmet()), "HEAD");
GlobalRecorder.getInstance().item(player, disarmNull(player.getInventory().getChestplate()), "CHEST"); GlobalRecorder.getInstance().item(player, disarmNull(player.getInventory().getChestplate()), "CHEST");
GlobalRecorder.getInstance().item(player, disarmNull(player.getInventory().getLeggings()), "LEGS"); GlobalRecorder.getInstance().item(player, disarmNull(player.getInventory().getLeggings()), "LEGS");
@@ -25,11 +25,13 @@ import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentListener; import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.utils.FlatteningWrapper;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@@ -101,7 +103,25 @@ public class WaterRemover implements Listener {
if (!Config.BlueExtendRegion.inRegion(b) && !Config.RedExtendRegion.inRegion(b)) return; if (!Config.BlueExtendRegion.inRegion(b) && !Config.RedExtendRegion.inRegion(b)) return;
//checks for water and removes it, if present //checks for water and removes it, if present
if (!FlatteningWrapper.impl.removeWater(b)) return; boolean result = true;
Material type = b.getType();
if (type == Material.WATER || type == Material.LAVA) {
b.setType(Material.AIR);
} else {
BlockData data = b.getBlockData();
if (!(data instanceof Waterlogged)) {
result = false;
} else {
Waterlogged waterlogged = (Waterlogged) data;
if (waterlogged.isWaterlogged()) {
b.setType(Material.AIR);
} else {
result = false;
}
}
}
if (!result) return;
if (b.getY() < MIN_Y) return; if (b.getY() < MIN_Y) return;
@@ -42,11 +42,14 @@ import de.steamwar.techhider.BlockIds;
import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.chat.TextComponent;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Pose; import net.minecraft.world.entity.Pose;
import org.bukkit.Bukkit; import net.minecraft.world.level.block.Block;
import org.bukkit.Location; import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.Material; import org.bukkit.*;
import org.bukkit.Sound; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -72,7 +75,7 @@ public class PacketProcessor implements Listener {
private static final org.bukkit.scoreboard.Team team = FightScoreboard.getBukkitTeam("Replay"); private static final org.bukkit.scoreboard.Team team = FightScoreboard.getBukkitTeam("Replay");
static { static {
BountifulWrapper.impl.setNametagVisibility(team); team.setOption(org.bukkit.scoreboard.Team.Option.NAME_TAG_VISIBILITY, org.bukkit.scoreboard.Team.OptionStatus.FOR_OWN_TEAM);
team.setNameTagVisibility(NameTagVisibility.NEVER); team.setNameTagVisibility(NameTagVisibility.NEVER);
} }
@@ -460,8 +463,15 @@ public class PacketProcessor implements Listener {
if (!Config.ArenaRegion.in2dRegion(x, z)) return; //Outside of the arena if (!Config.ArenaRegion.in2dRegion(x, z)) return; //Outside of the arena
execSync(() -> { execSync(() -> {
BlockIdWrapper.impl.setBlock(Config.world, x, y, z, TechHiderWrapper.ENABLED && hiddenBlockIds.contains(blockState) ? obfuscateWith : blockState); int blockState1 = TechHiderWrapper.ENABLED && hiddenBlockIds.contains(blockState) ? obfuscateWith : blockState;
FightSystem.getHullHider().blockUpdate(Config.world.getBlockAt(x, y, z), BlockIdWrapper.impl.idToMaterial(blockState)); BlockState blockData = Block.stateById(blockState1);
ServerLevel level = ((CraftWorld) Config.world).getHandle();
BlockPos pos = new BlockPos(x, y, z);
level.removeBlockEntity(pos);
level.setBlock(pos, blockData, blockState1);
level.getChunkSource().blockChanged(pos);
FightSystem.getHullHider().blockUpdate(Config.world.getBlockAt(x, y, z), CraftMagicNumbers.getMaterial(Block.stateById(blockState)).getItemType());
}); });
} }
@@ -478,7 +488,7 @@ public class PacketProcessor implements Listener {
double finalX = x; double finalX = x;
double finalZ = z; double finalZ = z;
execSync(() -> BountifulWrapper.impl.spawnParticle(Config.world, particleName, finalX + Config.ArenaRegion.getMinX(), y + Config.BluePasteRegion.getMinY(), finalZ + Config.ArenaRegion.getMinZ())); execSync(() -> Config.world.spawnParticle(Particle.valueOf(particleName), finalX + Config.ArenaRegion.getMinX(), y + Config.BluePasteRegion.getMinY(), finalZ + Config.ArenaRegion.getMinZ(), 1));
} }
private void sound() throws IOException { private void sound() throws IOException {
@@ -502,7 +512,10 @@ public class PacketProcessor implements Listener {
Sound sound = Sound.valueOf(soundName); Sound sound = Sound.valueOf(soundName);
execSync(() -> WorldOfColorWrapper.impl.playSound(new Location(Config.world, x, y, z), sound, soundCategory, volume, pitch)); execSync(() -> {
Location location = new Location(Config.world, x, y, z);
location.getWorld().playSound(location, sound, SoundCategory.valueOf(soundCategory), volume, pitch);
});
} }
private void soundAtPlayer() throws IOException { private void soundAtPlayer() throws IOException {
@@ -603,7 +616,7 @@ public class PacketProcessor implements Listener {
Bukkit.getOnlinePlayers().forEach(p -> { Bukkit.getOnlinePlayers().forEach(p -> {
p.resetTitle(); p.resetTitle();
WorldOfColorWrapper.impl.sendTitle(p, title, subtitle, 5, 40, 5); p.sendTitle(title, subtitle, 5, 40, 5);
}); });
} }
@@ -25,7 +25,6 @@ import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightPlayer; import de.steamwar.fightsystem.fight.FightPlayer;
import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.utils.BlockIdWrapper;
import de.steamwar.fightsystem.utils.CraftbukkitWrapper; import de.steamwar.fightsystem.utils.CraftbukkitWrapper;
import de.steamwar.fightsystem.utils.Message; import de.steamwar.fightsystem.utils.Message;
import de.steamwar.fightsystem.utils.SWSound; import de.steamwar.fightsystem.utils.SWSound;
@@ -35,6 +34,7 @@ import de.steamwar.sql.SteamwarUser;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.craftbukkit.block.CraftBlockState;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -219,7 +219,7 @@ public interface Recorder {
} }
default void blockChange(Block block) { default void blockChange(Block block) {
int blockState = BlockIdWrapper.impl.blockToId(block); int blockState = net.minecraft.world.level.block.Block.getId(((CraftBlockState) block.getState()).getHandle());
int shortX = block.getX() - Config.ArenaRegion.getMinX(); int shortX = block.getX() - Config.ArenaRegion.getMinX();
int shortY = block.getY() - Config.BluePasteRegion.getMinY(); int shortY = block.getY() - Config.BluePasteRegion.getMinY();
@@ -1,75 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.fightsystem.utils;
import com.comphenix.tinyprotocol.TinyProtocol;
import com.mojang.authlib.GameProfile;
import de.steamwar.core.ProtocolWrapper;
import de.steamwar.fightsystem.FightSystem;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.block.CraftBlockState;
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
public class BlockIdWrapper {
public static final BlockIdWrapper impl = new BlockIdWrapper();
public Material idToMaterial(int blockState) {
return CraftMagicNumbers.getMaterial(net.minecraft.world.level.block.Block.stateById(blockState)).getItemType();
}
public int blockToId(Block block) {
return net.minecraft.world.level.block.Block.getId(((CraftBlockState) block.getState()).getHandle());
}
public void setBlock(World world, int x, int y, int z, int blockState) {
BlockState blockData = net.minecraft.world.level.block.Block.stateById(blockState);
ServerLevel level = ((CraftWorld) world).getHandle();
BlockPos pos = new BlockPos(x, y, z);
level.removeBlockEntity(pos);
level.setBlock(pos, blockData, blockState);
level.getChunkSource().blockChanged(pos);
}
public void trackEntity(Player player, Entity entity) {
if (entity instanceof Player) {
TinyProtocol.instance.sendPacket(player, ProtocolWrapper.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.REMOVE, new GameProfile(entity.getUniqueId(), entity.getName()), GameMode.CREATIVE));
}
player.showEntity(FightSystem.getPlugin(), entity);
}
public void untrackEntity(Player player, Entity entity) {
player.hideEntity(FightSystem.getPlugin(), entity);
if (entity instanceof Player) {
TinyProtocol.instance.sendPacket(player, ProtocolWrapper.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.ADD, new GameProfile(entity.getUniqueId(), entity.getName()), GameMode.CREATIVE));
}
}
}
@@ -1,158 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.fightsystem.utils;
import de.steamwar.Reflection;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.listener.Recording;
import de.steamwar.fightsystem.record.GlobalRecorder;
import net.minecraft.world.InteractionHand;
import org.bukkit.*;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarStyle;
import org.bukkit.boss.BossBar;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerPickupArrowEvent;
import org.bukkit.event.player.PlayerSwapHandItemsEvent;
import org.bukkit.scoreboard.Team;
import java.util.HashMap;
import java.util.Map;
public class BountifulWrapper {
public static final BountifulWrapper impl = new BountifulWrapper();
private static final Class<?> enumHand = InteractionHand.class;
private static final Object mainHand = enumHand.getEnumConstants()[0];
private static final Reflection.Field<?> blockPlaceHand = Reflection.getField(Recording.blockPlacePacket, enumHand, 0);
public boolean mainHand(Object packet) {
return blockPlaceHand.get(packet) == mainHand;
}
public boolean bowInHand(boolean mainHand, Player p) {
return (mainHand ? p.getInventory().getItemInMainHand() : p.getInventory().getItemInOffHand()).getType() == Material.BOW;
}
public void setAttackSpeed(Player player) {
AttributeInstance attribute = player.getAttribute(Attribute.ATTACK_SPEED);
attribute.setBaseValue(16);
}
public void setNametagVisibility(Team team) {
team.setOption(Team.Option.NAME_TAG_VISIBILITY, Team.OptionStatus.FOR_OWN_TEAM);
}
public Listener newDenyArrowPickupListener() {
return new Listener() {
@EventHandler
public void onArrowPickup(PlayerPickupArrowEvent e) {
if (Fight.fighting(e.getPlayer())) e.setCancelled(true);
}
};
}
public Listener newDenyHandSwapListener() {
return new Listener() {
@EventHandler
public void onSwapItems(PlayerSwapHandItemsEvent event) {
if (Fight.fighting(event.getPlayer())) event.setCancelled(true);
}
};
}
public void recordHandItems(Player player) {
GlobalRecorder.getInstance().item(player, Recording.disarmNull(player.getInventory().getItemInMainHand()), "MAINHAND");
GlobalRecorder.getInstance().item(player, Recording.disarmNull(player.getInventory().getItemInOffHand()), "OFFHAND");
}
public Listener newHandSwapRecorder() {
return new Listener() {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onItemSwap(PlayerSwapHandItemsEvent e) {
if (Recording.isNotSent(e.getPlayer()))
return;
Player player = e.getPlayer();
GlobalRecorder.getInstance().item(player, Recording.disarmNull(e.getMainHandItem()), "MAINHAND");
GlobalRecorder.getInstance().item(player, Recording.disarmNull(e.getOffHandItem()), "OFFHAND");
}
};
}
public void spawnParticle(World world, String particleName, double x, double y, double z) {
world.spawnParticle(Particle.valueOf(particleName), x, y, z, 1);
}
private final Map<Player, BossBar> barMap = new HashMap<>();
public void sendBar(Player player, FightTeam team, double progress, String text) {
barMap.keySet().removeIf(p -> !p.isOnline());
if (!barMap.containsKey(player)) {
BossBar bar = Bukkit.createBossBar(player.getName(), BarColor.WHITE, BarStyle.SOLID);
barMap.put(player, bar);
bar.addPlayer(player);
}
BossBar bar = barMap.get(player);
BarColor color = chat2bar(team.getColor());
if (bar.getColor() != color) bar.setColor(color);
if (bar.getProgress() != progress) bar.setProgress(progress);
if (!bar.getTitle().equals(text)) bar.setTitle(text);
}
private BarColor chat2bar(ChatColor color) {
switch (color) {
case DARK_BLUE:
case DARK_AQUA:
case BLUE:
case AQUA:
return BarColor.BLUE;
case GREEN:
case DARK_GREEN:
return BarColor.GREEN;
case DARK_RED:
case RED:
return BarColor.RED;
case DARK_PURPLE:
return BarColor.PURPLE;
case GOLD:
case YELLOW:
return BarColor.YELLOW;
case LIGHT_PURPLE:
return BarColor.PINK;
case BLACK:
case WHITE:
case GRAY:
case DARK_GRAY:
default:
return BarColor.WHITE;
}
}
}
@@ -19,11 +19,9 @@
package de.steamwar.fightsystem.utils; package de.steamwar.fightsystem.utils;
import de.steamwar.fightsystem.Config;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.LevelChunkSection;
import org.bukkit.GameRule;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.entity.CraftEntity;
@@ -31,26 +29,12 @@ import org.bukkit.entity.Entity;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public class CraftbukkitWrapper { public class CraftbukkitWrapper {
public static final CraftbukkitWrapper impl = new CraftbukkitWrapper(); public static final CraftbukkitWrapper impl = new CraftbukkitWrapper();
protected net.minecraft.world.entity.Entity getEntity(Entity e) {
return ((CraftEntity) e).getHandle();
}
public float headRotation(Entity e) { public float headRotation(Entity e) {
return getEntity(e).getYHeadRot(); return ((CraftEntity) e).getHandle().getYHeadRot();
}
public Stream<net.minecraft.world.entity.Entity> entityIterator() {
return StreamSupport.stream(((CraftWorld) Config.world).getHandle().getEntities().getAll().spliterator(), false);
}
public void setupGamerule() {
Config.world.setGameRule(GameRule.LOCATOR_BAR, false);
} }
private LevelChunk getChunk(World world, int x, int z) { private LevelChunk getChunk(World world, int x, int z) {
@@ -34,12 +34,12 @@ import de.steamwar.fightsystem.winconditions.Wincondition;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarStyle;
import org.bukkit.boss.BossBar;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.ArrayList; import java.util.*;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -142,6 +142,7 @@ public class FightUI {
BossBarType.RED_LEFT.text = leftRedText; BossBarType.RED_LEFT.text = leftRedText;
} }
private final Map<Player, BossBar> barMap = new HashMap<>();
private void sendToPlayers() { private void sendToPlayers() {
Bukkit.getOnlinePlayers().forEach(player -> { Bukkit.getOnlinePlayers().forEach(player -> {
BossBarType bar = BossBarType.byAngle(CraftbukkitWrapper.impl.headRotation(player)); BossBarType bar = BossBarType.byAngle(CraftbukkitWrapper.impl.headRotation(player));
@@ -154,7 +155,55 @@ public class FightUI {
} }
} }
BountifulWrapper.impl.sendBar(player, bar.team, bar.progress, FightSystem.getMessage().parse(bar.text.getMsg(), player, params)); String text = FightSystem.getMessage().parse(bar.text.getMsg(), player, params);
barMap.keySet().removeIf(p -> !p.isOnline());
if (!barMap.containsKey(player)) {
BossBar bar1 = Bukkit.createBossBar(player.getName(), BarColor.WHITE, BarStyle.SOLID);
barMap.put(player, bar1);
bar1.addPlayer(player);
}
BossBar bar1 = barMap.get(player);
BarColor color;
switch (bar.team.getColor()) {
case DARK_BLUE:
case DARK_AQUA:
case BLUE:
case AQUA:
color = BarColor.BLUE;
break;
case GREEN:
case DARK_GREEN:
color = BarColor.GREEN;
break;
case DARK_RED:
case RED:
color = BarColor.RED;
break;
case DARK_PURPLE:
color = BarColor.PURPLE;
break;
case GOLD:
case YELLOW:
color = BarColor.YELLOW;
break;
case LIGHT_PURPLE:
color = BarColor.PINK;
break;
case BLACK:
case WHITE:
case GRAY:
case DARK_GRAY:
default:
color = BarColor.WHITE;
break;
}
if (bar1.getColor() != color) bar1.setColor(color);
if (bar1.getProgress() != bar.progress) bar1.setProgress(bar.progress);
if (!bar1.getTitle().equals(text)) bar1.setTitle(text);
}); });
} }
@@ -208,9 +257,17 @@ public class FightUI {
Bukkit.getOnlinePlayers().forEach(Player::resetTitle); Bukkit.getOnlinePlayers().forEach(Player::resetTitle);
if (winner != null) { if (winner != null) {
Bukkit.getOnlinePlayers().forEach(p -> WorldOfColorWrapper.impl.sendTitle(p, FightSystem.getMessage().parse("UI_WIN", p, winner.getColor(), winner.getName()), FightSystem.getMessage().parse(subtitle, p, params), 5, 40, 5)); Bukkit.getOnlinePlayers().forEach(p -> {
String title = FightSystem.getMessage().parse("UI_WIN", p, winner.getColor(), winner.getName());
String subtitle1 = FightSystem.getMessage().parse(subtitle, p, params);
p.sendTitle(title, subtitle1, 5, 40, 5);
});
} else { } else {
Bukkit.getOnlinePlayers().forEach(p -> WorldOfColorWrapper.impl.sendTitle(p, FightSystem.getMessage().parse("UI_DRAW", p), FightSystem.getMessage().parse(subtitle, p, params), 5, 40, 5)); Bukkit.getOnlinePlayers().forEach(p -> {
String title = FightSystem.getMessage().parse("UI_DRAW", p);
String subtitle1 = FightSystem.getMessage().parse(subtitle, p, params);
p.sendTitle(title, subtitle1, 5, 40, 5);
});
} }
} }
@@ -232,7 +289,10 @@ public class FightUI {
} }
Message message = queue.poll(); Message message = queue.poll();
Bukkit.getOnlinePlayers().forEach(p -> WorldOfColorWrapper.impl.sendTitle(p, " ", FightSystem.getMessage().parse(message.getMsg(), p, message.getParams()), 5, 40, 5)); Bukkit.getOnlinePlayers().forEach(p -> {
String subtitle = FightSystem.getMessage().parse(message.getMsg(), p, message.getParams());
p.sendTitle(" ", subtitle, 5, 40, 5);
});
Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), FightUI::printSubtitle, 50); Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), FightUI::printSubtitle, 50);
subtitleScheduled = true; subtitleScheduled = true;
} }
@@ -1,97 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.fightsystem.utils;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.block.data.type.Dispenser;
import org.bukkit.entity.Player;
import org.bukkit.entity.Pose;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BlockDataMeta;
import org.bukkit.inventory.meta.ItemMeta;
public class FlatteningWrapper {
public static final FlatteningWrapper impl = new FlatteningWrapper();
public boolean isWater(Block block) {
if (block.getType() == Material.WATER) return true;
BlockData data = block.getBlockData();
if (!(data instanceof Waterlogged)) return false;
return ((Waterlogged) data).isWaterlogged();
}
public boolean removeWater(Block block) {
Material type = block.getType();
if (type == Material.WATER || type == Material.LAVA) {
block.setType(Material.AIR);
return true;
}
BlockData data = block.getBlockData();
if (!(data instanceof Waterlogged)) return false;
Waterlogged waterlogged = (Waterlogged) data;
if (waterlogged.isWaterlogged()) {
block.setType(Material.AIR);
return true;
}
return false;
}
public boolean containsBlockMeta(ItemMeta meta) {
return meta instanceof BlockDataMeta && ((BlockDataMeta) meta).hasBlockData();
}
public boolean hasAttributeModifier(ItemStack stack) {
return stack.hasItemMeta() && stack.getItemMeta() != null && stack.getItemMeta().hasAttributeModifiers();
}
public boolean doRecord(BlockPhysicsEvent e) {
return e.getBlock() == e.getSourceBlock() || e.getChangedType() == Material.AIR;
}
public void forceLoadChunk(World world, int cX, int cZ) {
world.setChunkForceLoaded(cX, cZ, true);
}
public boolean checkPistonMoving(Block block) {
return block.getType() == Material.MOVING_PISTON;
}
public boolean isFacingWater(Block dispenser) {
return dispenser.getRelative(((Dispenser) dispenser.getBlockData()).getFacing()).isLiquid();
}
public boolean isCrouching(Player player) {
return player.getPose() == Pose.SWIMMING;
}
public void sendBlockChange(Player player, Block block, Material type) {
player.sendBlockChange(block.getLocation(), type.createBlockData());
}
}
@@ -20,15 +20,25 @@
package de.steamwar.fightsystem.utils; package de.steamwar.fightsystem.utils;
import com.comphenix.tinyprotocol.TinyProtocol; import com.comphenix.tinyprotocol.TinyProtocol;
import com.mojang.authlib.GameProfile;
import de.steamwar.core.ProtocolWrapper;
import de.steamwar.entity.REntity; import de.steamwar.entity.REntity;
import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.fight.FightTeam;
import it.unimi.dsi.fastutil.shorts.Short2ObjectArrayMap;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket;
import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.GameMode;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -91,7 +101,7 @@ public class Hull {
public void addPlayer(Player player) { public void addPlayer(Player player) {
if (players.add(player)) { if (players.add(player)) {
for (Entity entity : entities) { for (Entity entity : entities) {
BlockIdWrapper.impl.untrackEntity(player, entity); untrackEntity(player, entity);
} }
} }
} }
@@ -99,7 +109,7 @@ public class Hull {
public void removePlayer(Player player, boolean activeRemoval) { public void removePlayer(Player player, boolean activeRemoval) {
if (players.remove(player) && activeRemoval) { if (players.remove(player) && activeRemoval) {
for (Entity entity : entities) { for (Entity entity : entities) {
BlockIdWrapper.impl.trackEntity(player, entity); trackEntity(player, entity);
} }
// techhider triggers block change sending // techhider triggers block change sending
} }
@@ -110,18 +120,34 @@ public class Hull {
if (region.inRegion(location) && !visibility.get(new IntVector(location).toId(region))) { if (region.inRegion(location) && !visibility.get(new IntVector(location).toId(region))) {
if (entities.add(entity)) { if (entities.add(entity)) {
for (Player player : players) { for (Player player : players) {
BlockIdWrapper.impl.untrackEntity(player, entity); untrackEntity(player, entity);
} }
} }
} else { } else {
if (entities.remove(entity)) { if (entities.remove(entity)) {
for (Player player : players) { for (Player player : players) {
BlockIdWrapper.impl.trackEntity(player, entity); trackEntity(player, entity);
} }
} }
} }
} }
public void trackEntity(Player player, Entity entity) {
if (entity instanceof Player) {
TinyProtocol.instance.sendPacket(player, ProtocolWrapper.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.REMOVE, new GameProfile(entity.getUniqueId(), entity.getName()), GameMode.CREATIVE));
}
player.showEntity(FightSystem.getPlugin(), entity);
}
public void untrackEntity(Player player, Entity entity) {
player.hideEntity(FightSystem.getPlugin(), entity);
if (entity instanceof Player) {
TinyProtocol.instance.sendPacket(player, ProtocolWrapper.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.ADD, new GameProfile(entity.getUniqueId(), entity.getName()), GameMode.CREATIVE));
}
}
public void removeEntity(Entity entity) { public void removeEntity(Entity entity) {
entities.remove(entity); entities.remove(entity);
} }
@@ -189,7 +215,34 @@ public class Hull {
uncoveredSurface.clear(); uncoveredSurface.clear();
for (Map.Entry<IntVector, List<IntVector>> entry : sectionWise.entrySet()) { for (Map.Entry<IntVector, List<IntVector>> entry : sectionWise.entrySet()) {
Object packet = HullHiderWrapper.impl.generateBlockChangePacket(entry.getValue()); Object result;
List<IntVector> changes = entry.getValue();
Object[] blockdata = new Object[changes.size()];
for (int i = 0; i < blockdata.length; i++) {
IntVector change = changes.get(i);
blockdata[i] = ((CraftBlockData) Config.world.getBlockData(change.getX(), change.getY(), change.getZ())).getState();
}
if (changes.size() > 1) {
IntVector section = changes.get(0);
section = new IntVector(section.getX() >> 4, section.getY() >> 4, section.getZ() >> 4);
int xOffset = 16 * section.getX();
int yOffset = 16 * section.getY();
int zOffset = 16 * section.getZ();
short[] pos = new short[changes.size()];
for (int i = 0; i < changes.size(); i++) {
IntVector change = changes.get(i);
pos[i] = (short) (((change.getX() - xOffset) << 8) + ((change.getZ() - zOffset) << 4) + (change.getY() - yOffset));
}
result = new ClientboundSectionBlocksUpdatePacket(SectionPos.of(section.getX(), section.getY(), section.getZ()), new Short2ObjectArrayMap<>(pos, blockdata, blockdata.length));
} else {
IntVector pos = changes.get(0);
result = new ClientboundBlockUpdatePacket(new BlockPos(pos.getX(), pos.getY(), pos.getZ()), (BlockState) blockdata[0]);
}
Object packet = result;
players.forEach(player -> TinyProtocol.instance.sendPacket(player, packet)); players.forEach(player -> TinyProtocol.instance.sendPacket(player, packet));
} }
} }
@@ -117,7 +117,7 @@ public class HullHider implements Listener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockPhysic(BlockPhysicsEvent e) { public void onBlockPhysic(BlockPhysicsEvent e) {
if (FlatteningWrapper.impl.doRecord(e)) { if (e.getBlock() == e.getSourceBlock() || e.getChangedType() == Material.AIR) {
blockUpdate(e.getBlock(), e.getChangedType()); blockUpdate(e.getBlock(), e.getChangedType());
} }
} }
@@ -1,71 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.fightsystem.utils;
import de.steamwar.fightsystem.Config;
import it.unimi.dsi.fastutil.shorts.Short2ObjectArrayMap;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket;
import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
import java.util.List;
public class HullHiderWrapper {
public static final HullHiderWrapper impl = new HullHiderWrapper();
public Object generateBlockChangePacket(List<Hull.IntVector> changes) {
Object[] blockdata = new Object[changes.size()];
for (int i = 0; i < blockdata.length; i++) {
Hull.IntVector change = changes.get(i);
blockdata[i] = ((CraftBlockData) Config.world.getBlockData(change.getX(), change.getY(), change.getZ())).getState();
}
return generateBlockChangePacket(changes, blockdata);
}
private Object generateBlockChangePacket(List<Hull.IntVector> changes, Object[] blockdata) {
if (changes.size() > 1) {
Hull.IntVector section = changes.get(0);
section = new Hull.IntVector(section.getX() >> 4, section.getY() >> 4, section.getZ() >> 4);
int xOffset = 16 * section.getX();
int yOffset = 16 * section.getY();
int zOffset = 16 * section.getZ();
short[] pos = new short[changes.size()];
for (int i = 0; i < changes.size(); i++) {
Hull.IntVector change = changes.get(i);
pos[i] = (short) (((change.getX() - xOffset) << 8) + ((change.getZ() - zOffset) << 4) + (change.getY() - yOffset));
}
return constructMultiBlockChange(section, pos, blockdata);
} else {
Hull.IntVector pos = changes.get(0);
return new ClientboundBlockUpdatePacket(new BlockPos(pos.getX(), pos.getY(), pos.getZ()), (BlockState) blockdata[0]);
}
}
protected Object constructMultiBlockChange(Hull.IntVector section, short[] pos, Object[] blockdata) {
return new ClientboundSectionBlocksUpdatePacket(SectionPos.of(section.getX(), section.getY(), section.getZ()), new Short2ObjectArrayMap<>(pos, blockdata, blockdata.length));
}
}
@@ -1,79 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.fightsystem.utils;
import io.papermc.paper.datacomponent.DataComponentType;
import io.papermc.paper.datacomponent.DataComponentTypes;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.HashSet;
import java.util.Set;
public class ReflectionWrapper {
public static final ReflectionWrapper impl = new ReflectionWrapper();
private static final Set<DataComponentType> FORBIDDEN_TYPES = new HashSet<>();
static {
FORBIDDEN_TYPES.add(DataComponentTypes.CUSTOM_NAME);
FORBIDDEN_TYPES.add(DataComponentTypes.PROFILE);
FORBIDDEN_TYPES.add(DataComponentTypes.UNBREAKABLE);
FORBIDDEN_TYPES.add(DataComponentTypes.BLOCK_DATA);
FORBIDDEN_TYPES.add(DataComponentTypes.BLOCKS_ATTACKS);
FORBIDDEN_TYPES.add(DataComponentTypes.BUNDLE_CONTENTS);
FORBIDDEN_TYPES.add(DataComponentTypes.CUSTOM_MODEL_DATA);
FORBIDDEN_TYPES.add(DataComponentTypes.ATTRIBUTE_MODIFIERS);
FORBIDDEN_TYPES.add(DataComponentTypes.TOOL);
FORBIDDEN_TYPES.add(DataComponentTypes.WEAPON);
FORBIDDEN_TYPES.add(DataComponentTypes.FOOD);
FORBIDDEN_TYPES.add(DataComponentTypes.CONSUMABLE);
FORBIDDEN_TYPES.add(DataComponentTypes.POTION_CONTENTS);
FORBIDDEN_TYPES.add(DataComponentTypes.STORED_ENCHANTMENTS);
FORBIDDEN_TYPES.add(DataComponentTypes.CAN_BREAK);
FORBIDDEN_TYPES.add(DataComponentTypes.CAN_PLACE_ON);
FORBIDDEN_TYPES.add(DataComponentTypes.MAX_DAMAGE);
FORBIDDEN_TYPES.add(DataComponentTypes.USE_REMAINDER);
FORBIDDEN_TYPES.add(DataComponentTypes.USE_COOLDOWN);
FORBIDDEN_TYPES.add(DataComponentTypes.SUSPICIOUS_STEW_EFFECTS);
FORBIDDEN_TYPES.add(DataComponentTypes.CHARGED_PROJECTILES);
FORBIDDEN_TYPES.add(DataComponentTypes.INTANGIBLE_PROJECTILE);
FORBIDDEN_TYPES.add(DataComponentTypes.FIREWORKS);
FORBIDDEN_TYPES.add(DataComponentTypes.FIREWORK_EXPLOSION);
FORBIDDEN_TYPES.add(DataComponentTypes.EQUIPPABLE);
FORBIDDEN_TYPES.add(DataComponentTypes.REPAIR_COST);
FORBIDDEN_TYPES.add(DataComponentTypes.ENCHANTABLE);
}
public Object explosionHider(Player player, Object packet, PacketHiderFunction packetHiderFunction) {
return packet;
}
public boolean hasItems(ItemStack stack) {
FORBIDDEN_TYPES.forEach(stack::resetData);
return false;
}
public interface PacketHiderFunction {
Object hide(Player player, Object packet, Location location);
}
}
@@ -1,11 +0,0 @@
package de.steamwar.fightsystem.utils;
import net.minecraft.server.MinecraftServer;
public class TpsWarper {
public static final TpsWarper impl = new TpsWarper();
public void warp(float tps) {
MinecraftServer.getServer().tickRateManager().setTickRate(tps);
}
}
@@ -1,50 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.fightsystem.utils;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.scoreboard.Team;
public class WorldOfColorWrapper {
public static final WorldOfColorWrapper impl = new WorldOfColorWrapper();
public void setTeamColor(Team team, ChatColor color) {
team.setColor(color);
}
public boolean isInBlock(Projectile e) {
if (e instanceof Arrow arrow) return arrow.isInBlock();
return false;
}
public void playSound(Location location, Sound sound, String soundCategory, float volume, float pitch) {
location.getWorld().playSound(location, sound, SoundCategory.valueOf(soundCategory), volume, pitch);
}
public void sendTitle(Player player, String title, String subtitle, int start, int hold, int stop) {
player.sendTitle(title, subtitle, start, hold, stop);
}
}
@@ -19,13 +19,22 @@
package de.steamwar.fightsystem.winconditions; package de.steamwar.fightsystem.winconditions;
import de.steamwar.fightsystem.utils.FlatteningWrapper;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
@Linked @Linked
public class WinconditionWaterTechKO extends WinconditionBlocks { public class WinconditionWaterTechKO extends WinconditionBlocks {
public WinconditionWaterTechKO() { public WinconditionWaterTechKO() {
super(Winconditions.WATER_TECH_KO, "WaterTechKO", "BAR_WATER", FlatteningWrapper.impl::isWater); super(Winconditions.WATER_TECH_KO, "WaterTechKO", "BAR_WATER", block -> {
if (block.getType() == Material.WATER) return true;
BlockData data = block.getBlockData();
if (!(data instanceof Waterlogged)) return false;
return ((Waterlogged) data).isWaterlogged();
});
} }
} }
@@ -2,6 +2,7 @@ package com.comphenix.tinyprotocol;
import com.google.common.collect.MapMaker; import com.google.common.collect.MapMaker;
import de.steamwar.Reflection; import de.steamwar.Reflection;
import de.steamwar.core.CRIUWakeupEvent;
import de.steamwar.core.Core; import de.steamwar.core.Core;
import io.netty.channel.*; import io.netty.channel.*;
import net.minecraft.network.Connection; import net.minecraft.network.Connection;
@@ -164,6 +165,10 @@ public class TinyProtocol {
} }
} }
@EventHandler
public void onCRIUWakeup(CRIUWakeupEvent event) {
registerChannelHandler();
}
}; };
plugin.getServer().getPluginManager().registerEvents(listener, plugin); plugin.getServer().getPluginManager().registerEvents(listener, plugin);
@@ -222,15 +227,10 @@ public class TinyProtocol {
} }
} }
public <T> void addTypedFilter(Class<T> packetType, BiFunction<Player, ? super T, Object> filter) { public <T> void addFilter(Class<T> packetType, BiFunction<Player, ? super T, Object> filter) {
packetFilters.computeIfAbsent(packetType, c -> new CopyOnWriteArrayList<>()).add((BiFunction) filter); packetFilters.computeIfAbsent(packetType, c -> new CopyOnWriteArrayList<>()).add((BiFunction) filter);
} }
@Deprecated
public void addFilter(Class<?> packetType, BiFunction<Player, Object, Object> filter) {
packetFilters.computeIfAbsent(packetType, c -> new CopyOnWriteArrayList<>()).add(filter);
}
public void removeFilter(Class<?> packetType, BiFunction<Player, ?, Object> filter) { public void removeFilter(Class<?> packetType, BiFunction<Player, ?, Object> filter) {
packetFilters.getOrDefault(packetType, Collections.emptyList()).remove(filter); packetFilters.getOrDefault(packetType, Collections.emptyList()).remove(filter);
} }
@@ -342,6 +342,8 @@ public class TinyProtocol {
// Lookup channel again // Lookup channel again
if (channel == null) { if (channel == null) {
System.out.println(((CraftPlayer) player).getHandle());
System.out.println(((CraftPlayer) player).getHandle().connection);
Channel playerChannel = ((CraftPlayer) player).getHandle().connection.connection.channel; Channel playerChannel = ((CraftPlayer) player).getHandle().connection.connection.channel;
channelLookup.put(player.getName(), channel = playerChannel); channelLookup.put(player.getName(), channel = playerChannel);
} }
@@ -79,11 +79,14 @@ class CheckpointUtilsJ9 {
return; return;
} }
e.printStackTrace();
Bukkit.shutdown(); Bukkit.shutdown();
if (!message.contains("Can't dump ghost file") && !message.contains("Can't create link remap")) // File/Jar has been updated if (!message.contains("Can't dump ghost file") && !message.contains("Can't create link remap")) // File/Jar has been updated
throw new SecurityException(e); throw new SecurityException(e);
} finally { } finally {
if (true) return;
// Delete checkpoint // Delete checkpoint
try (Stream<Path> stream = Files.walk(path)) { try (Stream<Path> stream = Files.walk(path)) {
stream.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); stream.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
@@ -43,9 +43,8 @@ public class WorldIdentifier {
} }
public WorldIdentifier() { public WorldIdentifier() {
TinyProtocol.instance.addFilter(ClientboundLoginPacket.class, (player, o) -> { TinyProtocol.instance.addFilter(ClientboundLoginPacket.class, (player, packet) -> {
if (resourceKey == null) return o; if (resourceKey == null) return packet;
ClientboundLoginPacket packet = (ClientboundLoginPacket) o;
return new ClientboundLoginPacket(packet.playerId(), return new ClientboundLoginPacket(packet.playerId(),
packet.hardcore(), packet.hardcore(),
@@ -46,7 +46,7 @@ public class AntiNocom implements Listener {
private final Map<Player, Integer> flags = new ConcurrentHashMap<>(); private final Map<Player, Integer> flags = new ConcurrentHashMap<>();
public AntiNocom() { public AntiNocom() {
TinyProtocol.instance.addTypedFilter(ServerboundPlayerActionPacket.class, this::onDig); TinyProtocol.instance.addFilter(ServerboundPlayerActionPacket.class, this::onDig);
registerUseItem(); registerUseItem();
} }
@@ -56,7 +56,7 @@ public class AntiNocom implements Listener {
} }
private void registerUseItem() { private void registerUseItem() {
TinyProtocol.instance.addTypedFilter(ServerboundUseItemOnPacket.class, (player, packet) -> { TinyProtocol.instance.addFilter(ServerboundUseItemOnPacket.class, (player, packet) -> {
BlockPos pos = packet.getHitResult().getBlockPos(); BlockPos pos = packet.getHitResult().getBlockPos();
return isValid(player, "UseItem", pos.getX(), pos.getZ()) ? packet : null; return isValid(player, "UseItem", pos.getX(), pos.getZ()) ? packet : null;
}); });
@@ -343,9 +343,9 @@ public class REntity {
} }
private Object getMoveLookPacket(double diffX, double diffY, double diffZ, boolean rotEq) { private Object getMoveLookPacket(double diffX, double diffY, double diffZ, boolean rotEq) {
short x = (short) (this.x * 4096); short x = (short) (diffX * 4096);
short y = (short) (this.y * 4096); short y = (short) (diffY * 4096);
short z = (short) (this.z * 4096); short z = (short) (diffZ * 4096);
byte yaw = (byte) (this.yaw * 256 / 360); byte yaw = (byte) (this.yaw * 256 / 360);
byte pitch = (byte) (this.pitch * 256 / 360); byte pitch = (byte) (this.pitch * 256 / 360);
@@ -78,7 +78,7 @@ public class REntityServer implements Listener {
this.callback = callback; this.callback = callback;
if (uninitialized) { if (uninitialized) {
TinyProtocol.instance.addTypedFilter(ServerboundInteractPacket.class, filter); TinyProtocol.instance.addFilter(ServerboundInteractPacket.class, filter);
} }
} }
@@ -1,24 +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.techhider;
public interface QuadFunction<A, B, C, D, Return> {
Return apply(A a, B b, C c, D d);
}
@@ -357,7 +357,7 @@ public abstract class TechHider {
processors.put(ClientboundRemoveMobEffectPacket.class, this.buildEntityPacketProcessor(ClientboundRemoveMobEffectPacket::entityId)); processors.put(ClientboundRemoveMobEffectPacket.class, this.buildEntityPacketProcessor(ClientboundRemoveMobEffectPacket::entityId));
// 7.1.98 Set Entity Metadata: entity state can reveal blocks/items/displays. // 7.1.98 Set Entity Metadata: entity state can reveal blocks/items/displays.
processors.put(ClientboundSetEntityDataPacket.class, this.buildEntityPacketProcessor(ClientboundSetEntityDataPacket::id)); processors.put(ClientboundSetEntityDataPacket.class, this.buildEntityPacketProcessor(ClientboundSetEntityDataPacket::id));
// 7.1.26 Damage Event: entity ids and damage source location can leak hidde activity. // 7.1.26 Damage Event: entity ids and damage source location can leak hide activity.
processors.put(ClientboundDamageEventPacket.class, this.buildEntityPacketProcessor(ClientboundDamageEventPacket::entityId)); processors.put(ClientboundDamageEventPacket.class, this.buildEntityPacketProcessor(ClientboundDamageEventPacket::entityId));
// 7.1.54 Move Minecart Along Track: entity path and position signal. // 7.1.54 Move Minecart Along Track: entity path and position signal.
processors.put(ClientboundMoveMinecartPacket.class, this.buildEntityPacketProcessor(ClientboundMoveMinecartPacket::entityId)); processors.put(ClientboundMoveMinecartPacket.class, this.buildEntityPacketProcessor(ClientboundMoveMinecartPacket::entityId));
+1 -6
View File
@@ -37,12 +37,7 @@ tasks.build {
} }
kotlin { kotlin {
jvmToolchain(17) jvmToolchain(21)
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
} }
dependencies { dependencies {
-5
View File
@@ -21,11 +21,6 @@ plugins {
steamwar.java steamwar.java
} }
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
dependencies { dependencies {
compileOnly(libs.velocity) compileOnly(libs.velocity)
annotationProcessor(libs.velocityapi) annotationProcessor(libs.velocityapi)
@@ -493,6 +493,16 @@ TEAM_INFO_TEAM = §7Team §e{0} §8[§{1}{2}§8]
TEAM_INFO_LEADER = §7Leader ({0})§8: {1} TEAM_INFO_LEADER = §7Leader ({0})§8: {1}
TEAM_INFO_MEMBER = §7Member ({0})§8: {1} TEAM_INFO_MEMBER = §7Member ({0})§8: {1}
TEAM_INFO_EVENTS = §7Events ({0})§8: §e{1} TEAM_INFO_EVENTS = §7Events ({0})§8: §e{1}
#Server Team
TEAM_INFO_SW_USAGE = §8/§7team info §8[§eSW§8|§eSteamWar§8]
TEAM_INFO_SW_HEADER = §7Server Team §eSteam§8War §8[§eS§8W]
TEAM_INFO_SW_RANK = {0} §7({1})§8: {2}
#TEAM Prefix
TEAM_PREFIX_USAGE = §8/§7team prefix §8[§eteam§8|§eSW§8]
TEAM_PREFIX_CURRENT = §7Current chat prefix§8: §e{0}
TEAM_PREFIX_SET = §7Your chat prefix is now your §e{0} prefix§7.
TEAM_PREFIX_TEAM = Team
#Team List #Team List
TEAM_LIST_NOT_PAGE = §cNo page number entered TEAM_LIST_NOT_PAGE = §cNo page number entered
@@ -586,8 +596,8 @@ JOIN_STREAMING = §5Streaming Mode§7 is still active§8.§7 Keep in mind that y
EVENTMODE_KICK = §cYou are not an event participant. EVENTMODE_KICK = §cYou are not an event participant.
#TablistManager #TablistManager
TABLIST_PHASE_WEBSITE = §8Website: https://§eSteam§8War.de TABLIST_PHASE_WEBSITE = §7Website§8: §7https://§eSteam§8War§7.de
TABLIST_PHASE_DISCORD = §8Discord: https://§eSteam§8War.de/discord TABLIST_PHASE_DISCORD = §7Discord§8: §7https://§eSteam§8War§7.de/discord
TABLIST_FOOTER = §e{0} {1}§8ms §ePlayers§8: §7{2} TABLIST_FOOTER = §e{0} {1}§8ms §ePlayers§8: §7{2}
TABLIST_BAU = §7§lBuild TABLIST_BAU = §7§lBuild
LIST_COMMAND = §e{0}§8 [{1}]: §7{2} LIST_COMMAND = §e{0}§8 [{1}]: §7{2}
@@ -466,6 +466,11 @@ TEAM_INFO_LEADER = §7Leader ({0})§8: {1}
TEAM_INFO_MEMBER = §7Member ({0})§8: {1} TEAM_INFO_MEMBER = §7Member ({0})§8: {1}
TEAM_INFO_EVENTS = §7Events ({0})§8: §e{1} TEAM_INFO_EVENTS = §7Events ({0})§8: §e{1}
#Team Prefix
TEAM_PREFIX_USAGE = §8/§7team prefix §8[§eteam§8|§eSW§8]
TEAM_PREFIX_CURRENT = §7Aktueller Chatprefix§8: §e{0}
TEAM_PREFIX_SET = §7Dein Chatprefix ist jetzt dein §e{0}prefix§7.
#Team List #Team List
TEAM_LIST_NOT_PAGE = §cKeine Seitenzahl angegeben TEAM_LIST_NOT_PAGE = §cKeine Seitenzahl angegeben
TEAM_LIST_UNKNOWN_PAGE = §cUngültige Seitenzahl angegeben TEAM_LIST_UNKNOWN_PAGE = §cUngültige Seitenzahl angegeben
@@ -21,6 +21,7 @@ package de.steamwar.velocitycore;
import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.RegisteredServer;
import lombok.Getter; import lombok.Getter;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.TypeDescription; import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
@@ -46,7 +47,7 @@ public class Config {
Constructor constructor = new Constructor(clazz, new LoaderOptions()); Constructor constructor = new Constructor(clazz, new LoaderOptions());
constructor.addTypeDescription(typeDescription); constructor.addTypeDescription(typeDescription);
Representer representer = new Representer(); Representer representer = new Representer(new DumperOptions());
representer.getPropertyUtils().setSkipMissingProperties(true); representer.getPropertyUtils().setSkipMissingProperties(true);
Yaml yaml = new Yaml(constructor, representer); Yaml yaml = new Yaml(constructor, representer);
@@ -45,6 +45,7 @@ import de.steamwar.velocitycore.commands.TeamCommand;
import de.steamwar.velocitycore.discord.DiscordBot; import de.steamwar.velocitycore.discord.DiscordBot;
import de.steamwar.velocitycore.discord.DiscordConfig; import de.steamwar.velocitycore.discord.DiscordConfig;
import de.steamwar.velocitycore.listeners.BasicListener; import de.steamwar.velocitycore.listeners.BasicListener;
import de.steamwar.velocitycore.util.SteamwarPrefix;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
@@ -185,6 +186,7 @@ public class VelocityCore implements ReloadablePlugin {
schedule(() -> { schedule(() -> {
SteamwarUser.clear(); SteamwarUser.clear();
Team.clear(); Team.clear();
SteamwarPrefix.clearCache();
}).repeat(1, TimeUnit.HOURS).schedule(); }).repeat(1, TimeUnit.HOURS).schedule();
DiscordConfig discordConfig = DiscordConfig.load(); DiscordConfig discordConfig = DiscordConfig.load();
@@ -27,14 +27,12 @@ import de.steamwar.linkage.Linked;
import de.steamwar.messages.Chatter; import de.steamwar.messages.Chatter;
import de.steamwar.messages.Message; import de.steamwar.messages.Message;
import de.steamwar.messages.PlayerChatter; import de.steamwar.messages.PlayerChatter;
import de.steamwar.sql.Event; import de.steamwar.sql.*;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.Team;
import de.steamwar.sql.TeamTeilnahme;
import de.steamwar.velocitycore.VelocityCore; import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.discord.DiscordBot; import de.steamwar.velocitycore.discord.DiscordBot;
import de.steamwar.velocitycore.inventory.SWItem; import de.steamwar.velocitycore.inventory.SWItem;
import de.steamwar.velocitycore.inventory.SWListInv; import de.steamwar.velocitycore.inventory.SWListInv;
import de.steamwar.velocitycore.util.SteamwarPrefix;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.event.HoverEvent;
@@ -51,6 +49,9 @@ import static de.steamwar.persistent.Storage.teamInvitations;
@Linked @Linked
public class TeamCommand extends SWCommand { public class TeamCommand extends SWCommand {
public static final String STEAM_WAR = "SteamWar";
public static final String SW = "SW";
public TeamCommand() { public TeamCommand() {
super("team"); super("team");
} }
@@ -324,26 +325,63 @@ public class TeamCommand extends SWCommand {
} }
} }
@Register(value = "info", description = "TEAM_INFO_SW_USAGE")
public void infoServerTeam(Chatter sender, @StaticValue({SW, STEAM_WAR}) String __) {
sender.system("TEAM_INFO_SW_HEADER");
UserPerm.prefixes.entrySet().stream()
.filter(entry -> entry.getValue().getTeamPrefix())
.sorted(Map.Entry.<UserPerm, UserPerm.Prefix>comparingByKey().reversed())
.map(entry -> Map.entry(SteamwarUser.getUsersWithPerm(entry.getKey()), entry.getValue()))
.filter(entry -> !entry.getKey().isEmpty())
.forEach(entry -> {
UserPerm.Prefix prefix = entry.getValue();
String memberList = getMemberList(entry.getKey().stream());
sender.prefixless("TEAM_INFO_SW_RANK",
prefix.getColorCode() + prefix.getChatPrefix(),
entry.getKey().size(), memberList);
});
}
private String getMemberList(List<SteamwarUser> users, boolean leaders) { private String getMemberList(List<SteamwarUser> users, boolean leaders) {
return users.stream() return getMemberList(users.stream().filter(u -> u.isLeader() == leaders));
.filter(user -> user.isLeader() == leaders) }
.map(user -> {
StringBuilder st = new StringBuilder(); private String getMemberList(Stream<SteamwarUser> users) {
if (VelocityCore.getProxy().getPlayer(user.getUUID()).isPresent()) { return users.map(user -> getUserColor(user) + user.getUserName())
if (!StreamingCommand.isNotStreaming(user)) {
st.append("§5");
} else {
st.append("§a");
}
} else {
st.append("§e");
}
st.append(user.getUserName());
return st.toString();
})
.collect(Collectors.joining("§8,§r ")); .collect(Collectors.joining("§8,§r "));
} }
private String getUserColor(SteamwarUser user) {
if (VelocityCore.getProxy().getPlayer(user.getUUID()).isPresent()) {
return StreamingCommand.isNotStreaming(user) ? /* Not Streaming */ "§a" : /* Streaming */ "§5";
}
return "§e"; // Offline
}
@Register(value = "prefix", description = "TEAM_PREFIX_USAGE")
public void prefix(@Validator("canUseTeamPrefix") Chatter sender) {
boolean swPrefix = SteamwarPrefix.usesSWPrefix(sender.user());
sender.system("TEAM_PREFIX_CURRENT", swPrefix ? STEAM_WAR : sender.parseToPlain("TEAM_PREFIX_TEAM"));
}
@Register(value = "prefix", description = "TEAM_PREFIX_USAGE")
public void prefix(@Validator("canUseTeamPrefix") Chatter sender, @StaticValue(value = {SW, STEAM_WAR, "Team"}, falseValues = {2}, allowISE = true) boolean useSWTeamTag) {
SteamwarPrefix.setSWPrefix(sender.user(), useSWTeamTag);
sender.system("TEAM_PREFIX_SET", useSWTeamTag ? STEAM_WAR : sender.parseToPlain("TEAM_PREFIX_TEAM"));
}
@Validator(value = "canUseTeamPrefix", local = true)
public TypeValidator<Chatter> canUseTeamPrefixValidator() {
return (sender, value, messageSender) -> {
SteamwarUser user = value.user();
return user.hasPerm(UserPerm.TEAM)
&& user.getTeam() != 0
&& user.prefix() != UserPerm.emptyPrefix;
};
}
@Register("list") @Register("list")
public void list(Chatter sender, @Min(intValue = 1) @OptionalValue("1") @ErrorMessage("TEAM_LIST_NOT_PAGE") int page) { public void list(Chatter sender, @Min(intValue = 1) @OptionalValue("1") @ErrorMessage("TEAM_LIST_NOT_PAGE") int page) {
final int TEAMS_PER_PAGE = 10; final int TEAMS_PER_PAGE = 10;
@@ -532,6 +570,9 @@ public class TeamCommand extends SWCommand {
return new TypeMapper<Team>() { return new TypeMapper<Team>() {
@Override @Override
public Team map(Chatter sender, PreviousArguments previousArguments, String s) { public Team map(Chatter sender, PreviousArguments previousArguments, String s) {
if ((s.equalsIgnoreCase(SW) || s.equalsIgnoreCase(STEAM_WAR))) {
return null;
}
return Team.get(s); return Team.get(s);
} }
@@ -22,6 +22,7 @@ package de.steamwar.velocitycore.discord;
import de.steamwar.command.SWCommand; import de.steamwar.command.SWCommand;
import de.steamwar.messages.Chatter; import de.steamwar.messages.Chatter;
import de.steamwar.sql.Event; import de.steamwar.sql.Event;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.velocitycore.VelocityCore; import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.discord.channels.*; import de.steamwar.velocitycore.discord.channels.*;
import de.steamwar.velocitycore.discord.listeners.ChannelListener; import de.steamwar.velocitycore.discord.listeners.ChannelListener;
@@ -52,12 +53,12 @@ import net.dv8tion.jda.api.utils.MemberCachePolicy;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import java.awt.*; import java.awt.*;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors;
public class DiscordBot { public class DiscordBot {
public static final String ARGUMENT_NAME = "arguments"; public static final String ARGUMENT_NAME = "arguments";
@@ -169,7 +170,7 @@ public class DiscordBot {
eventChannel = new StaticMessageChannel(config.channel("events"), EventChannel::get); eventChannel = new StaticMessageChannel(config.channel("events"), EventChannel::get);
checklistChannel = new ChecklistChannel(config.channel("checklist")); checklistChannel = new ChecklistChannel(config.channel("checklist"));
config.getCouncilThread().forEach((roleId, threadId) -> new CouncilChannel(DiscordBot.getGuild().getRoleById(roleId), DiscordBot.getGuild().getThreadChannelById(threadId))); CouncilChannel.initCouncilChannels();
announcementChannel = new DiscordChannel(config.channel("announcement"), 0) { announcementChannel = new DiscordChannel(config.channel("announcement"), 0) {
@Override @Override
@@ -20,9 +20,7 @@
package de.steamwar.velocitycore.discord.channels; package de.steamwar.velocitycore.discord.channels;
import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.SteamwarUser;
import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.discord.DiscordBot; import de.steamwar.velocitycore.discord.DiscordBot;
import it.unimi.dsi.fastutil.Pair;
import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.entities.Role;
@@ -30,45 +28,88 @@ import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
public class CouncilChannel extends StaticMessageChannel { public class CouncilChannel extends StaticMessageChannel {
private static final Set<CouncilChannel> channels = new HashSet<>(); private static final Set<CouncilChannel> channels = new HashSet<>();
private static final Set<Role> roleSet = DiscordBot.getInstance()
.getConfig()
.getCouncilThread()
.keySet()
.stream()
.map(roleId -> DiscordBot.getGuild().getRoleById(roleId))
.collect(Collectors.toSet());
private static final Map<Role, List<Member>> membersByRole = new HashMap<>();
private static void initRolesAndMembers(Runnable loaded) {
List<Long> discordIds = SteamwarUser.getUsersWithDiscordId().stream()
.map(SteamwarUser::getDiscordId)
.collect(Collectors.toList());
membersByRole.clear();
AtomicInteger countdown = new AtomicInteger(0);
for (int i = 0; i < discordIds.size(); i += 100) {
countdown.incrementAndGet();
List<Long> retrieveIds = discordIds.subList(i, Math.min(discordIds.size(), i + 100));
DiscordBot.getGuild().retrieveMembersByIds(retrieveIds)
.onSuccess(members -> {
members.forEach(member -> {
for (Role role : roleSet) {
if (member.getUnsortedRoles().contains(role)) {
membersByRole.computeIfAbsent(role, __ -> new ArrayList<>()).add(member);
}
}
});
if (countdown.decrementAndGet() == 0) {
loaded.run();
}
});
}
}
public static void initCouncilChannels() {
initRolesAndMembers(() -> {
DiscordBot.getInstance()
.getConfig()
.getCouncilThread()
.forEach((roleId, threadId) -> {
new CouncilChannel(DiscordBot.getGuild().getRoleById(roleId), DiscordBot.getGuild().getThreadChannelById(threadId));
});
});
}
public static void updateAll() { public static void updateAll() {
channels.forEach(StaticMessageChannel::update); initRolesAndMembers(() -> {
channels.forEach(StaticMessageChannel::update);
});
} }
public CouncilChannel(Role role, ThreadChannel threadChannel) { public CouncilChannel(Role role, ThreadChannel threadChannel) {
super(threadChannel, () -> { super(threadChannel, () -> {
MessageCreateBuilder messageCreateBuilder = new MessageCreateBuilder(); MessageCreateBuilder messageCreateBuilder = new MessageCreateBuilder();
messageCreateBuilder.setContent("# Ratsmitglieder"); messageCreateBuilder.setContent("# Ratsmitglieder");
membersByRole.get(role)
List<Member> members; .stream()
try {
members = DiscordBot.getGuild().findMembersWithRoles(role).onError(throwable -> {
// Ignore
}).get();
} catch (Exception e) {
VelocityCore.getLogger().warning("Could not get members for " + role.getName());
return messageCreateBuilder;
}
members.stream()
.map(member -> { .map(member -> {
SteamwarUser steamwarUser = SteamwarUser.get(member.getIdLong()); SteamwarUser steamwarUser = SteamwarUser.get(member.getIdLong());
String name = steamwarUser == null ? member.getEffectiveName() : steamwarUser.getUserName(); String name = steamwarUser == null ? member.getEffectiveName() : steamwarUser.getUserName();
UUID uuid = steamwarUser == null ? null : steamwarUser.getUUID(); UUID uuid = steamwarUser == null ? null : steamwarUser.getUUID();
return Pair.of(name, uuid); return Map.entry(name, uuid);
}) })
.sorted(Comparator.comparing(Pair::key)) .sorted(Map.Entry.comparingByKey())
.forEach(pair -> { .forEach(entry -> {
messageCreateBuilder.addEmbeds(new EmbedBuilder() messageCreateBuilder.addEmbeds(new EmbedBuilder()
.setTitle(pair.key()) .setTitle(entry.getKey())
.setImage(pair.value() == null ? null : "https://api.steamwar.de/data/skin/" + pair.value().toString()) .setImage(entry.getValue() == null ? null : "https://api.steamwar.de/data/skin/" + entry.getValue())
.build()); .build());
}); });
return messageCreateBuilder; return messageCreateBuilder;
}, event -> { }, event -> {
}); });
@@ -42,6 +42,7 @@ import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.commands.PunishmentCommand; import de.steamwar.velocitycore.commands.PunishmentCommand;
import de.steamwar.velocitycore.discord.DiscordBot; import de.steamwar.velocitycore.discord.DiscordBot;
import de.steamwar.velocitycore.network.NetworkSender; import de.steamwar.velocitycore.network.NetworkSender;
import de.steamwar.velocitycore.util.SteamwarPrefix;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -176,19 +177,21 @@ public class ChatListener extends BasicListener {
final String coloredMessage = user.hasPerm(UserPerm.COLOR_CHAT) ? message.replace('&', '§') : message; final String coloredMessage = user.hasPerm(UserPerm.COLOR_CHAT) ? message.replace('&', '§') : message;
if (chatFilter(sender, coloredMessage)) return; if (chatFilter(sender, coloredMessage)) return;
boolean useSwPrefix = useSwPrefix(user);
boolean noReceiver = true; boolean noReceiver = true;
for (Chatter player : receivers.getChatters()) { for (Chatter player : receivers.getChatters()) {
if (player.chatShown()) { if (player.chatShown()) {
chatToReciever(player, msgReceiver, user, format, coloredMessage); chatToReciever(player, msgReceiver, user, format, coloredMessage, useSwPrefix);
if (sender.user().getId() != player.user().getId()) noReceiver = false; if (sender.user().getId() != player.user().getId()) noReceiver = false;
} }
} }
if (format.equals("CHAT_GLOBAL")) { if (format.equals("CHAT_GLOBAL")) {
DiscordBot.withBot(bot -> chatToReciever(bot.getIngameChat(), msgReceiver, user, format, coloredMessage)); DiscordBot.withBot(bot -> chatToReciever(bot.getIngameChat(), msgReceiver, user, format, coloredMessage, useSwPrefix));
} else if (format.equals("CHAT_SERVERTEAM")) { } else if (format.equals("CHAT_SERVERTEAM")) {
DiscordBot.withBot(bot -> chatToReciever(bot.getServerTeamChat(), msgReceiver, user, "CHAT_GLOBAL", coloredMessage)); DiscordBot.withBot(bot -> chatToReciever(bot.getServerTeamChat(), msgReceiver, user, "CHAT_GLOBAL", coloredMessage, useSwPrefix));
} else if (noReceiver) { } else if (noReceiver) {
sender.system("CHAT_NO_RECEIVER"); sender.system("CHAT_NO_RECEIVER");
} }
@@ -239,20 +242,45 @@ public class ChatListener extends BasicListener {
return false; return false;
} }
private static void chatToReciever(Chatter receiver, Chatter msgReceiver, SteamwarUser sender, String format, String message) { private static void chatToReciever(Chatter receiver, Chatter msgReceiver, SteamwarUser sender, String format, String message, boolean useSwPrefix) {
UserPerm.Prefix prefix = sender.prefix(); UserPerm.Prefix prefix = sender.prefix();
String teamPrefix = "";
if (sender.hasPerm(UserPerm.TEAM) && useSwPrefix) {
teamPrefix = "§eS§8W ";
} else if (sender.getTeam() != 0) {
Team team = Team.byId(sender.getTeam());
teamPrefix = "§" + team.getTeamColor() + team.getTeamKuerzel() + " ";
}
String chatColorCode = sender.hasPerm(UserPerm.TEAM) ? "§f" : "§7"; String chatColorCode = sender.hasPerm(UserPerm.TEAM) ? "§f" : "§7";
receiver.prefixless(format, receiver.prefixless(format,
sender, sender,
msgReceiver == null ? receiver : msgReceiver, msgReceiver == null ? receiver : msgReceiver,
highlightMentions(message, chatColorCode, receiver), highlightMentions(message, chatColorCode, receiver),
sender.getTeam() == 0 ? "" : "§" + Team.byId(sender.getTeam()).getTeamColor() + Team.byId(sender.getTeam()).getTeamKuerzel() + " ", teamPrefix,
"", "",
prefix.getColorCode(), prefix == UserPerm.emptyPrefix ? "§f" : prefix.getColorCode(),
prefix.getChatPrefix().length() == 0 ? "§f" : prefix.getChatPrefix() + " ", prefix.getChatPrefix().length() == 0 ? "§f" : prefix.getChatPrefix() + " ",
chatColorCode); chatColorCode);
} }
private static boolean useSwPrefix(SteamwarUser user) {
if (!user.hasPerm(UserPerm.TEAM)) {
return false;
}
UserPerm.Prefix prefix = user.prefix();
boolean hasTeamPrefix = user.getTeam() != 0;
boolean hasSwPrefix = prefix != UserPerm.emptyPrefix;
if (!hasSwPrefix) return false;
if (!hasTeamPrefix) return true;
return SteamwarPrefix.usesSWPrefix(user);
}
private static boolean filteredCommand(Chatter sender, String message) { private static boolean filteredCommand(Chatter sender, String message) {
String command = message.split(" ", 2)[0]; String command = message.split(" ", 2)[0];
if (command.startsWith("/") && command.contains(":")) { if (command.startsWith("/") && command.contains(":")) {
@@ -51,7 +51,7 @@ public class Tablist extends ChannelInboundHandlerAdapter {
private static final UUID[] swUuids = IntStream.range(0, 80).mapToObj(i -> UUID.randomUUID()).toArray(UUID[]::new); private static final UUID[] swUuids = IntStream.range(0, 80).mapToObj(i -> UUID.randomUUID()).toArray(UUID[]::new);
private static final String[] swNames = IntStream.range(0, 80).mapToObj(i -> " »SW« " + String.format("%02d", i)).toArray(String[]::new); private static final String[] swNames = IntStream.range(0, 80).mapToObj(i -> " »SW« " + String.format("%02d", i)).toArray(String[]::new);
public static final UpdateTeamsPacket createTeamPacket = new UpdateTeamsPacket21("zzzzzsw-tab", UpdateTeamsPacket.Mode.CREATE, Component.empty(), Component.empty(), Component.empty(), UpdateTeamsPacket.NameTagVisibility.NEVER, UpdateTeamsPacket.CollisionRule.ALWAYS, 21, (byte) 0x00, Arrays.stream(Tablist.swNames).toList()); public static final UpdateTeamsPacket createTeamPacket = new UpdateTeamsPacketImpl("zzzzzsw-tab", UpdateTeamsPacket.Mode.CREATE, Component.empty(), Component.empty(), Component.empty(), UpdateTeamsPacket.NameTagVisibility.NEVER, UpdateTeamsPacket.CollisionRule.ALWAYS, 21, (byte) 0x00, Arrays.stream(Tablist.swNames).toList());
private final Map<UUID, UpsertPlayerInfoPacket.Entry> directTabItems; private final Map<UUID, UpsertPlayerInfoPacket.Entry> directTabItems;
private final List<UpsertPlayerInfoPacket.Entry> current = new ArrayList<>(); private final List<UpsertPlayerInfoPacket.Entry> current = new ArrayList<>();
@@ -1,103 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.velocitycore.tablist;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.packet.UpdateTeamsPacket;
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
import io.netty.buffer.ByteBuf;
import net.kyori.adventure.text.Component;
import java.util.List;
public class UpdateTeamsPacket21 extends UpdateTeamsPacket {
private String name;
private Mode mode;
private Component displayName;
private Component prefix;
private Component suffix;
private NameTagVisibility nameTagVisibility;
private CollisionRule collisionRule;
private int color;
private byte friendlyFlags;
private List<String> players;
public UpdateTeamsPacket21(String name, Mode mode, Component displayName, Component prefix, Component suffix, NameTagVisibility nameTagVisibility, CollisionRule collisionRule, int color, byte friendlyFlags, List<String> players) {
super(name, mode, displayName, prefix, suffix, nameTagVisibility, collisionRule, color, friendlyFlags, players);
this.name = name;
this.mode = mode;
this.displayName = displayName;
this.prefix = prefix;
this.suffix = suffix;
this.nameTagVisibility = nameTagVisibility;
this.collisionRule = collisionRule;
this.color = color;
this.friendlyFlags = friendlyFlags;
this.players = players;
}
@Override
public void encode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
ProtocolUtils.writeString(byteBuf, this.name);
byteBuf.writeByte(this.mode.ordinal());
switch (this.mode) {
case CREATE:
case UPDATE:
(new ComponentHolder(protocolVersion, this.displayName)).write(byteBuf);
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_13)) {
(new ComponentHolder(protocolVersion, this.prefix)).write(byteBuf);
(new ComponentHolder(protocolVersion, this.suffix)).write(byteBuf);
}
byteBuf.writeByte(this.friendlyFlags);
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_21_5)) {
ProtocolUtils.writeVarInt(byteBuf, this.nameTagVisibility.ordinal());
ProtocolUtils.writeVarInt(byteBuf, this.collisionRule.ordinal());
} else {
ProtocolUtils.writeString(byteBuf, this.nameTagVisibility.getValue());
ProtocolUtils.writeString(byteBuf, this.collisionRule.getValue());
}
if (protocolVersion.greaterThan(ProtocolVersion.MINECRAFT_1_12_2)) {
ProtocolUtils.writeVarInt(byteBuf, this.color);
(new ComponentHolder(protocolVersion, this.prefix)).write(byteBuf);
(new ComponentHolder(protocolVersion, this.suffix)).write(byteBuf);
} else {
byteBuf.writeByte((byte) this.color);
}
ProtocolUtils.writeVarInt(byteBuf, this.players.size());
for (String player : this.players) {
ProtocolUtils.writeString(byteBuf, player);
}
break;
case ADD_PLAYER:
case REMOVE_PLAYER:
ProtocolUtils.writeVarInt(byteBuf, this.players.size());
for (String player : this.players) {
ProtocolUtils.writeString(byteBuf, player);
}
case REMOVE:
}
}
}
@@ -0,0 +1,76 @@
/*
* 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.tablist;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.packet.UpdateTeamsPacket;
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
import io.netty.buffer.ByteBuf;
import net.kyori.adventure.text.Component;
import java.util.List;
public class UpdateTeamsPacketImpl extends UpdateTeamsPacket {
public UpdateTeamsPacketImpl(String name, Mode mode, Component displayName, Component prefix, Component suffix, NameTagVisibility nameTagVisibility, CollisionRule collisionRule, int color, byte friendlyFlags, List<String> players) {
super(name, mode, displayName, prefix, suffix, nameTagVisibility, collisionRule, color, friendlyFlags, players);
}
@Override
public void encode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
ProtocolUtils.writeString(byteBuf, name);
byteBuf.writeByte(mode.ordinal());
switch (mode) {
case CREATE, UPDATE:
new ComponentHolder(protocolVersion, displayName).write(byteBuf);
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_13)) {
new ComponentHolder(protocolVersion, prefix).write(byteBuf);
new ComponentHolder(protocolVersion, suffix).write(byteBuf);
}
byteBuf.writeByte(friendlyFlags);
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_21_5)) {
ProtocolUtils.writeVarInt(byteBuf, nameTagVisibility.ordinal());
ProtocolUtils.writeVarInt(byteBuf, collisionRule.ordinal());
} else {
ProtocolUtils.writeString(byteBuf, nameTagVisibility.getValue());
ProtocolUtils.writeString(byteBuf, collisionRule.getValue());
}
if (protocolVersion.greaterThan(ProtocolVersion.MINECRAFT_1_12_2)) {
ProtocolUtils.writeVarInt(byteBuf, color);
new ComponentHolder(protocolVersion, prefix).write(byteBuf);
new ComponentHolder(protocolVersion, suffix).write(byteBuf);
} else {
byteBuf.writeByte((byte) color);
}
// Fallthrough since players are at the end of the packet!
case ADD_PLAYER, REMOVE_PLAYER:
ProtocolUtils.writeVarInt(byteBuf, players.size());
for (String player : players) {
ProtocolUtils.writeString(byteBuf, player);
}
break;
case REMOVE:
break;
}
}
}
@@ -0,0 +1,48 @@
/*
* 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.util;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.UserConfig;
import lombok.experimental.UtilityClass;
import java.util.HashMap;
import java.util.Map;
@UtilityClass
public class SteamwarPrefix {
private static final String PREFIX_MODE_CONFIG = "chatprefix";
private static final String PREFIX_MODE_SW = "SW";
private static final Map<SteamwarUser, Boolean> usesSwPrefix = new HashMap<>();
public static boolean usesSWPrefix(SteamwarUser user) {
return usesSwPrefix.computeIfAbsent(user, u -> PREFIX_MODE_SW.equals(UserConfig.getConfig(u.getId(), PREFIX_MODE_CONFIG)));
}
public static void setSWPrefix(SteamwarUser user, boolean preferSW) {
UserConfig.updatePlayerConfig(user.getId(), PREFIX_MODE_CONFIG, preferSW ? PREFIX_MODE_SW : null);
usesSwPrefix.put(user, preferSW);
}
public static void clearCache() {
usesSwPrefix.clear();
}
}
+22
View File
@@ -49,6 +49,10 @@ class DevServer extends DefaultTask {
@Optional @Optional
Map<String, String> dParams = new HashMap<>() Map<String, String> dParams = new HashMap<>()
@Input
@Optional
String jvmArgs = null
@Input @Input
@Optional @Optional
String checkpointFolder = null String checkpointFolder = null
@@ -82,6 +86,7 @@ class DevServer extends DefaultTask {
if (worldName == null) worldName = properties.get("worldName") if (worldName == null) worldName = properties.get("worldName")
host = properties.get("host") host = properties.get("host")
debugPort = new Random().nextInt(5001, 10000)
if (host == null) { if (host == null) {
throw new GradleException("Please supply the 'host' in a 'steamwar.properties' files either in this project dir or any parent project!") throw new GradleException("Please supply the 'host' in a 'steamwar.properties' files either in this project dir or any parent project!")
@@ -90,6 +95,7 @@ class DevServer extends DefaultTask {
doLast { doLast {
setupTemplate(template) setupTemplate(template)
uploadDependencies() uploadDependencies()
startDebugPort()
startDevServer() startDevServer()
} }
finalizedBy(new Finalizer()) finalizedBy(new Finalizer())
@@ -101,6 +107,9 @@ class DevServer extends DefaultTask {
@Internal @Internal
String host String host
@Internal
int debugPort
@Internal @Internal
Boolean running = true Boolean running = true
@@ -209,6 +218,17 @@ class DevServer extends DefaultTask {
} }
} }
void startDebugPort() {
def process = new ProcessBuilder("ssh", host, "-L", "5005:localhost:$debugPort").start()
def processOutput = new BufferedReader(new InputStreamReader(process.inputStream))
new Thread({
while (running) {
}
processOutput.close()
process.errorStream.close()
}).start()
}
void startDevServer() { void startDevServer() {
def devPy = new StringBuilder().append("dev.py") def devPy = new StringBuilder().append("dev.py")
if (port != null) devPy.append(" --port $port") if (port != null) devPy.append(" --port $port")
@@ -221,6 +241,8 @@ class DevServer extends DefaultTask {
devPy.append(" -D${dParam.key}=${dParam.value}") devPy.append(" -D${dParam.key}=${dParam.value}")
} }
devPy.append(" $template") devPy.append(" $template")
devPy.append(" -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:$debugPort")
if (jvmArgs != null) devPy.append(" $jvmArgs")
println("Starting $template with command ${devPy.toString()}") println("Starting $template with command ${devPy.toString()}")
def process = new ProcessBuilder("ssh", host, "-T", devPy.toString()).start() def process = new ProcessBuilder("ssh", host, "-T", devPy.toString()).start()
+1 -1
View File
@@ -122,7 +122,7 @@ dependencyResolutionManagement {
library("fawe", "de.steamwar:fastasyncworldedit:1.21") library("fawe", "de.steamwar:fastasyncworldedit:1.21")
library("velocity", "de.steamwar:velocity:RELEASE") library("velocity", "de.steamwar:velocity:RELEASE")
library("velocityapi", "com.velocitypowered:velocity-api:3.3.0-SNAPSHOT") library("velocityapi", "com.velocitypowered:velocity-api:3.5.0-SNAPSHOT")
library("viaapi", "com.viaversion:viaversion-api:4.3.1") library("viaapi", "com.viaversion:viaversion-api:4.3.1")
library("viavelocity", "com.viaversion:viaversion-velocity:4.3.1") library("viavelocity", "com.viaversion:viaversion-velocity:4.3.1")
library("jda", "net.dv8tion:JDA:5.5.1") library("jda", "net.dv8tion:JDA:5.5.1")