Compare commits

..

1 Commits

Author SHA1 Message Date
YoyoNow b2b803aca6 Remove unused code from Laufbau
Pull Request Build / Build (pull_request) Successful in 1m28s
2026-06-12 12:24:46 +02:00
50 changed files with 145 additions and 4205 deletions
@@ -25,7 +25,6 @@ import de.steamwar.bausystem.configplayer.ConfigConverter;
import de.steamwar.bausystem.features.gui.BauGUI;
import de.steamwar.bausystem.features.script.lua.SteamWarLuaPlugin;
import de.steamwar.bausystem.features.script.lua.libs.LuaLib;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.panzern.Panzern;
import de.steamwar.bausystem.features.slaves.panzern.PanzernAlgorithm;
import de.steamwar.bausystem.features.tracer.TraceManager;
@@ -112,9 +111,6 @@ public class BauSystem extends JavaPlugin implements Listener {
if (any instanceof ConfigConverter) {
Config.addConfigConverter((ConfigConverter) any);
}
if (any instanceof BoundingBoxLoader) {
((BoundingBoxLoader) any).load();
}
}
};
try {
@@ -19,28 +19,17 @@
package de.steamwar.bausystem.features.slaves.laufbau;
import com.sk89q.worldedit.blocks.SkullBlock;
import com.sk89q.worldedit.world.block.BaseBlock;
import de.steamwar.inventory.SWItem;
import lombok.Getter;
import lombok.ToString;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.block.data.type.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.function.Consumer;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@ToString
@Getter
public class BlockBoundingBox {
@@ -92,197 +81,4 @@ public class BlockBoundingBox {
public double volume() {
return volume;
}
static {
addPixel(Material.AIR.createBlockData(), 0, 0, 0, 0, 0, 0, null);
// 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.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));
Cocoa cocoaNorth = (Cocoa) Material.COCOA.createBlockData();
cocoaNorth.setAge(2);
cocoaNorth.setFacing(BlockFace.NORTH);
addPixel(cocoaNorth, 4, 3, 1, 8, 9, 8, createItem("LAUFBAU_BLOCK_COCOA", Material.COCOA_BEANS, "LAUFBAU_FACING_NORTH"));
Cocoa cocoaSouth = (Cocoa) Material.COCOA.createBlockData();
cocoaSouth.setAge(2);
cocoaSouth.setFacing(BlockFace.SOUTH);
addPixel(cocoaSouth, 4, 3, 7, 8, 9, 8, createItem("LAUFBAU_BLOCK_COCOA", Material.COCOA_BEANS, "LAUFBAU_FACING_SOUTH"));
Cocoa cocoaWest = (Cocoa) Material.COCOA.createBlockData();
cocoaWest.setAge(2);
cocoaWest.setFacing(BlockFace.WEST);
addPixel(cocoaWest, 1, 3, 4, 8, 9, 8, createItem("LAUFBAU_BLOCK_COCOA", Material.COCOA_BEANS, "LAUFBAU_FACING_WEST"));
Cocoa cocoaEast = (Cocoa) Material.COCOA.createBlockData();
cocoaEast.setAge(2);
cocoaEast.setFacing(BlockFace.EAST);
addPixel(cocoaEast, 7, 3, 4, 8, 9, 8, createItem("LAUFBAU_BLOCK_COCOA", Material.COCOA_BEANS, "LAUFBAU_FACING_EAST"));
TurtleEgg singleTurtleEgg = (TurtleEgg) Material.TURTLE_EGG.createBlockData();
singleTurtleEgg.setEggs(1);
singleTurtleEgg.setHatch(0);
addPixel(singleTurtleEgg, 4, 0, 3, 9, 7, 9, createItem("LAUFBAU_BLOCK_TURTLE_EGG", Material.TURTLE_EGG, "LAUFBAU_COUNT_1"));
TurtleEgg doubleTurtleEgg = (TurtleEgg) Material.TURTLE_EGG.createBlockData();
doubleTurtleEgg.setEggs(2);
doubleTurtleEgg.setHatch(0);
addPixel(doubleTurtleEgg, 1, 0, 1, 14, 7, 14, createItem("LAUFBAU_BLOCK_TURTLE_EGG", Material.TURTLE_EGG, "LAUFBAU_COUNT_2"));
addPixel(Material.CHEST.createBlockData(), 1, 0, 1, 14, 14, 14, createItem("LAUFBAU_BLOCK_CHEST", Material.CHEST));
Snow snowLayers8 = (Snow) Material.SNOW.createBlockData();
snowLayers8.setLayers(8);
addPixel(snowLayers8, 0, 0, 0, 16, 14, 16, createItem("LAUFBAU_BLOCK_SNOW", Material.SNOW, "LAUFBAU_LAYERS_8"));
Directional headNorth = (Directional) Material.PLAYER_WALL_HEAD.createBlockData();
headNorth.setFacing(BlockFace.NORTH);
addPixel(headNorth, 4, 4, 8, 8, 8, 8, createItem("LAUFBAU_BLOCK_PLAYER_WALL_HEAD", Material.PLAYER_HEAD, "LAUFBAU_FACING_NORTH"), BlockBoundingBox::randomPlayerHead);
Directional headSouth = (Directional) Material.PLAYER_WALL_HEAD.createBlockData();
headSouth.setFacing(BlockFace.SOUTH);
addPixel(headSouth, 4, 4, 0, 8, 8, 8, createItem("LAUFBAU_BLOCK_PLAYER_WALL_HEAD", Material.PLAYER_HEAD, "LAUFBAU_FACING_SOUTH"), BlockBoundingBox::randomPlayerHead);
Directional headWest = (Directional) Material.PLAYER_WALL_HEAD.createBlockData();
headWest.setFacing(BlockFace.WEST);
addPixel(headWest, 8, 4, 4, 8, 8, 8, createItem("LAUFBAU_BLOCK_PLAYER_WALL_HEAD", Material.PLAYER_HEAD, "LAUFBAU_FACING_WEST"), BlockBoundingBox::randomPlayerHead);
Directional headEast = (Directional) Material.PLAYER_WALL_HEAD.createBlockData();
headEast.setFacing(BlockFace.EAST);
addPixel(headEast, 0, 4, 4, 8, 8, 8, createItem("LAUFBAU_BLOCK_PLAYER_WALL_HEAD", Material.PLAYER_HEAD, "LAUFBAU_FACING_EAST"), BlockBoundingBox::randomPlayerHead);
Snow snowLayers7 = (Snow) Material.SNOW.createBlockData();
snowLayers7.setLayers(7);
addPixel(snowLayers7, 0, 0, 0, 16, 12, 16, createItem("LAUFBAU_BLOCK_SNOW", Material.SNOW, "LAUFBAU_LAYERS_7"));
Snow snowLayers6 = (Snow) Material.SNOW.createBlockData();
snowLayers6.setLayers(6);
addPixel(snowLayers6, 0, 0, 0, 16, 10, 16, createItem("LAUFBAU_BLOCK_SNOW", Material.SNOW, "LAUFBAU_LAYERS_6"));
addPixel(Material.STONECUTTER.createBlockData(), 0, 0, 0, 16, 9, 16, createItem("LAUFBAU_BLOCK_STONECUTTER", Material.STONECUTTER));
addPixel(Material.PLAYER_HEAD.createBlockData(), 4, 0, 4, 8, 8, 8, createItem("LAUFBAU_BLOCK_PLAYER_HEAD", Material.PLAYER_HEAD), BlockBoundingBox::randomPlayerHead);
addPixel(Material.CAKE.createBlockData(), 1, 0, 1, 14, 8, 14, createItem("LAUFBAU_BLOCK_CAKE", Material.CAKE));
Slab bottomSlab = (Slab) Material.END_STONE_BRICK_SLAB.createBlockData();
bottomSlab.setType(Slab.Type.BOTTOM);
addPixel(bottomSlab, 0, 0, 0, 16, 8, 16, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_SLAB", Material.END_STONE_BRICK_SLAB, "LAUFBAU_TYPE_BOTTOM"));
Slab topSlab = (Slab) Material.END_STONE_BRICK_SLAB.createBlockData();
topSlab.setType(Slab.Type.TOP);
addPixel(topSlab, 0, 8, 0, 16, 8, 16, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_SLAB", Material.END_STONE_BRICK_SLAB, "LAUFBAU_TYPE_TOP"));
SeaPickle quadSeaPickle = (SeaPickle) Material.SEA_PICKLE.createBlockData();
quadSeaPickle.setWaterlogged(false);
quadSeaPickle.setPickles(4);
addPixel(quadSeaPickle, 2, 0, 2, 12, 7, 12, createItem("LAUFBAU_BLOCK_SEA_PICKLE", Material.SEA_PICKLE, "LAUFBAU_COUNT_4"));
Campfire campfire = (Campfire) Material.CAMPFIRE.createBlockData();
campfire.setSignalFire(false);
campfire.setLit(false);
addPixel(campfire, 0, 0, 0, 16, 7, 16, createItem("LAUFBAU_BLOCK_CAMPFIRE", Material.CAMPFIRE));
SeaPickle trippleSeaPickle = (SeaPickle) Material.SEA_PICKLE.createBlockData();
trippleSeaPickle.setWaterlogged(false);
trippleSeaPickle.setPickles(3);
addPixel(trippleSeaPickle, 2, 0, 2, 12, 6, 12, createItem("LAUFBAU_BLOCK_SEA_PICKLE", Material.SEA_PICKLE, "LAUFBAU_COUNT_3"));
SeaPickle doubleSeaPickle = (SeaPickle) Material.SEA_PICKLE.createBlockData();
doubleSeaPickle.setWaterlogged(false);
doubleSeaPickle.setPickles(2);
addPixel(doubleSeaPickle, 3, 0, 3, 10, 6, 10, createItem("LAUFBAU_BLOCK_SEA_PICKLE", Material.SEA_PICKLE, "LAUFBAU_COUNT_2"));
SeaPickle singleSeaPickle = (SeaPickle) Material.SEA_PICKLE.createBlockData();
singleSeaPickle.setWaterlogged(false);
singleSeaPickle.setPickles(1);
addPixel(singleSeaPickle, 6, 0, 6, 4, 6, 4, createItem("LAUFBAU_BLOCK_SEA_PICKLE", Material.SEA_PICKLE, "LAUFBAU_COUNT_1"));
addPixel(Material.FLOWER_POT.createBlockData(), 5, 0, 5, 6, 6, 6, createItem("LAUFBAU_BLOCK_FLOWER_POT", Material.FLOWER_POT));
Snow snowLayers3 = (Snow) Material.SNOW.createBlockData();
snowLayers3.setLayers(3);
addPixel(snowLayers3, 0, 0, 0, 16, 4, 16, createItem("LAUFBAU_BLOCK_SNOW", Material.SNOW, "LAUFBAU_LAYERS_3"));
TrapDoor bottomTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
bottomTrapDoor.setHalf(Bisected.Half.BOTTOM);
addPixel(bottomTrapDoor, 0, 0, 0, 16, 3, 16, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_HALF_BOTTOM"));
TrapDoor topTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
topTrapDoor.setHalf(Bisected.Half.TOP);
addPixel(topTrapDoor, 0, 13, 0, 16, 3, 16, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_HALF_TOP"));
Snow snowLayers2 = (Snow) Material.SNOW.createBlockData();
snowLayers2.setLayers(2);
addPixel(snowLayers2, 0, 0, 0, 16, 2, 16, createItem("LAUFBAU_BLOCK_SNOW", Material.SNOW, "LAUFBAU_LAYERS_2"));
addPixel(Material.LILY_PAD.createBlockData(), 1, 0, 1, 14, 1.5, 14, createItem("LAUFBAU_BLOCK_LILY_PAD", Material.LILY_PAD));
addPixel(Material.WHITE_CARPET.createBlockData(), 0, 0, 0, 16, 1, 16, createItem("LAUFBAU_BLOCK_WHITE_CARPET", Material.WHITE_CARPET));
Directional endRodBottomTop = (Directional) Material.END_ROD.createBlockData();
endRodBottomTop.setFacing(BlockFace.UP);
addPixel(endRodBottomTop, 6, 0, 6, 4, 16, 4, createItem("LAUFBAU_BLOCK_END_ROD", Material.END_ROD, "LAUFBAU_FACING_UP", "LAUFBAU_FACING_DOWN"));
Directional endRodNorthSouth = (Directional) Material.END_ROD.createBlockData();
endRodNorthSouth.setFacing(BlockFace.NORTH);
addPixel(endRodNorthSouth, 6, 6, 0, 4, 4, 16, createItem("LAUFBAU_BLOCK_END_ROD", Material.END_ROD, "LAUFBAU_FACING_NORTH", "LAUFBAU_FACING_SOUTH"));
Directional endRodEastWest = (Directional) Material.END_ROD.createBlockData();
endRodEastWest.setFacing(BlockFace.EAST);
addPixel(endRodEastWest, 0, 6, 6, 16, 4, 4, createItem("LAUFBAU_BLOCK_END_ROD", Material.END_ROD, "LAUFBAU_FACING_EAST", "LAUFBAU_FACING_WEST"));
Directional lightningRodBottomTop = (Directional) Material.LIGHTNING_ROD.createBlockData();
lightningRodBottomTop.setFacing(BlockFace.UP);
addPixel(lightningRodBottomTop, 6, 0, 6, 4, 16, 4, createItem("LAUFBAU_BLOCK_LIGHTNING_ROD", Material.LIGHTNING_ROD, "LAUFBAU_FACING_UP", "LAUFBAU_FACING_DOWN"));
Directional lightningRodNorthSouth = (Directional) Material.LIGHTNING_ROD.createBlockData();
lightningRodNorthSouth.setFacing(BlockFace.NORTH);
addPixel(lightningRodNorthSouth, 6, 6, 0, 4, 4, 16, createItem("LAUFBAU_BLOCK_LIGHTNING_ROD", Material.LIGHTNING_ROD, "LAUFBAU_FACING_NORTH", "LAUFBAU_FACING_SOUTH"));
Directional lightningRodEastWest = (Directional) Material.LIGHTNING_ROD.createBlockData();
lightningRodEastWest.setFacing(BlockFace.EAST);
addPixel(lightningRodEastWest, 0, 6, 6, 16, 4, 4, createItem("LAUFBAU_BLOCK_LIGHTNING_ROD", Material.LIGHTNING_ROD, "LAUFBAU_FACING_EAST", "LAUFBAU_FACING_WEST"));
Waterlogged conduit = (Waterlogged) Material.CONDUIT.createBlockData();
conduit.setWaterlogged(false);
addPixel(conduit, 5, 5, 5, 6, 6, 6, createItem("LAUFBAU_BLOCK_CONDUIT", Material.CONDUIT));
TrapDoor northTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
northTrapDoor.setFacing(BlockFace.NORTH);
northTrapDoor.setOpen(true);
addPixel(northTrapDoor, 0, 0, 13, 16, 16, 3, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_FACING_NORTH", "LAUFBAU_OPEN"));
TrapDoor southTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
southTrapDoor.setFacing(BlockFace.SOUTH);
southTrapDoor.setOpen(true);
addPixel(southTrapDoor, 0, 0, 0, 16, 16, 3, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_FACING_SOUTH", "LAUFBAU_OPEN"));
TrapDoor westTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
westTrapDoor.setFacing(BlockFace.WEST);
westTrapDoor.setOpen(true);
addPixel(westTrapDoor, 13, 0, 0, 3, 16, 16, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_FACING_WEST", "LAUFBAU_OPEN"));
TrapDoor eastTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
eastTrapDoor.setFacing(BlockFace.EAST);
eastTrapDoor.setOpen(true);
addPixel(eastTrapDoor, 0, 0, 0, 3, 16, 16, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_FACING_EAST", "LAUFBAU_OPEN"));
}
private static void addPixel(BlockData blockData, double xPixel, double yPixel, double zPixel, double dxPixel, double dyPixel, double dzPixel, SWItem swItem) {
new BlockBoundingBox(blockData, Arrays.asList(pixelCuboid(xPixel, yPixel, zPixel, dxPixel, dyPixel, dzPixel)), swItem);
}
private static void addPixel(BlockData blockData, double xPixel, double yPixel, double zPixel, double dxPixel, double dyPixel, double dzPixel, SWItem swItem, Consumer<BaseBlock> blockConsumer) {
new BlockBoundingBox(blockData, Arrays.asList(pixelCuboid(xPixel, yPixel, zPixel, dxPixel, dyPixel, dzPixel)), swItem, blockConsumer);
}
@SuppressWarnings("deprecation")
private static void randomPlayerHead(BaseBlock block) {
if (block instanceof SkullBlock) {
SkullBlock skullBlock = (SkullBlock) block;
skullBlock.setOwner(randomPlayerHead.get(random.nextInt(randomPlayerHead.size())).toString());
}
}
}
@@ -1,25 +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.features.slaves.laufbau;
public interface BoundingBoxLoader {
void load();
}
@@ -22,6 +22,7 @@ package de.steamwar.bausystem.features.slaves.laufbau;
import de.steamwar.bausystem.region.Point;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.bukkit.util.BoundingBox;
@Data
@AllArgsConstructor
@@ -33,6 +34,15 @@ public class Cuboid {
private double dy;
private double dz;
public Cuboid(BoundingBox boundingBox) {
this.x = boundingBox.getMinX();
this.y = boundingBox.getMinY();
this.z = boundingBox.getMinZ();
this.dx = boundingBox.getWidthX();
this.dy = boundingBox.getHeight();
this.dz = boundingBox.getWidthZ();
}
public boolean intersects(Cuboid cuboid) {
double minx = x - cuboid.dx;
double miny = y - cuboid.dy;
@@ -24,15 +24,52 @@ import de.steamwar.bausystem.SWUtils;
import de.steamwar.bausystem.shared.Pair;
import de.steamwar.bausystem.utils.WorldEditUtils;
import de.steamwar.command.SWCommand;
import de.steamwar.inventory.SWItem;
import de.steamwar.linkage.Linked;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.phys.shapes.CollisionContext;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Registry;
import org.bukkit.craftbukkit.block.CraftBlockType;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.craftbukkit.util.CraftVoxelShape;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.VoxelShape;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
@Linked
public class LaufbauCommand extends SWCommand {
static {
AtomicLong counter = new AtomicLong();
AtomicReference<VoxelShape> shape = new AtomicReference<>();
long time = System.currentTimeMillis();
Registry.BLOCK.forEach(blockType -> {
Block block = CraftBlockType.bukkitToMinecraftNew(blockType);
block.getStateDefinition().getPossibleStates().forEach(blockState -> {
VoxelShape voxelShape = new CraftVoxelShape(blockState.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO, CollisionContext.empty()));
shape.set(voxelShape);
Material material = blockType.asMaterial();
if (!material.isItem()) return;
new BlockBoundingBox(
CraftBlockData.createData(blockState),
voxelShape.getBoundingBoxes().stream().map(Cuboid::new).collect(Collectors.toList()),
new SWItem(material, "Item")
);
counter.incrementAndGet();
});
});
System.out.println(System.currentTimeMillis() - time + "ms " + shape.get() + " " + counter.get());
}
public LaufbauCommand() {
super("laufbau", "laufsklave");
}
@@ -1,261 +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.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.AmethystCluster;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class AmethystBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
floorSmallAmethystBud();
ceilingSmallAmethystBud();
northSmallAmethystBud();
southSmallAmethystBud();
eastSmallAmethystBud();
westSmallAmethystBud();
floorMediumAmethystBud();
ceilingMediumAmethystBud();
northMediumAmethystBud();
southMediumAmethystBud();
eastMediumAmethystBud();
westMediumAmethystBud();
floorLargeAmethystBud();
ceilingLargeAmethystBud();
northLargeAmethystBud();
southLargeAmethystBud();
eastLargeAmethystBud();
westLargeAmethystBud();
floorAmethystCluster();
ceilingAmethystCluster();
northAmethystCluster();
southAmethystCluster();
eastAmethystCluster();
westAmethystCluster();
}
private void floorSmallAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.SMALL_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.UP);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 0, 4, 8, 3, 8));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_SMALL_AMETHYST_BUD", Material.SMALL_AMETHYST_BUD, "LAUFBAU_FACING_UP"));
}
private void ceilingSmallAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.SMALL_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.DOWN);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 13, 4, 8, 3, 8));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_SMALL_AMETHYST_BUD", Material.SMALL_AMETHYST_BUD, "LAUFBAU_FACING_DOWN"));
}
private void northSmallAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.SMALL_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 13, 8, 8, 3));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_SMALL_AMETHYST_BUD", Material.SMALL_AMETHYST_BUD, "LAUFBAU_FACING_NORTH"));
}
private void southSmallAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.SMALL_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 0, 8, 8, 3));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_SMALL_AMETHYST_BUD", Material.SMALL_AMETHYST_BUD, "LAUFBAU_FACING_SOUTH"));
}
private void eastSmallAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.SMALL_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 4, 4, 3, 8, 8));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_SMALL_AMETHYST_BUD", Material.SMALL_AMETHYST_BUD, "LAUFBAU_FACING_EAST"));
}
private void westSmallAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.SMALL_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(13, 4, 4, 3, 8, 8));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_SMALL_AMETHYST_BUD", Material.SMALL_AMETHYST_BUD, "LAUFBAU_FACING_WEST"));
}
private void floorMediumAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.MEDIUM_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.UP);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 0, 3, 10, 4, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_MEDIUM_AMETHYST_BUD", Material.MEDIUM_AMETHYST_BUD, "LAUFBAU_FACING_UP"));
}
private void ceilingMediumAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.MEDIUM_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.DOWN);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 12, 3, 10, 4, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_MEDIUM_AMETHYST_BUD", Material.MEDIUM_AMETHYST_BUD, "LAUFBAU_FACING_DOWN"));
}
private void northMediumAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.MEDIUM_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 3, 12, 10, 10, 4));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_MEDIUM_AMETHYST_BUD", Material.MEDIUM_AMETHYST_BUD, "LAUFBAU_FACING_NORTH"));
}
private void southMediumAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.MEDIUM_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 3, 0, 10, 10, 4));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_MEDIUM_AMETHYST_BUD", Material.MEDIUM_AMETHYST_BUD, "LAUFBAU_FACING_SOUTH"));
}
private void eastMediumAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.MEDIUM_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 3, 3, 4, 10, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_MEDIUM_AMETHYST_BUD", Material.MEDIUM_AMETHYST_BUD, "LAUFBAU_FACING_EAST"));
}
private void westMediumAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.MEDIUM_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(12, 3, 3, 4, 10, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_MEDIUM_AMETHYST_BUD", Material.MEDIUM_AMETHYST_BUD, "LAUFBAU_FACING_WEST"));
}
private void floorLargeAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.LARGE_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.UP);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 0, 3, 10, 5, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_LARGE_AMETHYST_BUD", Material.LARGE_AMETHYST_BUD, "LAUFBAU_FACING_UP"));
}
private void ceilingLargeAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.LARGE_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.DOWN);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 11, 3, 10, 5, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_LARGE_AMETHYST_BUD", Material.LARGE_AMETHYST_BUD, "LAUFBAU_FACING_DOWN"));
}
private void northLargeAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.LARGE_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 3, 11, 10, 10, 5));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_LARGE_AMETHYST_BUD", Material.LARGE_AMETHYST_BUD, "LAUFBAU_FACING_NORTH"));
}
private void southLargeAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.LARGE_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 3, 0, 10, 10, 5));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_LARGE_AMETHYST_BUD", Material.LARGE_AMETHYST_BUD, "LAUFBAU_FACING_SOUTH"));
}
private void eastLargeAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.LARGE_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 3, 3, 5, 10, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_LARGE_AMETHYST_BUD", Material.LARGE_AMETHYST_BUD, "LAUFBAU_FACING_EAST"));
}
private void westLargeAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.LARGE_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(11, 3, 3, 5, 10, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_LARGE_AMETHYST_BUD", Material.LARGE_AMETHYST_BUD, "LAUFBAU_FACING_WEST"));
}
private void floorAmethystCluster() {
AmethystCluster cluster = (AmethystCluster) Material.AMETHYST_CLUSTER.createBlockData();
cluster.setFacing(BlockFace.UP);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 0, 3, 10, 7, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_AMETHYST_CLUSTER", Material.AMETHYST_CLUSTER, "LAUFBAU_FACING_UP"));
}
private void ceilingAmethystCluster() {
AmethystCluster cluster = (AmethystCluster) Material.AMETHYST_CLUSTER.createBlockData();
cluster.setFacing(BlockFace.DOWN);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 9, 3, 10, 7, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_AMETHYST_CLUSTER", Material.AMETHYST_CLUSTER, "LAUFBAU_FACING_DOWN"));
}
private void northAmethystCluster() {
AmethystCluster cluster = (AmethystCluster) Material.AMETHYST_CLUSTER.createBlockData();
cluster.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 3, 9, 10, 10, 7));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_AMETHYST_CLUSTER", Material.AMETHYST_CLUSTER, "LAUFBAU_FACING_NORTH"));
}
private void southAmethystCluster() {
AmethystCluster cluster = (AmethystCluster) Material.AMETHYST_CLUSTER.createBlockData();
cluster.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 3, 0, 10, 10, 7));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_AMETHYST_CLUSTER", Material.AMETHYST_CLUSTER, "LAUFBAU_FACING_SOUTH"));
}
private void eastAmethystCluster() {
AmethystCluster cluster = (AmethystCluster) Material.AMETHYST_CLUSTER.createBlockData();
cluster.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 3, 3, 7, 10, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_AMETHYST_CLUSTER", Material.AMETHYST_CLUSTER, "LAUFBAU_FACING_EAST"));
}
private void westAmethystCluster() {
AmethystCluster cluster = (AmethystCluster) Material.AMETHYST_CLUSTER.createBlockData();
cluster.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(9, 3, 3, 7, 10, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_AMETHYST_CLUSTER", Material.AMETHYST_CLUSTER, "LAUFBAU_FACING_WEST"));
}
}
@@ -1,46 +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.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class AzaleaBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
BlockData blockData = Material.FLOWERING_AZALEA.createBlockData();
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(6, 0, 6, 4, 8, 4));
new BlockBoundingBox(blockData, cuboidList, createItem("LAUFBAU_BLOCK_AZALEA", Material.FLOWERING_AZALEA));
}
}
@@ -1,149 +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.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.Bell;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class BellBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
ceilingBell();
floorNorthBell();
floorEastBell();
doubleWallNorthBell();
doubleWallEastBell();
singleWallNorthBell();
singleWallSouthBell();
singleWallEastBell();
singleWallWestBell();
}
public void ceilingBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.CEILING);
bell.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 4, 8, 2, 8));
cuboidList.add(pixelCuboid(5, 6, 5, 6, 8, 6));
cuboidList.add(pixelCuboid(7, 13, 7, 2, 3, 2));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_CEILING"));
}
public void floorNorthBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.FLOOR);
bell.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 4, 16, 16, 8));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_FLOOR", "LAUFBAU_FACING_NORTH", "LAUFBAU_FACING_SOUTH"));
}
public void floorEastBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.FLOOR);
bell.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 0, 0, 8, 16, 16));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_FLOOR", "LAUFBAU_FACING_EAST", "LAUFBAU_FACING_WEST"));
}
public void doubleWallNorthBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.DOUBLE_WALL);
bell.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 4, 8, 2, 8));
cuboidList.add(pixelCuboid(5, 6, 5, 6, 8, 6));
cuboidList.add(pixelCuboid(7, 13, 0, 2, 2, 16));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_DOUBLE_WALL", "LAUFBAU_FACING_NORTH"));
}
public void doubleWallEastBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.DOUBLE_WALL);
bell.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 4, 8, 2, 8));
cuboidList.add(pixelCuboid(5, 6, 5, 6, 8, 6));
cuboidList.add(pixelCuboid(0, 13, 7, 16, 2, 2));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_DOUBLE_WALL", "LAUFBAU_FACING_EAST"));
}
public void singleWallNorthBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.SINGLE_WALL);
bell.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 4, 8, 2, 8));
cuboidList.add(pixelCuboid(5, 6, 5, 6, 8, 6));
cuboidList.add(pixelCuboid(7, 13, 0, 2, 2, 13));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_SINGLE_WALL", "LAUFBAU_FACING_NORTH"));
}
public void singleWallSouthBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.SINGLE_WALL);
bell.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 4, 8, 2, 8));
cuboidList.add(pixelCuboid(5, 6, 5, 6, 8, 6));
cuboidList.add(pixelCuboid(7, 13, 3, 2, 2, 13));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_SINGLE_WALL", "LAUFBAU_FACING_SOUTH"));
}
public void singleWallEastBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.SINGLE_WALL);
bell.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 4, 8, 2, 8));
cuboidList.add(pixelCuboid(5, 6, 5, 6, 8, 6));
cuboidList.add(pixelCuboid(3, 13, 7, 13, 2, 2));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_SINGLE_WALL", "LAUFBAU_FACING_EAST"));
}
public void singleWallWestBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.SINGLE_WALL);
bell.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 4, 8, 2, 8));
cuboidList.add(pixelCuboid(5, 6, 5, 6, 8, 6));
cuboidList.add(pixelCuboid(0, 13, 7, 13, 2, 2));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_SINGLE_WALL", "LAUFBAU_FACING_WEST"));
}
}
@@ -1,46 +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.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.data.type.BrewingStand;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class BrewingStandBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
BrewingStand brewingStand = (BrewingStand) Material.BREWING_STAND.createBlockData();
List<Cuboid> cuboids = new ArrayList<>();
cuboids.add(pixelCuboid(1, 0, 1, 14, 2, 14));
cuboids.add(pixelCuboid(7, 2, 7, 2, 12, 2));
new BlockBoundingBox(brewingStand, cuboids, createItem("LAUFBAU_BLOCK_BREWING_STAND", Material.BREWING_STAND));
}
}
@@ -1,62 +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.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.data.Lightable;
import org.bukkit.block.data.type.Candle;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class CandleBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
caked();
single();
}
private void caked() {
Lightable candleCake = (Lightable) Material.CYAN_CANDLE_CAKE.createBlockData();
candleCake.setLit(true);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(7, 8, 7, 2, 6, 2));
new BlockBoundingBox(candleCake, cuboidList, createItem("LAUFBAU_BLOCK_CANDLE_CAKE", Material.CAKE));
}
private void single() {
Candle candle = (Candle) Material.CYAN_CANDLE.createBlockData();
candle.setCandles(1);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(7, 0, 7, 2, 6, 2));
new BlockBoundingBox(candle, cuboidList, createItem("LAUFBAU_BLOCK_CANDLE", Material.CYAN_CANDLE, "LAUFBAU_COUNT_1"));
}
}
@@ -1,69 +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.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Axis;
import org.bukkit.Material;
import org.bukkit.block.data.Orientable;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class ChainBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
bottomTopChain();
northSouthChain();
eastWestChain();
}
private void bottomTopChain() {
Orientable chainBottomTop = (Orientable) Material.CHAIN.createBlockData();
chainBottomTop.setAxis(Axis.Y);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(6.5, 0, 6.5, 3, 16, 3));
new BlockBoundingBox(chainBottomTop, cuboidList, createItem("LAUFBAU_BLOCK_CHAIN", Material.CHAIN, "LAUFBAU_FACING_UP", "LAUFBAU_FACING_DOWN"));
}
private void northSouthChain() {
Orientable chainBottomTop = (Orientable) Material.CHAIN.createBlockData();
chainBottomTop.setAxis(Axis.Z);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(6.5, 6.5, 0, 3, 3, 16));
new BlockBoundingBox(chainBottomTop, cuboidList, createItem("LAUFBAU_BLOCK_CHAIN", Material.CHAIN, "LAUFBAU_FACING_NORTH", "LAUFBAU_FACING_SOUTH"));
}
private void eastWestChain() {
Orientable chainBottomTop = (Orientable) Material.CHAIN.createBlockData();
chainBottomTop.setAxis(Axis.X);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 6.5, 6.5, 16, 3, 3));
new BlockBoundingBox(chainBottomTop, cuboidList, createItem("LAUFBAU_BLOCK_CHAIN", Material.CHAIN, "LAUFBAU_FACING_EAST", "LAUFBAU_FACING_WEST"));
}
}
@@ -1,89 +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.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.MultipleFacing;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class ChorusPlantBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
for (int nx = 0; nx < 2; nx++) {
for (int ny = 0; ny < 2; ny++) {
for (int nz = 0; nz < 2; nz++) {
for (int px = 0; px < 2; px++) {
for (int py = 0; py < 2; py++) {
for (int pz = 0; pz < 2; pz++) {
MultipleFacing chorusPlant = (MultipleFacing) Material.CHORUS_PLANT.createBlockData();
List<String> lore = new ArrayList<>();
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 3, 3, 10, 10, 10));
if (nx == 1) {
lore.add("LAUFBAU_CONNECTION_WEST");
chorusPlant.setFace(BlockFace.WEST, true);
cuboidList.add(pixelCuboid(0, 3, 3, 3, 10, 10));
}
if (ny == 1) {
lore.add("LAUFBAU_CONNECTION_DOWN");
chorusPlant.setFace(BlockFace.DOWN, true);
cuboidList.add(pixelCuboid(3, 0, 3, 10, 3, 10));
}
if (nz == 1) {
lore.add("LAUFBAU_CONNECTION_NORTH");
chorusPlant.setFace(BlockFace.NORTH, true);
cuboidList.add(pixelCuboid(3, 3, 0, 10, 10, 3));
}
if (px == 1) {
lore.add("LAUFBAU_CONNECTION_EAST");
chorusPlant.setFace(BlockFace.EAST, true);
cuboidList.add(pixelCuboid(13, 3, 3, 3, 10, 10));
}
if (py == 1) {
lore.add("LAUFBAU_CONNECTION_UP");
chorusPlant.setFace(BlockFace.UP, true);
cuboidList.add(pixelCuboid(3, 13, 3, 10, 3, 10));
}
if (pz == 1) {
lore.add("LAUFBAU_CONNECTION_SOUTH");
chorusPlant.setFace(BlockFace.SOUTH, true);
cuboidList.add(pixelCuboid(3, 3, 13, 10, 10, 3));
}
new BlockBoundingBox(chorusPlant, cuboidList, createItem("LAUFBAU_BLOCK_CHORUS_PLANT", Material.CHORUS_PLANT, lore.toArray(new String[0])));
}
}
}
}
}
}
}
}
@@ -1,45 +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.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class DragonEggBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
BlockData blockData = Material.DRAGON_EGG.createBlockData();
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(1, 0, 1, 14, 16, 14));
new BlockBoundingBox(blockData, cuboidList, createItem("LAUFBAU_BLOCK_DRAGON_EGG", Material.DRAGON_EGG));
}
}
@@ -1,59 +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.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.data.type.BigDripleaf;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class DripLeafBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
tiltNone();
tiltPartial();
}
private void tiltNone() {
BigDripleaf bigDripleaf = (BigDripleaf) Material.BIG_DRIPLEAF.createBlockData();
bigDripleaf.setTilt(BigDripleaf.Tilt.NONE);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 11, 0, 16, 4, 16));
new BlockBoundingBox(bigDripleaf, cuboidList, createItem("LAUFBAU_BLOCK_BIG_DRIP_LEAF", Material.BIG_DRIPLEAF, "LAUFBAU_TILT_NONE"));
}
private void tiltPartial() {
BigDripleaf bigDripleaf = (BigDripleaf) Material.BIG_DRIPLEAF.createBlockData();
bigDripleaf.setTilt(BigDripleaf.Tilt.PARTIAL);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 11, 0, 16, 2, 16));
new BlockBoundingBox(bigDripleaf, cuboidList, createItem("LAUFBAU_BLOCK_BIG_DRIP_LEAF", Material.BIG_DRIPLEAF, "LAUFBAU_TILT_PARTIAL"));
}
}
@@ -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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.Fence;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class FencesBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
for (int nx = 0; nx < 2; nx++) {
for (int nz = 0; nz < 2; nz++) {
for (int px = 0; px < 2; px++) {
for (int pz = 0; pz < 2; pz++) {
Fence fence = (Fence) Material.NETHER_BRICK_FENCE.createBlockData();
List<String> lore = new ArrayList<>();
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(6, 0, 6, 4, 24, 4));
if (nz == 1) {
lore.add("LAUFBAU_CONNECTION_NORTH");
fence.setFace(BlockFace.NORTH, true);
cuboidList.add(pixelCuboid(6, 0, 0, 4, 24, 6));
}
if (pz == 1) {
lore.add("LAUFBAU_CONNECTION_SOUTH");
fence.setFace(BlockFace.SOUTH, true);
cuboidList.add(pixelCuboid(6, 0, 10, 4, 24, 6));
}
if (nx == 1) {
lore.add("LAUFBAU_CONNECTION_WEST");
fence.setFace(BlockFace.WEST, true);
cuboidList.add(pixelCuboid(0, 0, 6, 6, 24, 4));
}
if (px == 1) {
lore.add("LAUFBAU_CONNECTION_EAST");
fence.setFace(BlockFace.EAST, true);
cuboidList.add(pixelCuboid(10, 0, 6, 6, 24, 4));
}
new BlockBoundingBox(fence, cuboidList, createItem("LAUFBAU_BLOCK_NETHER_BRICK_FENCE", Material.NETHER_BRICK_FENCE, lore.toArray(new String[0])));
}
}
}
}
}
}
@@ -1,157 +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.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.FaceAttachable;
import org.bukkit.block.data.type.Grindstone;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class GrindstoneBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
floorNorthGrindstone();
floorEastGrindstone();
ceilingNorthGrindstone();
ceilingEastGrindstone();
wallNorthGrindstone();
wallSouthGrindstone();
wallEastGrindstone();
wallWestGrindstone();
}
public void floorNorthGrindstone() {
Grindstone grindstone = (Grindstone) Material.GRINDSTONE.createBlockData();
grindstone.setAttachedFace(FaceAttachable.AttachedFace.FLOOR);
grindstone.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 2, 8, 12, 12));
cuboidList.add(pixelCuboid(2, 0, 6, 2, 7, 4));
cuboidList.add(pixelCuboid(12, 0, 6, 2, 7, 4));
cuboidList.add(pixelCuboid(2, 7, 5, 2, 6, 6));
cuboidList.add(pixelCuboid(12, 7, 5, 2, 6, 6));
new BlockBoundingBox(grindstone, cuboidList, createItem("LAUFBAU_BLOCK_GRINDSTONE", Material.GRINDSTONE, "LAUFBAU_ATTACHMENT_FLOOR", "LAUFBAU_FACING_NORTH", "LAUFBAU_FACING_SOUTH"));
}
public void floorEastGrindstone() {
Grindstone grindstone = (Grindstone) Material.GRINDSTONE.createBlockData();
grindstone.setAttachedFace(FaceAttachable.AttachedFace.FLOOR);
grindstone.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(2, 4, 4, 12, 12, 8));
cuboidList.add(pixelCuboid(6, 0, 2, 4, 7, 2));
cuboidList.add(pixelCuboid(6, 0, 12, 4, 7, 2));
cuboidList.add(pixelCuboid(5, 7, 2, 6, 6, 2));
cuboidList.add(pixelCuboid(5, 7, 12, 6, 6, 2));
new BlockBoundingBox(grindstone, cuboidList, createItem("LAUFBAU_BLOCK_GRINDSTONE", Material.GRINDSTONE, "LAUFBAU_ATTACHMENT_FLOOR", "LAUFBAU_FACING_EAST", "LAUFBAU_FACING_WEST"));
}
public void ceilingNorthGrindstone() {
Grindstone grindstone = (Grindstone) Material.GRINDSTONE.createBlockData();
grindstone.setAttachedFace(FaceAttachable.AttachedFace.CEILING);
grindstone.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 0, 2, 8, 12, 12));
cuboidList.add(pixelCuboid(2, 9, 6, 2, 7, 4));
cuboidList.add(pixelCuboid(12, 9, 6, 2, 7, 4));
cuboidList.add(pixelCuboid(2, 3, 5, 2, 6, 6));
cuboidList.add(pixelCuboid(12, 3, 5, 2, 6, 6));
new BlockBoundingBox(grindstone, cuboidList, createItem("LAUFBAU_BLOCK_GRINDSTONE", Material.GRINDSTONE, "LAUFBAU_ATTACHMENT_CEILING", "LAUFBAU_FACING_NORTH", "LAUFBAU_FACING_SOUTH"));
}
public void ceilingEastGrindstone() {
Grindstone grindstone = (Grindstone) Material.GRINDSTONE.createBlockData();
grindstone.setAttachedFace(FaceAttachable.AttachedFace.CEILING);
grindstone.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(2, 0, 4, 12, 12, 8));
cuboidList.add(pixelCuboid(6, 9, 2, 4, 7, 2));
cuboidList.add(pixelCuboid(6, 9, 12, 4, 7, 2));
cuboidList.add(pixelCuboid(5, 3, 2, 6, 6, 2));
cuboidList.add(pixelCuboid(5, 3, 12, 6, 6, 2));
new BlockBoundingBox(grindstone, cuboidList, createItem("LAUFBAU_BLOCK_GRINDSTONE", Material.GRINDSTONE, "LAUFBAU_ATTACHMENT_CEILING", "LAUFBAU_FACING_EAST", "LAUFBAU_FACING_WEST"));
}
public void wallNorthGrindstone() {
Grindstone grindstone = (Grindstone) Material.GRINDSTONE.createBlockData();
grindstone.setAttachedFace(FaceAttachable.AttachedFace.WALL);
grindstone.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 2, 0, 8, 12, 12));
cuboidList.add(pixelCuboid(2, 6, 9, 2, 4, 7));
cuboidList.add(pixelCuboid(12, 6, 9, 2, 4, 7));
cuboidList.add(pixelCuboid(2, 5, 3, 2, 6, 6));
cuboidList.add(pixelCuboid(12, 5, 3, 2, 6, 6));
new BlockBoundingBox(grindstone, cuboidList, createItem("LAUFBAU_BLOCK_GRINDSTONE", Material.GRINDSTONE, "LAUFBAU_ATTACHMENT_WALL", "LAUFBAU_FACING_NORTH"));
}
public void wallSouthGrindstone() {
Grindstone grindstone = (Grindstone) Material.GRINDSTONE.createBlockData();
grindstone.setAttachedFace(FaceAttachable.AttachedFace.WALL);
grindstone.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 2, 4, 8, 12, 12));
cuboidList.add(pixelCuboid(2, 6, 0, 2, 4, 7));
cuboidList.add(pixelCuboid(12, 6, 0, 2, 4, 7));
cuboidList.add(pixelCuboid(2, 5, 7, 2, 6, 6));
cuboidList.add(pixelCuboid(12, 5, 7, 2, 6, 6));
new BlockBoundingBox(grindstone, cuboidList, createItem("LAUFBAU_BLOCK_GRINDSTONE", Material.GRINDSTONE, "LAUFBAU_ATTACHMENT_WALL", "LAUFBAU_FACING_SOUTH"));
}
public void wallEastGrindstone() {
Grindstone grindstone = (Grindstone) Material.GRINDSTONE.createBlockData();
grindstone.setAttachedFace(FaceAttachable.AttachedFace.WALL);
grindstone.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 2, 4, 12, 12, 8));
cuboidList.add(pixelCuboid(0, 6, 2, 7, 4, 2));
cuboidList.add(pixelCuboid(0, 6, 12, 7, 4, 2));
cuboidList.add(pixelCuboid(7, 5, 2, 6, 6, 2));
cuboidList.add(pixelCuboid(7, 5, 12, 6, 6, 2));
new BlockBoundingBox(grindstone, cuboidList, createItem("LAUFBAU_BLOCK_GRINDSTONE", Material.GRINDSTONE, "LAUFBAU_ATTACHMENT_WALL", "LAUFBAU_FACING_EAST"));
}
public void wallWestGrindstone() {
Grindstone grindstone = (Grindstone) Material.GRINDSTONE.createBlockData();
grindstone.setAttachedFace(FaceAttachable.AttachedFace.WALL);
grindstone.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 2, 4, 12, 12, 8));
cuboidList.add(pixelCuboid(9, 6, 2, 7, 4, 2));
cuboidList.add(pixelCuboid(9, 6, 12, 7, 4, 2));
cuboidList.add(pixelCuboid(3, 5, 2, 6, 6, 2));
cuboidList.add(pixelCuboid(3, 5, 12, 6, 6, 2));
new BlockBoundingBox(grindstone, cuboidList, createItem("LAUFBAU_BLOCK_GRINDSTONE", Material.GRINDSTONE, "LAUFBAU_ATTACHMENT_WALL", "LAUFBAU_FACING_WEST"));
}
}
@@ -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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.Hopper;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class HopperBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
downHopper();
northHopper();
southHopper();
eastHopper();
westHopper();
}
public void downHopper() {
Hopper hopper = (Hopper) Material.HOPPER.createBlockData();
hopper.setFacing(BlockFace.DOWN);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 10, 0, 16, 6, 16));
cuboidList.add(pixelCuboid(4, 4, 4, 8, 6, 8));
cuboidList.add(pixelCuboid(6, 0, 6, 4, 4, 4));
new BlockBoundingBox(hopper, cuboidList, createItem("LAUFBAU_BLOCK_HOPPER", Material.HOPPER, "LAUFBAU_CONNECTION_FLOOR"));
}
public void northHopper() {
Hopper hopper = (Hopper) Material.HOPPER.createBlockData();
hopper.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 10, 0, 16, 6, 16));
cuboidList.add(pixelCuboid(4, 4, 4, 8, 6, 8));
cuboidList.add(pixelCuboid(6, 4, 0, 4, 4, 4));
new BlockBoundingBox(hopper, cuboidList, createItem("LAUFBAU_BLOCK_HOPPER", Material.HOPPER, "LAUFBAU_CONNECTION_NORTH"));
}
public void southHopper() {
Hopper hopper = (Hopper) Material.HOPPER.createBlockData();
hopper.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 10, 0, 16, 6, 16));
cuboidList.add(pixelCuboid(4, 4, 4, 8, 6, 8));
cuboidList.add(pixelCuboid(6, 4, 12, 4, 4, 4));
new BlockBoundingBox(hopper, cuboidList, createItem("LAUFBAU_BLOCK_HOPPER", Material.HOPPER, "LAUFBAU_CONNECTION_SOUTH"));
}
public void eastHopper() {
Hopper hopper = (Hopper) Material.HOPPER.createBlockData();
hopper.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 10, 0, 16, 6, 16));
cuboidList.add(pixelCuboid(4, 4, 4, 8, 6, 8));
cuboidList.add(pixelCuboid(12, 4, 6, 4, 4, 4));
new BlockBoundingBox(hopper, cuboidList, createItem("LAUFBAU_BLOCK_HOPPER", Material.HOPPER, "LAUFBAU_CONNECTION_EAST"));
}
public void westHopper() {
Hopper hopper = (Hopper) Material.HOPPER.createBlockData();
hopper.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 10, 0, 16, 6, 16));
cuboidList.add(pixelCuboid(4, 4, 4, 8, 6, 8));
cuboidList.add(pixelCuboid(0, 4, 6, 4, 4, 4));
new BlockBoundingBox(hopper, cuboidList, createItem("LAUFBAU_BLOCK_HOPPER", Material.HOPPER, "LAUFBAU_CONNECTION_WEST"));
}
}
@@ -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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.Fence;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class IronBarBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
for (int nx = 0; nx < 2; nx++) {
for (int nz = 0; nz < 2; nz++) {
for (int px = 0; px < 2; px++) {
for (int pz = 0; pz < 2; pz++) {
Fence fence = (Fence) Material.IRON_BARS.createBlockData();
List<String> lore = new ArrayList<>();
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(7, 0, 7, 2, 16, 2));
if (nz == 1) {
lore.add("LAUFBAU_CONNECTION_NORTH");
fence.setFace(BlockFace.NORTH, true);
cuboidList.add(pixelCuboid(7, 0, 0, 2, 16, 7));
}
if (pz == 1) {
lore.add("LAUFBAU_CONNECTION_SOUTH");
fence.setFace(BlockFace.SOUTH, true);
cuboidList.add(pixelCuboid(7, 0, 9, 2, 16, 7));
}
if (nx == 1) {
lore.add("LAUFBAU_CONNECTION_WEST");
fence.setFace(BlockFace.WEST, true);
cuboidList.add(pixelCuboid(0, 0, 7, 7, 16, 2));
}
if (px == 1) {
lore.add("LAUFBAU_CONNECTION_EAST");
fence.setFace(BlockFace.EAST, true);
cuboidList.add(pixelCuboid(9, 0, 7, 7, 16, 2));
}
new BlockBoundingBox(fence, cuboidList, createItem("LAUFBAU_BLOCK_IRON_BARS", Material.IRON_BARS, lore.toArray(new String[0])));
}
}
}
}
}
}
@@ -1,61 +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.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.data.type.Lantern;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class LanternBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
lantern();
hangingLantern();
}
public void lantern() {
Lantern lantern = (Lantern) Material.LANTERN.createBlockData();
lantern.setHanging(false);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(5, 0, 5, 6, 7, 6));
cuboidList.add(pixelCuboid(6, 7, 6, 4, 2, 4));
new BlockBoundingBox(lantern, cuboidList, createItem("LAUFBAU_BLOCK_LANTERN", Material.LANTERN));
}
public void hangingLantern() {
Lantern lantern = (Lantern) Material.LANTERN.createBlockData();
lantern.setHanging(true);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(5, 1, 5, 6, 7, 6));
cuboidList.add(pixelCuboid(6, 8, 6, 4, 2, 4));
new BlockBoundingBox(lantern, cuboidList, createItem("LAUFBAU_BLOCK_LANTERN", Material.LANTERN, "LAUFBAU_HANGING"));
}
}
@@ -1,46 +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.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class LecternBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
BlockData blockData = Material.LECTERN.createBlockData();
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 2, 16));
cuboidList.add(pixelCuboid(4, 2, 4, 8, 12, 8));
new BlockBoundingBox(blockData, cuboidList, createItem("LAUFBAU_BLOCK_LECTERN", Material.LECTERN));
}
}
@@ -1,343 +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.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.Stairs;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class StairBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
straightBottomNorthStair();
straightBottomSouthStair();
straightBottomEastStair();
straightBottomWestStair();
straightTopNorthStair();
straightTopSouthStair();
straightTopEastStair();
straightTopWestStair();
outerLeftBottomNorthStair();
outerLeftBottomSouthStair();
outerLeftBottomEastStair();
outerLeftBottomWestStair();
outerLeftTopNorthStair();
outerLeftTopSouthStair();
outerLeftTopEastStair();
outerLeftTopWestStair();
innerLeftBottomNorthStair();
innerLeftBottomSouthStair();
innerLeftBottomEastStair();
innerLeftBottomWestStair();
innerLeftTopNorthStair();
innerLeftTopSouthStair();
innerLeftTopEastStair();
innerLeftTopWestStair();
}
public void straightBottomNorthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.STRAIGHT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_STRAIGHT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_NORTH"));
}
public void straightBottomSouthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.STRAIGHT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 8, 16, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_STRAIGHT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_SOUTH"));
}
public void straightBottomEastStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.STRAIGHT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(8, 8, 0, 8, 8, 16));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_STRAIGHT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_EAST"));
}
public void straightBottomWestStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.STRAIGHT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 0, 8, 8, 16));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_STRAIGHT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_WEST"));
}
public void straightTopNorthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.STRAIGHT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_STRAIGHT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_NORTH"));
}
public void straightTopSouthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.STRAIGHT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 8, 16, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_STRAIGHT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_SOUTH"));
}
public void straightTopEastStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.STRAIGHT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(8, 0, 0, 8, 8, 16));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_STRAIGHT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_EAST"));
}
public void straightTopWestStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.STRAIGHT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 0, 8, 8, 16));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_STRAIGHT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_WEST"));
}
public void outerLeftBottomNorthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.OUTER_LEFT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 0, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_OUTER_LEFT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_NORTH"));
}
public void outerLeftBottomSouthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.OUTER_LEFT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(8, 8, 8, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_OUTER_LEFT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_SOUTH"));
}
public void outerLeftBottomEastStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.OUTER_LEFT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(8, 8, 0, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_OUTER_LEFT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_EAST"));
}
public void outerLeftBottomWestStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.OUTER_LEFT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 8, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_OUTER_LEFT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_WEST"));
}
public void outerLeftTopNorthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.OUTER_LEFT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 0, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_OUTER_LEFT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_NORTH"));
}
public void outerLeftTopSouthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.OUTER_LEFT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(8, 0, 8, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_OUTER_LEFT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_SOUTH"));
}
public void outerLeftTopEastStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.OUTER_LEFT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(8, 0, 0, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_OUTER_LEFT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_EAST"));
}
public void outerLeftTopWestStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.OUTER_LEFT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 8, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_OUTER_LEFT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_WEST"));
}
public void innerLeftBottomNorthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.INNER_LEFT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 8));
cuboidList.add(pixelCuboid(0, 8, 8, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_INNER_LEFT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_NORTH"));
}
public void innerLeftBottomSouthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.INNER_LEFT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 8, 16, 8, 8));
cuboidList.add(pixelCuboid(8, 8, 0, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_INNER_LEFT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_SOUTH"));
}
public void innerLeftBottomEastStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.INNER_LEFT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 8));
cuboidList.add(pixelCuboid(8, 8, 8, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_INNER_LEFT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_EAST"));
}
public void innerLeftBottomWestStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.INNER_LEFT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 8, 16, 8, 8));
cuboidList.add(pixelCuboid(0, 8, 0, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_INNER_LEFT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_WEST"));
}
public void innerLeftTopNorthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.INNER_LEFT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 8));
cuboidList.add(pixelCuboid(0, 0, 8, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_INNER_LEFT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_NORTH"));
}
public void innerLeftTopSouthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.INNER_LEFT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 8, 16, 8, 8));
cuboidList.add(pixelCuboid(8, 0, 0, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_INNER_LEFT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_SOUTH"));
}
public void innerLeftTopEastStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.INNER_LEFT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 8));
cuboidList.add(pixelCuboid(8, 0, 8, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_INNER_LEFT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_EAST"));
}
public void innerLeftTopWestStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.INNER_LEFT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 8, 16, 8, 8));
cuboidList.add(pixelCuboid(0, 0, 0, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_INNER_LEFT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_WEST"));
}
}
@@ -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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.Wall;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class WallBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
v18();
}
private void v18() {
for (int nx = 0; nx < 2; nx++) {
for (int nz = 0; nz < 2; nz++) {
for (int px = 0; px < 2; px++) {
for (int pz = 0; pz < 2; pz++) {
Wall fence = (Wall) Material.END_STONE_BRICK_WALL.createBlockData();
List<String> lore = new ArrayList<>();
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 0, 4, 8, 24, 8));
if (nz == 1) {
lore.add("LAUFBAU_CONNECTION_NORTH");
fence.setHeight(BlockFace.NORTH, Wall.Height.LOW);
cuboidList.add(pixelCuboid(5, 0, 0, 6, 24, 4));
}
if (pz == 1) {
lore.add("LAUFBAU_CONNECTION_SOUTH");
fence.setHeight(BlockFace.SOUTH, Wall.Height.LOW);
cuboidList.add(pixelCuboid(5, 0, 12, 6, 24, 4));
}
if (nx == 1) {
lore.add("LAUFBAU_CONNECTION_WEST");
fence.setHeight(BlockFace.WEST, Wall.Height.LOW);
cuboidList.add(pixelCuboid(0, 0, 5, 4, 24, 6));
}
if (px == 1) {
lore.add("LAUFBAU_CONNECTION_EAST");
fence.setHeight(BlockFace.EAST, Wall.Height.LOW);
cuboidList.add(pixelCuboid(12, 0, 5, 4, 24, 6));
}
new BlockBoundingBox(fence, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_WALL", Material.END_STONE_BRICK_WALL, lore.toArray(new String[0])));
}
}
}
}
}
}
@@ -139,7 +139,6 @@ public class NoClipCommand extends SWCommand implements Listener {
@EventHandler(ignoreCancelled = true)
public void onBlock(BlockCanBuildEvent event) {
if (event.getPlayer() == null) return;
if (SWPlayer.of(event.getPlayer()).hasComponent(NoClipData.class)) {
event.setBuildable(true);
}
@@ -57,7 +57,7 @@ public class WorldEditListener implements Listener {
private static final Set<String> commands = new HashSet<>();
private static final Set<String> commandExclusions = new HashSet<>();
private static final String[] shortcutCommands = {"//1", "//2", "//90", "//-90", "//180", "//p", "//c", "//flopy", "//floppy", "//flopyp", "//floppyp", "//u", "//r", "//download", "/download"};
private static final String[] shortcutCommands = {"//1", "//2", "//90", "//-90", "//180", "//p", "//c", "//flopy", "//floppy", "//flopyp", "//floppyp", "//u", "//r"};
public static boolean isWorldEditCommand(String command) {
for (String shortcut : shortcutCommands) {
+1
View File
@@ -37,5 +37,6 @@ tasks.register<DevServer>("DevBau21") {
dependsOn(":SpigotCore:shadowJar")
dependsOn(":BauSystem:shadowJar")
dependsOn(":SchematicSystem:shadowJar")
dependsOn(":KotlinCore:shadowJar")
template = "Bau21"
}
-1
View File
@@ -18,7 +18,6 @@ dependencies {
implementation("com.github.ajalt.clikt:clikt:5.0.3")
implementation("com.github.ajalt.mordant:mordant:3.0.2")
implementation(libs.logback)
implementation("org.yaml:snakeyaml:2.2")
implementation("org.mariadb.jdbc:mariadb-java-client:3.3.1")
implementation(libs.exposedCore)
+9 -62
View File
@@ -14,11 +14,9 @@ import com.github.ajalt.clikt.parameters.types.file
import com.github.ajalt.clikt.parameters.types.long
import com.github.ajalt.clikt.parameters.types.path
import com.sun.security.auth.module.UnixSystem
import org.yaml.snakeyaml.Yaml
import java.io.File
import kotlin.io.path.absolute
import kotlin.io.path.absolutePathString
import kotlin.random.Random
const val LOG4J_CONFIG = """<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="com.mojang.util">
@@ -71,42 +69,32 @@ class DevCommand : CliktCommand("dev") {
override fun run() {
val args = mutableListOf<String>()
var serverDir = resolveServerDirectory(server)
val serverDirectory = File(workingDir, server)
val serverDir =
if (serverDirectory.exists() && serverDirectory.isDirectory) serverDirectory else File(workingDir, server)
if (isVelocity(server)) {
runServer(
args, jvmArgs, listOf(
jar?.absolutePath
?: File("/jars/Velocity.jar").absolutePath
?: File("/jar/Velocity.jar").absolutePath
), serverDir
)
} else {
setLogConfig(args)
val version = findVersion(server)
?: throw CliktError("Unknown Server Version")
val gameModeTemplate = if (serverDir.isDirectory) null else loadGameModeTemplate(server)
if (gameModeTemplate != null) {
serverDir = gameModeTemplate.serverDir
args += "-Dconfig=$server.yml"
}
val worldFile = world?.absolute()?.toFile()
?: File(workingDir, "devtempworld")
var jarFile = jar?.absolutePath
?: File(serverDir, "devtempworld")
val jarFile = jar?.absolutePath
?: additionalVersions[server]?.let { supportedVersionJars[it] }
?: supportedVersionJars[version]
?: throw CliktError("Unknown Server Version")
if (gameModeTemplate != null) {
jarFile = if (gameModeTemplate.spigot) {
jarFile.replace("paper", "spigot")
} else {
jarFile.replace("spigot", "paper")
}
}
if (!worldFile.exists()) {
val templateFile = gameModeTemplate?.worldTemplate ?: File(serverDir, "Bauwelt")
val templateFile = File(serverDir, "Bauwelt")
if (!templateFile.exists()) {
throw CliktError("Could not find world template: ${templateFile.absolutePath}")
throw CliktError("World Template not found!")
}
templateFile.copyRecursively(worldFile)
}
@@ -135,12 +123,6 @@ class DevCommand : CliktCommand("dev") {
}
}
data class GameModeTemplate(
val serverDir: File,
val worldTemplate: File,
val spigot: Boolean
)
val jvmDefaultParams = arrayOf(
"-Xmx1G",
"-Xgc:excessiveGCratio=80",
@@ -183,41 +165,6 @@ class DevCommand : CliktCommand("dev") {
fun isVelocity(server: String): Boolean =
server.endsWith("Velocity")
fun resolveServerDirectory(server: String): File {
val localServer = File(workingDir, server)
if (localServer.isDirectory) {
return localServer
}
return File("/servers", server)
}
fun loadGameModeTemplate(server: String): GameModeTemplate? {
val configFile = File("/configs/GameModes/$server.yml")
if (!configFile.exists()) {
throw CliktError("Server/GameMode not found")
}
val document = configFile.reader().use { reader ->
Yaml().load<Map<String, Any?>>(reader)
} ?: throw CliktError("GameMode config is empty: ${configFile.absolutePath}")
val serverConfig = document["Server"] as? Map<*, *>
?: throw CliktError("GameMode config is missing Server section: ${configFile.absolutePath}")
val folder = serverConfig["Folder"] as? String
?: throw CliktError("GameMode config is missing Server.Folder: ${configFile.absolutePath}")
val maps = (serverConfig["Maps"] as? List<*>)
?.filterIsInstance<String>()
?.takeIf { it.isNotEmpty() }
?: throw CliktError("GameMode config is missing Server.Maps: ${configFile.absolutePath}")
val serverDir = File("/servers", folder)
val worldTemplate = File(File(serverDir, "arenas"), maps[Random.nextInt(maps.size)])
return GameModeTemplate(
serverDir = serverDir,
worldTemplate = worldTemplate,
spigot = serverConfig["Spigot"] == true
)
}
fun setLogConfig(args: MutableList<String>) {
args += "-DlogPath=${workingDir.absolutePath}/logs"
args += "-Dlog4j.configurationFile=${log4jConfig.absolutePath}"
@@ -243,4 +190,4 @@ class DevCommand : CliktCommand("dev") {
Runtime.getRuntime().addShutdownHook(Thread { if (process.isAlive) process.destroyForcibly() })
process.waitFor()
}
}
}
@@ -86,24 +86,6 @@ class CheckedSchematic(id: EntityID<CompositeID>) : CompositeEntity(id) {
useDb {
find { (CheckedSchematicTable.nodeOwner eq owner.id) and (CheckedSchematicTable.seen eq false) }.orderBy(CheckedSchematicTable.endTime to SortOrder.DESC).toList()
}
@JvmStatic
fun countAccepted(owner: SteamwarUser) =
useDb {
find { (CheckedSchematicTable.nodeOwner eq owner.id) and (CheckedSchematicTable.declineReason eq "freigegeben") }.count()
}
@JvmStatic
fun countAccepted(owner: SteamwarUser, type: String) =
useDb {
find { (CheckedSchematicTable.nodeOwner eq owner.id) and (CheckedSchematicTable.declineReason eq "freigegeben") and (CheckedSchematicTable.nodeType like "$type%") }.count()
}
@JvmStatic
fun countChecked(validator: SteamwarUser) =
useDb {
find { CheckedSchematicTable.validator eq validator.id }.count()
}
}
val node by CheckedSchematicTable.nodeId.transform({ it?.let { EntityID(it, SchematicNodeTable) } }, { it?.value })
@@ -130,43 +130,6 @@ class EventFight(id: EntityID<Int>) : IntEntity(id), Comparable<EventFight> {
}
)
}
@JvmStatic
fun countEventFights(fighter: SteamwarUser) =
useDb {
exec(
"SELECT COUNT(DISTINCT F.FightID) AS FightCount FROM FightPlayer INNER JOIN Fight F on FightPlayer.FightID = F.FightID INNER JOIN EventFight EF on F.FightID = EF.Fight WHERE UserID = ?",
args = listOf(IntegerColumnType() to fighter.id.value)
) {
if (it.next()) {
it.getLong("FightCount")
} else {
0
}
}
?: 0
}
@JvmStatic
fun countPlacement(fighter: SteamwarUser, placement: Int) =
useDb {
exec(
"""
SELECT COUNT(DISTINCT EventFight.EventID) AS PlacementCount FROM TeamTeilnahme
INNER JOIN EventFight ON EventFight.EventID = TeamTeilnahme.EventID
INNER JOIN FightPlayer ON FightPlayer.FightID = EventFight.Fight
WHERE (IF(FightPlayer.Team = 1, EventFight.TeamBlue, EventFight.TeamRed)) = TeamTeilnahme.TeamID AND UserID = ? AND Placement = ?
""".trimIndent(),
args = listOf(IntegerColumnType() to fighter.id.value, IntegerColumnType() to placement)
) {
if (it.next()) {
it.getInt("PlacementCount")
} else {
0
}
}
?: 0
}
}
val fightID by EventFightTable.id.transform({ EntityID(it, EventFightTable) }, { it.value })
@@ -20,12 +20,9 @@
package de.steamwar.sql
import de.steamwar.sql.internal.useDb
import org.jetbrains.exposed.v1.core.IntegerColumnType
import org.jetbrains.exposed.v1.core.VarCharColumnType
import org.jetbrains.exposed.v1.core.dao.id.CompositeID
import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable
import org.jetbrains.exposed.v1.core.dao.id.EntityID
import org.jetbrains.exposed.v1.core.eq
import org.jetbrains.exposed.v1.core.inList
import org.jetbrains.exposed.v1.dao.CompositeEntity
import org.jetbrains.exposed.v1.dao.CompositeEntityClass
@@ -72,28 +69,6 @@ class FightPlayer(id: EntityID<CompositeID>) : CompositeEntity(id) {
useDb {
find { FightPlayerTable.fightId inList fightIds.toList() }.toList()
}
@JvmStatic
fun countFights(userId: Int) =
useDb {
find { FightPlayerTable.userId eq userId }.count()
}
@JvmStatic
fun countFights(userId: Int, type: String) =
useDb {
exec(
"SELECT COUNT(*) AS FightCount FROM FightPlayer INNER JOIN Fight F on FightPlayer.FightID = F.FightID WHERE UserID = ? AND GameMode LIKE ?",
args = listOf(IntegerColumnType() to userId, VarCharColumnType() to "$type%")
) {
if (it.next()) {
it.getInt("FightCount")
} else {
0
}
}
?: 0
}
}
val fightID by FightPlayerTable.fightId.transform({ EntityID(it, FightTable) }, { it.value })
@@ -146,12 +146,12 @@ public final class GameModeConfig<M, W> {
public final List<String> CheckQuestions;
/**
* The allowed checkers to check this schematic type denoted by a list of SteamwarUser ids.
* The allowed checkers to check this schematic type denoted by a list of SteamWar ids.
* The people need the {@link UserPerm#CHECK} to be able to check though.
*
* @implSpec {@code []} by default -> denoting every person with {@link UserPerm#CHECK} can check it
*/
public final Set<Integer> Checkers;
public final List<Integer> Checkers;
/**
* Bundle for countdowns during the fight
@@ -246,7 +246,7 @@ public final class GameModeConfig<M, W> {
}
CheckQuestions = loader.getStringList("CheckQuestions");
Checkers = loader.getIntSet("Checkers");
Checkers = loader.getIntList("Checkers");
Times = new TimesConfig(loader.with("Times"));
// Arena would be here to be in config order but needs Schematic.Size and EnterStages loaded afterwards
Schematic = new SchematicConfig<>(loader.with("Schematic"));
@@ -139,12 +139,6 @@ final class YMLWrapper<M, W> {
return get(path, o -> (List<Integer>) o);
}
public Set<Integer> getIntSet(String path) {
List<Integer> list = get(path, o -> (List<Integer>) o);
if (list.isEmpty()) return Collections.emptySet();
return Collections.unmodifiableSet(new HashSet<>(list));
}
public List<SchematicType> getSchematicTypeList(String path) {
List<String> list = getStringList(path);
if (list.isEmpty()) {
+3 -3
View File
@@ -38,11 +38,11 @@ widener {
fromCatalog(libs.paperapi)
}
tasks.register<DevServer>("DevLobby") {
tasks.register<DevServer>("DevLobby20") {
group = "run"
description = "Run a Dev Lobby"
description = "Run a 1.20 Dev Lobby"
dependsOn(":SpigotCore:shadowJar")
dependsOn(":LobbySystem:jar")
template = "Lobby21"
template = "Lobby20"
worldName = "Lobby"
}
@@ -42,10 +42,7 @@ import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.Month;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
public class CustomMap implements Listener {
@@ -59,7 +56,7 @@ public class CustomMap implements Listener {
new Vector(2346, 45, 1297), new Vector(2345, 45, 1297), new Vector(2344, 45, 1297), new Vector(2343, 45, 1297), new Vector(2342, 45, 1297), new Vector(2341, 45, 1297), new Vector(2340, 45, 1297)
);
private static final CustomMap RIGHT = new CustomMap(new File(System.getProperty("user.home") + "/lobbyBanner/right/"),
private static final CustomMap RIGHT = new CustomMap(new File(System.getProperty("user.home") + "/lobbyBanner/right.png"),
new Vector(2330, 48, 1297), new Vector(2329, 48, 1297), new Vector(2328, 48, 1297), new Vector(2327, 48, 1297), new Vector(2326, 48, 1297), new Vector(2325, 48, 1297), new Vector(2324, 48, 1297),
new Vector(2330, 47, 1297), new Vector(2329, 47, 1297), new Vector(2328, 47, 1297), new Vector(2327, 47, 1297), new Vector(2326, 47, 1297), new Vector(2325, 47, 1297), new Vector(2324, 47, 1297),
new Vector(2330, 46, 1297), new Vector(2329, 46, 1297), new Vector(2328, 46, 1297), new Vector(2327, 46, 1297), new Vector(2326, 46, 1297), new Vector(2325, 46, 1297), new Vector(2324, 46, 1297),
@@ -69,49 +66,30 @@ public class CustomMap implements Listener {
private File mapFile;
private Map<Vector, Integer> itemFrameIndex = new HashMap<>();
private ItemFrame[] itemFrames;
private boolean update = true;
private long lastModified = Long.MAX_VALUE;
public CustomMap(File mapFileOrDirectory, Vector... itemFrames) {
this.mapFile = mapFileOrDirectory;
public CustomMap(File mapFile, Vector... itemFrames) {
this.mapFile = mapFile;
this.itemFrames = new ItemFrame[itemFrames.length];
for (int i = 0; i < itemFrames.length; i++) {
itemFrameIndex.put(itemFrames[i], i);
}
if (mapFileOrDirectory.isDirectory()) {
AtomicReference<Month> lastMonth = new AtomicReference<>(LocalDateTime.now().getMonth());
Bukkit.getScheduler().runTaskTimer(LobbySystem.getInstance(), () -> {
Month current = LocalDateTime.now().getMonth();
if (!current.equals(lastMonth.get()) || update) {
lastMonth.set(current);
update = false;
this.mapFile = new File(mapFileOrDirectory, current.getValue() + ".png");
update();
}
}, 200L, 1200L);
} else {
AtomicReference<Long> lastModified = new AtomicReference<>(Long.MAX_VALUE);
Bukkit.getScheduler().runTaskTimer(LobbySystem.getInstance(), () -> {
long modified = mapFileOrDirectory.lastModified();
if (modified > lastModified.get() || update) {
lastModified.set(modified);
update = false;
update();
}
}, 200L, 200L);
}
Bukkit.getPluginManager().registerEvents(this, LobbySystem.getInstance());
}
private void update() {
System.out.println("Updating Banner: " + mapFile.getName());
Bukkit.getScheduler().runTaskAsynchronously(LobbySystem.getInstance(), () -> {
try {
run();
} catch (IOException e) {
// Ignore
Bukkit.getScheduler().runTaskTimer(LobbySystem.getInstance(), () -> {
long modified = mapFile.lastModified();
if (modified > lastModified) {
lastModified = modified;
System.out.println("Updating Banner: " + mapFile.getName());
Bukkit.getScheduler().runTaskAsynchronously(LobbySystem.getInstance(), () -> {
try {
run();
} catch (IOException e) {
// Ignore
}
});
}
});
}, 200L, 200L);
Bukkit.getPluginManager().registerEvents(this, LobbySystem.getInstance());
}
@EventHandler
@@ -123,7 +101,7 @@ public class CustomMap implements Listener {
if (itemFrameIndex.containsKey(vector)) {
if (itemFrames[itemFrameIndex.get(vector)] != null) continue;
itemFrames[itemFrameIndex.get(vector)] = itemFrame;
update = true;
lastModified = 0;
ItemStack itemStack = new ItemStack(Material.FILLED_MAP, 1);
MapMeta mapMeta = (MapMeta) itemStack.getItemMeta();
+1 -11
View File
@@ -29,15 +29,5 @@ dependencies {
compileOnly(libs.paperapi)
compileOnly(libs.nms)
compileOnly(libs.fawe)
}
tasks.register<FightServer>("MissileWars21") {
group = "run"
description = "Run a 1.21 Dev MissileWars"
dependsOn(":SpigotCore:shadowJar")
dependsOn(":MissileWars:jar")
template = "MissileWars"
worldName = "Great_Wall"
jar = "/jars/paper-1.21.6.jar"
compileOnly(libs.worldedit)
}
@@ -30,8 +30,6 @@ import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockTypes;
import de.steamwar.misslewars.MissileWars;
@@ -111,17 +109,11 @@ public class Missile extends SpecialItem {
v = aT.apply(v.toVector3()).toBlockPoint();
v = v.add(location.getBlockX(), location.getBlockY(), location.getBlockZ());
EditSession e = WorldEdit.getInstance().getEditSessionFactory()
.getEditSession(world, -1);
e.setSideEffectApplier(SideEffectSet.defaults()
.with(SideEffect.NEIGHBORS, SideEffect.State.ON)
.with(SideEffect.LIGHTING, SideEffect.State.ON)
.with(SideEffect.UPDATE, SideEffect.State.ON));
EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, -1);
ClipboardHolder ch = new ClipboardHolder(clipboard);
ch.setTransform(aT);
Operations.completeBlindly(ch.createPaste(e).to(v).ignoreAirBlocks(true).build());
e.flushSession();
return true;
}
@@ -37,27 +37,17 @@ public class AutoChecker {
public static final AutoChecker impl = new AutoChecker();
public AutoCheckerResult check(Clipboard clipboard, GameModeConfig<Material, String> type) {
return AutoCheckerResult.builder()
.type(type)
.height(clipboard.getDimensions().y())
.width(clipboard.getDimensions().x())
.depth(clipboard.getDimensions().z())
.blockScanResult(scan(clipboard, type))
.entities(
clipboard.getEntities().stream()
.map(Entity::getLocation)
.map(blockVector3 -> new BlockPos(blockVector3.getBlockX(), blockVector3.getBlockY(), blockVector3.getBlockZ()))
.collect(Collectors.toList()))
return AutoCheckerResult.builder().type(type).height(clipboard.getDimensions().x()).width(clipboard.getDimensions().x())
.depth(clipboard.getDimensions().z()).blockScanResult(scan(clipboard, type))
.entities(clipboard.getEntities().stream().map(Entity::getLocation)
.map(blockVector3 -> new BlockPos(blockVector3.getBlockX(), blockVector3.getBlockY(), blockVector3.getBlockZ()))
.collect(Collectors.toList()))
.build();
}
public AutoCheckerResult sizeCheck(Clipboard clipboard, GameModeConfig<Material, String> type) {
return AutoCheckerResult.builder()
.type(type)
.height(clipboard.getDimensions().y())
.width(clipboard.getDimensions().x())
.depth(clipboard.getDimensions().z())
.build();
return AutoCheckerResult.builder().type(type).height(clipboard.getDimensions().y()).width(clipboard.getDimensions().x())
.depth(clipboard.getDimensions().z()).build();
}
public AutoChecker.BlockScanResult scan(Clipboard clipboard, GameModeConfig<Material, String> type) {
@@ -59,6 +59,8 @@ dependencies {
compileOnly(libs.netty)
compileOnly(libs.brigadier)
compileOnly(libs.fastutil)
implementation(libs.anvilgui)
}
widener {
@@ -1,890 +0,0 @@
package net.wesjd.anvilgui;
import lombok.Getter;
import lombok.NonNull;
import net.md_5.bungee.api.chat.BaseComponent;
import net.wesjd.anvilgui.version.VersionWrapper;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.*;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.Plugin;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.logging.Level;
/**
* An anvil gui, used for gathering a user's input
*
* @author Wesley Smith
* @since 1.0
*/
public class AnvilGUI {
/**
* The local {@link VersionWrapper} object for the server's version
*/
private static final VersionWrapper WRAPPER = VersionWrapper.INSTANCE;
/**
* The variable containing an item with air. Used when the item would be null.
* To keep the heap clean, this object only gets iniziaised once
*/
private static final ItemStack AIR = new ItemStack(Material.AIR);
/**
* If the given ItemStack is null, return an air ItemStack, otherwise return the given ItemStack
*
* @param stack The ItemStack to check
* @return air or the given ItemStack
*/
private static ItemStack itemNotNull(ItemStack stack) {
return stack == null ? AIR : stack;
}
/**
* The {@link Plugin} that this anvil GUI is associated with
*/
private final Plugin plugin;
/**
* The player who has the GUI open
*/
private final Player player;
/**
* An {@link Executor} that executes tasks on the main server thread
*/
private final Executor mainThreadExecutor;
/**
* The title of the anvil inventory
*/
private final Object titleComponent;
/**
* The initial contents of the inventory
*/
private final ItemStack[] initialContents;
/**
* A state that decides where the anvil GUI is able to get closed by the user
*/
private final boolean preventClose;
/**
* A set of slot numbers that are permitted to be interacted with by the user. An interactable
* slot is one that is able to be minipulated by the player, i.e. clicking and picking up an item,
* placing in a new one, etc.
*/
private final Set<Integer> interactableSlots;
/** An {@link Consumer} that is called when the anvil GUI is close */
private final Consumer<StateSnapshot> closeListener;
/** A flag that decides whether the async click handler can be run concurrently */
private final boolean concurrentClickHandlerExecution;
/** An {@link BiFunction} that is called when a slot is clicked */
private final ClickHandler clickHandler;
/**
* The container id of the inventory, used for NMS methods
*/
private int containerId;
/**
* The inventory that is used on the Bukkit side of things
*/
@Getter
private Inventory inventory;
/**
* The listener holder class
*/
private final ListenUp listener = new ListenUp();
/**
* Represents the state of the inventory being open
*/
private boolean open;
/**
* The actual container backing the Anvil GUI
*/
private VersionWrapper.AnvilContainerWrapper container;
/**
* Create an AnvilGUI
*
* @param plugin A {@link org.bukkit.plugin.java.JavaPlugin} instance
* @param player The {@link Player} to open the inventory for
* @param mainThreadExecutor An {@link Executor} that executes on the main server thread
* @param titleComponent What to have the text already set to
* @param initialContents The initial contents of the inventory
* @param preventClose Whether to prevent the inventory from closing
* @param closeListener A {@link Consumer} when the inventory closes
* @param concurrentClickHandlerExecution Flag to allow concurrent execution of the click handler
* @param clickHandler A {@link ClickHandler} that is called when the player clicks a slot
*/
private AnvilGUI(
Plugin plugin,
Player player,
Executor mainThreadExecutor,
Object titleComponent,
ItemStack[] initialContents,
boolean preventClose,
Set<Integer> interactableSlots,
Consumer<StateSnapshot> closeListener,
boolean concurrentClickHandlerExecution,
ClickHandler clickHandler) {
this.plugin = plugin;
this.player = player;
this.mainThreadExecutor = mainThreadExecutor;
this.titleComponent = titleComponent;
this.initialContents = initialContents;
this.preventClose = preventClose;
this.interactableSlots = Collections.unmodifiableSet(interactableSlots);
this.closeListener = closeListener;
this.concurrentClickHandlerExecution = concurrentClickHandlerExecution;
this.clickHandler = clickHandler;
}
/**
* Opens the anvil GUI
*/
private void openInventory() {
Bukkit.getPluginManager().registerEvents(listener, plugin);
container = WRAPPER.newContainerAnvil(player, titleComponent);
inventory = container.getBukkitInventory();
// We need to use setItem instead of setContents because a Minecraft ContainerAnvil
// contains two separate inventories: the result inventory and the ingredients inventory.
// The setContents method only updates the ingredients inventory unfortunately,
// but setItem handles the index going into the result inventory.
for (int i = 0; i < initialContents.length; i++) {
inventory.setItem(i, initialContents[i]);
}
containerId = WRAPPER.getNextContainerId(player, container);
WRAPPER.handleInventoryCloseEvent(player);
WRAPPER.sendPacketOpenWindow(player, containerId, titleComponent);
WRAPPER.setActiveContainer(player, container);
WRAPPER.setActiveContainerId(container, containerId);
WRAPPER.addActiveContainerSlotListener(container, player);
open = true;
}
/**
* Closes the inventory if it's open.
*/
public void closeInventory() {
closeInventory(true);
}
/**
* Closes the inventory if it's open, only sending the close inventory packets if the arg is true
*
* @param sendClosePacket Whether to send the close inventory event, packet, etc
*/
private void closeInventory(boolean sendClosePacket) {
if (!open) {
return;
}
open = false;
HandlerList.unregisterAll(listener);
inventory = container.getBukkitInventory();
// We need to use setItem instead of setContents because a Minecraft ContainerAnvil
// contains two separate inventories: the result inventory and the ingredients inventory.
// The setContents method only updates the ingredients inventory unfortunately,
// but setItem handles the index going into the result inventory.
for (int i = 0; i < initialContents.length; i++) {
inventory.setItem(i, new ItemStack(Material.AIR));
}
if (sendClosePacket) {
WRAPPER.handleInventoryCloseEvent(player);
WRAPPER.setActiveContainerDefault(player);
WRAPPER.sendPacketCloseWindow(player, containerId);
}
if (closeListener != null) {
closeListener.accept(StateSnapshot.fromAnvilGUI(this));
}
}
/**
* Updates the title of the AnvilGUI to the new one.
*
* @param literalTitle The title to use as literal text
* @param preserveRenameText Whether to preserve the entered rename text
* @throws IllegalArgumentException when literalTitle is null
* @see Builder#title(String)
*/
public void setTitle(@NonNull String literalTitle, boolean preserveRenameText) {
setTitle(WRAPPER.literalChatComponent(literalTitle), preserveRenameText);
}
/**
* Updates the title of the AnvilGUI to the new one.
*
* @param json The json used to parse into a rich chat component
* @param preserveRenameText Whether to preserve the entered rename text
* @throws IllegalArgumentException when json is null
* @see Builder#jsonTitle(String)
*/
public void setJsonTitle(@NonNull String json, boolean preserveRenameText) {
setTitle(WRAPPER.jsonChatComponent(json), preserveRenameText);
}
/**
* Updates the title of the AnvilGUI to the new one.
*
* @param title The title as a NMS ChatComponent
* @param preserveRenameText Whether to preserve the entered rename text
*/
private void setTitle(Object title, boolean preserveRenameText) {
String renameText = container.getRenameText();
WRAPPER.sendPacketOpenWindow(player, containerId, title);
if (preserveRenameText) {
// The renameText field is marked as @Nullable in newer versions
container.setRenameText(renameText == null ? "" : renameText);
}
}
/**
* Simply holds the listeners for the GUI
*/
private class ListenUp implements Listener {
/**
* Boolean storing the running status of the latest click handler to prevent double execution.
* All accesses to this boolean will be from the main server thread, except for the rare event
* that the plugin is disabled and the mainThreadExecutor throws an exception
*/
private boolean clickHandlerRunning = false;
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
if (!event.getInventory().equals(inventory)) {
return;
}
final int rawSlot = event.getRawSlot();
// ignore items dropped outside the window
if (rawSlot == -999) return;
final Player clicker = (Player) event.getWhoClicked();
final Inventory clickedInventory = event.getClickedInventory();
if (clickedInventory != null) {
if (clickedInventory.equals(clicker.getInventory())) {
// prevent players from merging items from the anvil inventory
if (event.getClick().equals(ClickType.DOUBLE_CLICK)) {
event.setCancelled(true);
return;
}
// prevent shift moving items from players inv to the anvil inventory
if (event.isShiftClick()) {
event.setCancelled(true);
return;
}
}
// prevent players from swapping items in the anvil gui
if ((event.getCursor() != null && event.getCursor().getType() != Material.AIR)
&& !interactableSlots.contains(rawSlot)
&& event.getClickedInventory().equals(inventory)) {
event.setCancelled(true);
return;
}
}
if (rawSlot < 3 && rawSlot >= 0 || event.getAction().equals(InventoryAction.MOVE_TO_OTHER_INVENTORY)) {
event.setCancelled(true);
if (clickHandlerRunning && !concurrentClickHandlerExecution) {
// A click handler is running, don't launch another one
return;
}
final CompletableFuture<List<ResponseAction>> actionsFuture =
clickHandler.apply(rawSlot, StateSnapshot.fromAnvilGUI(AnvilGUI.this));
final Consumer<List<ResponseAction>> actionsConsumer = actions -> {
for (final ResponseAction action : actions) {
action.accept(AnvilGUI.this, clicker);
}
};
if (actionsFuture.isDone()) {
// Fast-path without scheduling if clickHandler is performed in sync
// Because the future is already completed, .join() will not block the server thread
actionsFuture.thenAccept(actionsConsumer).join();
} else {
clickHandlerRunning = true;
// If the plugin is disabled and the Executor throws an exception, the exception will be passed to
// the .handle method
actionsFuture
.thenAcceptAsync(actionsConsumer, mainThreadExecutor)
.handle((results, exception) -> {
if (exception != null) {
plugin.getLogger()
.log(
Level.SEVERE,
"An exception occurred in the AnvilGUI clickHandler",
exception);
}
// Whether an exception occurred or not, set running to false
clickHandlerRunning = false;
return null;
});
}
}
}
@EventHandler
public void onInventoryDrag(InventoryDragEvent event) {
if (event.getInventory().equals(inventory)) {
event.setCancelled(true);
}
}
@EventHandler
public void onInventoryClose(InventoryCloseEvent event) {
if (open && event.getInventory().equals(inventory)) {
closeInventory(false);
if (preventClose) {
mainThreadExecutor.execute(AnvilGUI.this::openInventory);
}
}
}
}
/** A builder class for an {@link AnvilGUI} object */
public static class Builder {
/** An {@link Executor} that executes tasks on the main server thread */
private Executor mainThreadExecutor;
/** An {@link Consumer} that is called when the anvil GUI is close */
private Consumer<StateSnapshot> closeListener;
/** A flag that decides whether the async click handler can be run concurrently */
private boolean concurrentClickHandlerExecution = false;
/** An {@link Function} that is called when a slot in the inventory has been clicked */
private ClickHandler clickHandler;
/** A state that decides where the anvil GUI is able to be closed by the user */
private boolean preventClose = false;
/** A set of integers containing the slot numbers that should be modifiable by the user. */
private Set<Integer> interactableSlots = Collections.emptySet();
/** The {@link Plugin} that this anvil GUI is associated with */
private Plugin plugin;
/** The text that will be displayed to the user */
private Object titleComponent = WRAPPER.literalChatComponent("Repair & Name");
/** The starting text on the item */
private String itemText;
/** An {@link ItemStack} to be put in the left input slot */
private ItemStack itemLeft;
/** An {@link ItemStack} to be put in the right input slot */
private ItemStack itemRight;
/** An {@link ItemStack} to be placed in the output slot */
private ItemStack itemOutput;
/**
* Set a custom main server thread executor. Useful for plugins targeting Folia.
*
* @param executor The executor to run tasks on
* @return The {@link Builder} instance
* @throws IllegalArgumentException when the executor is null
*/
public Builder mainThreadExecutor(@NonNull Executor executor) {
this.mainThreadExecutor = executor;
return this;
}
/**
* Prevents the closing of the anvil GUI by the user
*
* @return The {@link Builder} instance
*/
public Builder preventClose() {
preventClose = true;
return this;
}
/**
* Permit the user to modify (take items in and out) the slot numbers provided.
*
* @param slots A varags param for the slot numbers. You can avoid relying on magic constants by using
* the {@link AnvilGUI.Slot} class.
* @return The {@link Builder} instance
*/
public Builder interactableSlots(int... slots) {
final Set<Integer> newValue = new HashSet<>();
for (int slot : slots) {
newValue.add(slot);
}
interactableSlots = newValue;
return this;
}
/**
* Listens for when the inventory is closed
*
* @param closeListener An {@link Consumer} that is called when the anvil GUI is closed
* @return The {@link Builder} instance
* @throws IllegalArgumentException when the closeListener is null
*/
public Builder onClose(@NonNull Consumer<StateSnapshot> closeListener) {
this.closeListener = closeListener;
return this;
}
/**
* Do an action when a slot is clicked in the inventory
* <p>
* The ClickHandler is only called when the previous execution of the ClickHandler has finished.
* To alter this behaviour use {@link #allowConcurrentClickHandlerExecution()}
*
* @param clickHandler A {@link ClickHandler} that is called when the user clicks a slot. The
* {@link Integer} is the slot number corresponding to {@link Slot}, the
* {@link StateSnapshot} contains information about the current state of the anvil,
* and the response is a {@link CompletableFuture} that will eventually return a
* list of {@link ResponseAction} to execute in the order that they are supplied.
* @return The {@link Builder} instance
* @throws IllegalArgumentException when the function supplied is null
*/
public Builder onClickAsync(@NonNull ClickHandler clickHandler) {
this.clickHandler = clickHandler;
return this;
}
/**
* By default, the {@link #onClickAsync(ClickHandler) async click handler} will not run concurrently
* and instead wait for the previous {@link CompletableFuture} to finish before executing it again.
* <p>
* If this trait is desired, it can be enabled by calling this method but may lead to inconsistent
* behaviour if not handled properly.
*
* @return The {@link Builder} instance
*/
public Builder allowConcurrentClickHandlerExecution() {
this.concurrentClickHandlerExecution = true;
return this;
}
/**
* Do an action when a slot is clicked in the inventory
*
* @param clickHandler A {@link BiFunction} that is called when the user clicks a slot. The
* {@link Integer} is the slot number corresponding to {@link Slot}, the
* {@link StateSnapshot} contains information about the current state of the anvil,
* and the response is a list of {@link ResponseAction} to execute in the order
* that they are supplied.
* @return The {@link Builder} instance
* @throws IllegalArgumentException when the function supplied is null
*/
public Builder onClick(@NonNull BiFunction<Integer, StateSnapshot, List<ResponseAction>> clickHandler) {
this.clickHandler =
(slot, stateSnapshot) -> CompletableFuture.completedFuture(clickHandler.apply(slot, stateSnapshot));
return this;
}
/**
* Sets the plugin for the {@link AnvilGUI}
*
* @param plugin The {@link Plugin} this anvil GUI is associated with
* @return The {@link Builder} instance
* @throws IllegalArgumentException if the plugin is null
*/
public Builder plugin(@NonNull Plugin plugin) {
this.plugin = plugin;
return this;
}
/**
* Sets the initial item-text that is displayed to the user.
* <br><br>
* If the usage of Adventure Components is desired, you must create an item, set the displayname of it
* and put it into the AnvilGUI via {@link #itemLeft(ItemStack)} manually.
*
* @param text The initial name of the item in the anvil
* @return The {@link Builder} instance
* @throws IllegalArgumentException if the text is null
*/
public Builder text(@NonNull String text) {
this.itemText = text;
return this;
}
/**
* Sets the AnvilGUI title that is to be displayed to the user.
* <br>
* The provided title will be treated as literal text.
*
* @param title The title that is to be displayed to the user
* @return The {@link Builder} instance
* @throws IllegalArgumentException if the title is null
*/
public Builder title(@NonNull String title) {
this.titleComponent = WRAPPER.literalChatComponent(title);
return this;
}
/**
* Sets the AnvilGUI title that is to be displayed to the user.
* <br>
* The provided json will be parsed into rich chat components.
*
* @param json The title that is to be displayed to the user
* @return The {@link Builder} instance
* @throws IllegalArgumentException if the title is null
* @see net.md_5.bungee.chat.ComponentSerializer#toString(BaseComponent)
*/
public Builder jsonTitle(@NonNull String json) {
this.titleComponent = WRAPPER.jsonChatComponent(json);
return this;
}
/**
* Sets the {@link ItemStack} to be put in the first slot
*
* @param item The {@link ItemStack} to be put in the first slot
* @return The {@link Builder} instance
* @throws IllegalArgumentException if the {@link ItemStack} is null
*/
public Builder itemLeft(@NonNull ItemStack item) {
this.itemLeft = item;
return this;
}
/**
* Sets the {@link ItemStack} to be put in the second slot
*
* @param item The {@link ItemStack} to be put in the second slot
* @return The {@link Builder} instance
*/
public Builder itemRight(ItemStack item) {
this.itemRight = item;
return this;
}
/**
* Sets the {@link ItemStack} to be put in the output slot
*
* @param item The {@link ItemStack} to be put in the output slot
* @return The {@link Builder} instance
*/
public Builder itemOutput(ItemStack item) {
this.itemOutput = item;
return this;
}
/**
* Creates the anvil GUI and opens it for the player
*
* @param player The {@link Player} the anvil GUI should open for
* @return The {@link AnvilGUI} instance from this builder
* @throws IllegalArgumentException when the onClick function, plugin, or player is null
*/
public AnvilGUI open(@NonNull Player player) {
if (plugin == null) {
throw new IllegalStateException("An AnvilGUI plugin has not been set!");
}
if (clickHandler == null) {
throw new IllegalStateException("An AnvilGUI clickHandler has not been set!");
}
if (itemText != null) {
if (itemLeft == null) {
itemLeft = new ItemStack(Material.PAPER);
}
ItemMeta paperMeta = itemLeft.getItemMeta();
paperMeta.setDisplayName(itemText);
itemLeft.setItemMeta(paperMeta);
}
// If no executor is specified, execute all tasks with the BukkitScheduler
if (mainThreadExecutor == null) {
mainThreadExecutor = task -> Bukkit.getScheduler().runTask(plugin, task);
}
final AnvilGUI anvilGUI = new AnvilGUI(
plugin,
player,
mainThreadExecutor,
titleComponent,
new ItemStack[] {itemLeft, itemRight, itemOutput},
preventClose,
interactableSlots,
closeListener,
concurrentClickHandlerExecution,
clickHandler);
anvilGUI.openInventory();
return anvilGUI;
}
}
/**
* A handler that is called when the user clicks a slot. The
* {@link Integer} is the slot number corresponding to {@link Slot}, the
* {@link StateSnapshot} contains information about the current state of the anvil,
* and the response is a {@link CompletableFuture} that will eventually return a
* list of {@link ResponseAction} to execute in the order that they are supplied.
*/
@FunctionalInterface
public interface ClickHandler extends BiFunction<Integer, StateSnapshot, CompletableFuture<List<ResponseAction>>> {}
/** An action to run in response to a player clicking the output slot in the GUI. This interface is public
* and permits you, the developer, to add additional response features easily to your custom AnvilGUIs. */
@FunctionalInterface
public interface ResponseAction extends BiConsumer<AnvilGUI, Player> {
/**
* Replace the input text box value with the provided text value.
*
* Before using this method, it must be verified by the caller that items are either in
* {@link Slot#INPUT_LEFT} or {@link Slot#OUTPUT} present.
*
* @param text The text to write in the input box
* @return The {@link ResponseAction} to achieve the text replacement
* @throws IllegalArgumentException when the text is null
* @throws IllegalStateException when the slots {@link Slot#INPUT_LEFT} and {@link Slot#OUTPUT} are <code>null</code>
*/
static ResponseAction replaceInputText(@NonNull String text) {
return (anvilgui, player) -> {
ItemStack item = anvilgui.getInventory().getItem(Slot.OUTPUT);
if (item == null) {
// Fallback on left input slot if player hasn't typed anything yet
item = anvilgui.getInventory().getItem(Slot.INPUT_LEFT);
}
if (item == null) {
throw new IllegalStateException(
"replaceInputText can only be used if slots OUTPUT or INPUT_LEFT are not empty");
}
final ItemStack cloned = item.clone();
final ItemMeta meta = cloned.getItemMeta();
meta.setDisplayName(text);
cloned.setItemMeta(meta);
anvilgui.getInventory().setItem(Slot.INPUT_LEFT, cloned);
};
}
/**
* Updates the title of the AnvilGUI to the new one.
*
* @param literalTitle The title to use as literal text
* @param preserveRenameText Whether to preserve the entered rename text
* @throws IllegalArgumentException when literalTitle is null
* @see Builder#title(String)
*/
static ResponseAction updateTitle(@NonNull String literalTitle, boolean preserveRenameText) {
return (anvilGUI, player) -> anvilGUI.setTitle(literalTitle, preserveRenameText);
}
/**
* Updates the title of the AnvilGUI to the new one.
*
* @param json The json used to parse into a rich chat component
* @param preserveRenameText Whether to preserve the entered rename text
* @throws IllegalArgumentException when json is null
* @see Builder#jsonTitle(String)
*/
static ResponseAction updateJsonTitle(@NonNull String json, boolean preserveRenameText) {
return (anvilGUI, player) -> anvilGUI.setJsonTitle(json, preserveRenameText);
}
/**
* Open another inventory
* @param otherInventory The inventory to open
* @return The {@link ResponseAction} to achieve the inventory open
* @throws IllegalArgumentException when the otherInventory is null
*/
static ResponseAction openInventory(@NonNull Inventory otherInventory) {
return (anvilgui, player) -> player.openInventory(otherInventory);
}
/**
* Close the AnvilGUI
* @return The {@link ResponseAction} to achieve closing the AnvilGUI
*/
static ResponseAction close() {
return (anvilgui, player) -> anvilgui.closeInventory();
}
/**
* Run the provided runnable
* @param runnable The runnable to run
* @return The {@link ResponseAction} to achieve running the runnable
* @throws IllegalArgumentException when the runnable is null
*/
static ResponseAction run(@NonNull Runnable runnable) {
return (anvilgui, player) -> runnable.run();
}
}
/**
* Represents a response when the player clicks the output item in the anvil GUI
* @deprecated Since 1.6.2, use {@link ResponseAction}
*/
@Deprecated
public static class Response {
/**
* Returns an {@link Response} object for when the anvil GUI is to close
* @return An {@link Response} object for when the anvil GUI is to display text to the user
* @deprecated Since 1.6.2, use {@link ResponseAction#close()}
*/
public static List<ResponseAction> close() {
return Arrays.asList(ResponseAction.close());
}
/**
* Returns an {@link Response} object for when the anvil GUI is to display text to the user
*
* @param text The text that is to be displayed to the user
* @return A list containing the {@link ResponseAction} for legacy compat
* @deprecated Since 1.6.2, use {@link ResponseAction#replaceInputText(String)}
*/
public static List<ResponseAction> text(String text) {
return Arrays.asList(ResponseAction.replaceInputText(text));
}
/**
* Returns an {@link Response} object for when the GUI should open the provided inventory
*
* @param inventory The inventory to open
* @return A list containing the {@link ResponseAction} for legacy compat
* @deprecated Since 1.6.2, use {@link ResponseAction#openInventory(Inventory)}
*/
public static List<ResponseAction> openInventory(Inventory inventory) {
return Arrays.asList(ResponseAction.openInventory(inventory));
}
}
/**
* Class wrapping the magic constants of slot numbers in an anvil GUI
*/
public static class Slot {
private static final int[] values = new int[] {Slot.INPUT_LEFT, Slot.INPUT_RIGHT, Slot.OUTPUT};
/**
* The slot on the far left, where the first input is inserted. An {@link ItemStack} is always inserted
* here to be renamed
*/
public static final int INPUT_LEFT = 0;
/**
* Not used, but in a real anvil you are able to put the second item you want to combine here
*/
public static final int INPUT_RIGHT = 1;
/**
* The output slot, where an item is put when two items are combined from {@link #INPUT_LEFT} and
* {@link #INPUT_RIGHT} or {@link #INPUT_LEFT} is renamed
*/
public static final int OUTPUT = 2;
/**
* Get all anvil slot values
*
* @return The array containing all possible anvil slots
*/
public static int[] values() {
return values;
}
}
/** Represents a snapshot of the state of an AnvilGUI */
public static final class StateSnapshot {
/**
* Create an {@link StateSnapshot} from the current state of an {@link AnvilGUI}
* @param anvilGUI The instance to take the snapshot of
* @return The snapshot
*/
private static StateSnapshot fromAnvilGUI(AnvilGUI anvilGUI) {
final Inventory inventory = anvilGUI.getInventory();
return new StateSnapshot(
itemNotNull(inventory.getItem(Slot.INPUT_LEFT)).clone(),
itemNotNull(inventory.getItem(Slot.INPUT_RIGHT)).clone(),
itemNotNull(inventory.getItem(Slot.OUTPUT)).clone(),
anvilGUI.player);
}
/**
* The {@link ItemStack} in the anvilGui slots
*/
private final ItemStack leftItem, rightItem, outputItem;
/**
* The {@link Player} that clicked the output slot
*/
private final Player player;
/**
* The event parameter constructor
* @param leftItem The left item in the combine slot of the anvilGUI
* @param rightItem The right item in the combine slot of the anvilGUI
* @param outputItem The item that would have been outputted, when the items would have been combined
* @param player The player that clicked the output slot
*/
public StateSnapshot(ItemStack leftItem, ItemStack rightItem, ItemStack outputItem, Player player) {
this.leftItem = leftItem;
this.rightItem = rightItem;
this.outputItem = outputItem;
this.player = player;
}
/**
* It returns the item in the left combine slot of the gui
*
* @return The leftItem
*/
public ItemStack getLeftItem() {
return leftItem;
}
/**
* It returns the item in the right combine slot of the gui
*
* @return The rightItem
*/
public ItemStack getRightItem() {
return rightItem;
}
/**
* It returns the output item that would have been the result
* by combining the left and right one
*
* @return The outputItem
*/
public ItemStack getOutputItem() {
return outputItem;
}
/**
* It returns the player that clicked onto the output slot
*
* @return The player
*/
public Player getPlayer() {
return player;
}
/**
* It returns the text the player typed into the rename field
*
* @return The text of the rename field
*/
public String getText() {
return outputItem.hasItemMeta() ? outputItem.getItemMeta().getDisplayName() : "";
}
}
}
@@ -1,151 +0,0 @@
package net.wesjd.anvilgui.version;
import net.minecraft.core.BlockPos;
import net.minecraft.core.component.DataComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ClientboundContainerClosePacket;
import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket;
import net.minecraft.network.protocol.game.ClientboundSetExperiencePacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.inventory.AnvilMenu;
import net.minecraft.world.inventory.ContainerLevelAccess;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.inventory.Slot;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.craftbukkit.util.CraftChatMessage;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.inventory.Inventory;
public final class VersionWrapper {
public static final VersionWrapper INSTANCE = new VersionWrapper();
/**
* Interface implemented by the custom NMS AnvilContainer used to interact with it directly
*/
public interface AnvilContainerWrapper {
/**
* Retrieves the raw text that has been entered into the Anvil at the moment
* <br><br>
* This field is marked as public in the Minecraft AnvilContainer only from Minecraft 1.11 and upwards
*
* @return The raw text in the rename field
*/
default String getRenameText() {
return null;
}
/**
* Sets the provided text as the literal hovername of the item in the left input slot
*
* @param text The text to set
*/
default void setRenameText(String text) {
}
/**
* Gets the {@link Inventory} wrapper of the NMS container
*
* @return The inventory of the NMS container
*/
Inventory getBukkitInventory();
}
private static class AnvilContainer extends AnvilMenu implements AnvilContainerWrapper {
public AnvilContainer(Player player, int containerId, Component guiTitle) {
super(
containerId,
((CraftPlayer) player).getHandle().getInventory(),
ContainerLevelAccess.create(((CraftWorld) player.getWorld()).getHandle(), new BlockPos(0, 0, 0))
);
this.checkReachable = false;
setTitle(guiTitle);
}
public int getContainerId() {
return this.containerId;
}
public String getRenameText() {
return this.itemName;
}
public void setRenameText(String text) {
// If an item is present in the left input slot change its hover name to the literal text.
Slot inputLeft = getSlot(0);
if (inputLeft.hasItem()) {
inputLeft.getItem()
.set(DataComponents.CUSTOM_NAME, Component.literal(text));
}
}
public Inventory getBukkitInventory() {
return this.getBukkitView().getTopInventory();
}
}
private int getRealNextContainerId(Player player) {
return toNMS(player).nextContainerCounter();
}
/**
* Turns a {@link Player} into an NMS one
*
* @param player The player to be converted
* @return the NMS EntityPlayer
*/
private ServerPlayer toNMS(Player player) {
return ((CraftPlayer) player).getHandle();
}
public int getNextContainerId(Player player, AnvilContainerWrapper container) {
return ((AnvilContainer) container).getContainerId();
}
public void handleInventoryCloseEvent(Player player) {
CraftEventFactory.handleInventoryCloseEvent(toNMS(player), InventoryCloseEvent.Reason.UNKNOWN);
toNMS(player).doCloseContainer();
}
public void sendPacketOpenWindow(Player player, int containerId, Object inventoryTitle) {
toNMS(player).connection.send(new ClientboundOpenScreenPacket(containerId, MenuType.ANVIL, (Component) inventoryTitle));
}
public void sendPacketCloseWindow(Player player, int containerId) {
toNMS(player).connection.send(new ClientboundContainerClosePacket(containerId));
}
public void sendPacketExperienceChange(Player player, int experienceLevel) {
toNMS(player).connection.send(new ClientboundSetExperiencePacket(0f, 0, experienceLevel));
}
public void setActiveContainerDefault(Player player) {
toNMS(player).containerMenu = toNMS(player).inventoryMenu;
}
public void setActiveContainer(Player player, AnvilContainerWrapper container) {
toNMS(player).containerMenu = (AnvilMenu) container;
}
public void setActiveContainerId(AnvilContainerWrapper container, int containerId) {
}
public void addActiveContainerSlotListener(AnvilContainerWrapper container, Player player) {
toNMS(player).initMenu((AnvilMenu) container);
}
public AnvilContainerWrapper newContainerAnvil(Player player, Object title) {
return new AnvilContainer(player, getRealNextContainerId(player), (Component) title);
}
public Object literalChatComponent(String content) {
return Component.literal(content);
}
public Object jsonChatComponent(String json) {
return CraftChatMessage.fromJSON(json);
}
}
@@ -1,43 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.velocitycore.advancements;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URI;
public class Items {
/**
* Loaded from https://github.com/retrooper/packetevents/blob/2.0/mappings/registries/item.json
*/
public static final JsonObject values;
static {
try {
values = new Gson().fromJson(new BufferedReader(new InputStreamReader(URI.create("https://raw.githubusercontent.com/retrooper/packetevents/refs/heads/2.0/mappings/registries/item.json").toURL().openConnection().getInputStream())), JsonObject.class);
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
}
@@ -20,7 +20,6 @@
package de.steamwar.command;
import com.velocitypowered.api.command.SimpleCommand;
import com.velocitypowered.api.command.SimpleCommand.Invocation;
import de.steamwar.messages.Chatter;
import de.steamwar.messages.Message;
import de.steamwar.sql.UserPerm;
@@ -92,15 +91,11 @@ public class SWCommand extends AbstractSWCommand<Chatter> {
@Override
public boolean hasPermission(Invocation invocation) {
return SWCommand.this.hasPermission(invocation);
return permission == null || Chatter.of(invocation.source()).user().perms().contains(permission);
}
};
}
protected boolean hasPermission(Invocation invocation) {
return permission == null || Chatter.of(invocation.source()).user().perms().contains(permission);
}
@Override
public void unregister() {
if (command == null) return;
@@ -201,8 +201,8 @@ public class ServerStarter {
private void tempWorld(String template) {
worldDir = TEMP_WORLD_PATH;
worldSetup = () -> copyWorld(node, template, new File(worldDir, worldName).getPath());
worldCleanup = () -> SubserverSystem.deleteFolder(node, new File(worldDir, worldName).getPath());
worldSetup = () -> copyWorld(node, template, worldDir + worldName);
worldCleanup = () -> SubserverSystem.deleteFolder(node, worldDir + worldName);
}
private void buildWithTemp(Player owner) {
@@ -396,4 +396,4 @@ public class ServerStarter {
}
}
}
}
@@ -1,340 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.velocitycore.advancements;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
import de.steamwar.messages.Chatter;
import de.steamwar.sql.SteamwarUser;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import net.kyori.adventure.text.Component;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
@RequiredArgsConstructor
public class Advancement {
protected static final Map<SteamwarUser, Map<Advancement.Value.Key, Advancement.Value>> values = new HashMap<>();
{
Advancements.all.add(this);
}
protected final Map<SteamwarUser, Advancement.Data> data = new HashMap<>();
protected final Map<SteamwarUser, Advancement.Value> value = new HashMap<>();
public Advancement.Data get(SteamwarUser user) {
return get(user, Data::new);
}
public Advancement.Data get(SteamwarUser user, BiFunction<Advancement, SteamwarUser, Data> function) {
if (data.containsKey(user)) return data.get(user);
return function.apply(this, user);
}
private final String identifier;
private final Optional<Advancement> parent;
private final Display display;
private final HidePolicy hidePolicy;
private final int total;
private final Function<SteamwarUser, Integer> progressCalculator;
@Override
public String toString() {
StringBuilder st = new StringBuilder();
st.append("Advancement(");
parent.ifPresent(advancement -> st.append(advancement.identifier).append("<-"));
st.append(identifier);
st.append(", total=").append(total);
st.append(")");
return st.toString();
}
@RequiredArgsConstructor
@AllArgsConstructor
public static class Display {
private final Component title;
private final Component description;
private final String item;
private final FrameType frameType;
private Optional<String> background = Optional.empty();
private final float xCoord;
private final float yCoord;
public enum FrameType {
TASK,
CHALLENGE,
GOAL
}
}
public enum HidePolicy {
NEVER {
@Override
public boolean hidden(Data data) {
return false;
}
},
NO_PROGRESS {
@Override
public boolean hidden(Data data) {
return data.progress == 0;
}
},
PREVIOUS_UNFINISHED {
@Override
public boolean hidden(Data data) {
if (data.advancement.parent.isPresent()) {
Advancement parent = data.advancement.parent.get();
Advancement.Data parentData = parent.get(data.user);
return parentData.progress != parentData.advancement.total;
} else {
return false;
}
}
},
WITH_PREVIOUS {
@Override
public boolean hidden(Data data) {
if (data.advancement.parent.isPresent()) {
Advancement parent = data.advancement.parent.get();
Advancement.Data parentData = parent.get(data.user);
return parentData.hidden;
} else {
return false;
}
}
},
;
public abstract boolean hidden(Data data);
}
public static class Value<T extends Number> {
@AllArgsConstructor
public static class Key<T extends Number> {
public static final List<Key> keys = new ArrayList<>();
{
keys.add(this);
}
private final Function<SteamwarUser, T> valueFunction;
private Advancement.Value get(SteamwarUser user) {
Key self = this;
return values.computeIfAbsent(user, __ -> new HashMap<>()).computeIfAbsent(self, __ -> {
Value data = new Advancement.Value();
data.update(user, self);
return data;
});
}
public Function<SteamwarUser, Integer> max(int neededValue) {
return user -> {
double value = get(user).value.doubleValue();
if (value > neededValue) return Math.min(neededValue, 100);
return (int) (value / Math.max(neededValue / 100.0, 1));
};
}
public Function<SteamwarUser, Integer> reached(int neededValue) {
return user -> {
double value = get(user).value.doubleValue();
return value >= neededValue ? 1 : 0;
};
}
}
@Getter
private T value;
public void update(SteamwarUser user, Key<T> key) {
this.value = key.valueFunction.apply(user);
}
}
@ToString
public static class Data {
private final Advancement advancement;
private final SteamwarUser user;
private int progress;
private boolean showToast = true;
private boolean hidden = false;
public Data(Advancement advancement, SteamwarUser user) {
this.advancement = advancement;
advancement.data.put(user, this);
this.user = user;
this.progress = advancement.progressCalculator.apply(user);
checkHidden();
checkFinished();
new Packet(this, showToast).send();
}
public Data(Advancement advancement, SteamwarUser user, int progress) {
this.advancement = advancement;
advancement.data.put(user, this);
this.user = user;
this.progress = progress;
checkHidden();
checkFinished();
new Packet(this, showToast).send();
}
public void update() {
this.progress = advancement.progressCalculator.apply(user);
checkHidden();
new Packet(this, showToast).send();
// Update Advancements that have this as parent
Advancements.getAll()
.stream()
.filter(advancement -> advancement.parent.filter(value -> value == this.advancement).isPresent())
.map(advancement -> advancement.get(user))
.forEach(Advancement.Data::update);
checkFinished();
}
private void checkHidden() {
hidden = advancement.hidePolicy.hidden(this);
}
private void checkFinished() {
if (progress == advancement.total) {
showToast = false;
}
}
private void encodeAdvancement(ByteBuf byteBuf, ProtocolVersion protocolVersion, boolean showToast) {
ProtocolUtils.writeString(byteBuf, advancement.identifier);
if (advancement.parent.isPresent()) {
byteBuf.writeBoolean(true);
ProtocolUtils.writeString(byteBuf, advancement.parent.get().identifier);
} else {
byteBuf.writeBoolean(false);
}
{ // Display
byteBuf.writeBoolean(true);
new ComponentHolder(protocolVersion, advancement.display.title).write(byteBuf);
new ComponentHolder(protocolVersion, advancement.display.description).write(byteBuf);
{ // Slot
ProtocolUtils.writeVarInt(byteBuf, 1);
int itemId = Items.values
.get(protocolVersion.name().replace("MINECRAFT_", "V_"))
.getAsJsonObject()
.get(advancement.display.item)
.getAsInt();
ProtocolUtils.writeVarInt(byteBuf, itemId);
ProtocolUtils.writeVarInt(byteBuf, 0);
ProtocolUtils.writeVarInt(byteBuf, 0);
}
ProtocolUtils.writeVarInt(byteBuf, advancement.display.frameType.ordinal());
if (advancement.display.background.isPresent()) {
byteBuf.writeInt(0x01 | (showToast ? 0x02 : 0x00) | (hidden ? 0x04 : 0x00));
ProtocolUtils.writeString(byteBuf, advancement.display.background.get());
} else {
byteBuf.writeInt((showToast ? 0x02 : 0x00) | (hidden ? 0x04 : 0x00));
}
byteBuf.writeFloat(advancement.display.xCoord);
byteBuf.writeFloat(advancement.display.yCoord);
}
ProtocolUtils.writeVarInt(byteBuf, advancement.total);
for (int i = 0; i < advancement.total; i++) {
ProtocolUtils.writeVarInt(byteBuf, 1);
ProtocolUtils.writeString(byteBuf, advancement.identifier + "_" + i);
}
byteBuf.writeBoolean(false); // No Telemetry
}
private void encodeProgress(ByteBuf byteBuf) {
ProtocolUtils.writeString(byteBuf, this.advancement.identifier);
ProtocolUtils.writeVarInt(byteBuf, advancement.total);
for (int i = 0; i < advancement.total; i++) {
ProtocolUtils.writeString(byteBuf, advancement.identifier + "_" + i);
if (i == advancement.total - 1 && advancement.total == progress) {
byteBuf.writeBoolean(true);
byteBuf.writeLong(new Date().getTime());
} else if (i < progress) {
byteBuf.writeBoolean(true);
byteBuf.writeLong(0);
} else {
byteBuf.writeBoolean(false);
}
}
}
}
protected record Packet(Data data, boolean showToast) implements MinecraftPacket {
public void send() {
Player player = Chatter.of(data.user).getPlayer();
((ConnectedPlayer) player).getConnection().write(this);
}
@Override
public void decode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
throw new UnsupportedOperationException();
}
@Override
public void encode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
byteBuf.writeBoolean(false); // Clear
if (!data.hidden) {
ProtocolUtils.writeVarInt(byteBuf, 1);
data.encodeAdvancement(byteBuf, protocolVersion, showToast);
ProtocolUtils.writeVarInt(byteBuf, 0); // No Advancements to remove
ProtocolUtils.writeVarInt(byteBuf, 1);
data.encodeProgress(byteBuf);
} else {
ProtocolUtils.writeVarInt(byteBuf, 0); // No Advancements to update
ProtocolUtils.writeVarInt(byteBuf, 1);
ProtocolUtils.writeString(byteBuf, data.advancement.identifier);
ProtocolUtils.writeVarInt(byteBuf, 0); // No Advancements Progress to update
}
byteBuf.writeBoolean(true); // Show Advancements
}
@Override
public boolean handle(MinecraftSessionHandler minecraftSessionHandler) {
return false;
}
}
}
@@ -1,315 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.velocitycore.advancements;
import de.steamwar.messages.Chatter;
import de.steamwar.persistent.Storage;
import de.steamwar.sql.CheckedSchematic;
import de.steamwar.sql.EventFight;
import de.steamwar.sql.FightPlayer;
import lombok.Getter;
import lombok.experimental.UtilityClass;
import net.kyori.adventure.text.Component;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@UtilityClass
public class Advancements {
@Getter
static final List<Advancement> all = new ArrayList<>();
@Getter
private static final List<Advancement> playtime = new ArrayList<>();
public static final Advancement.Value.Key<Double> PLAY_TIME_KEY = new Advancement.Value.Key<>(user -> {
double playtime = user.getOnlinetime();
playtime += Instant.now().getEpochSecond() - Storage.sessions.get(Chatter.of(user).getPlayer()).toInstant().getEpochSecond();
playtime /= 60d * 60d;
return playtime;
});
public static final Advancement.Value.Key<Long> FIGHT_COUNT = new Advancement.Value.Key<>(user -> {
return FightPlayer.countFights(user.getId());
});
public static final Advancement.Value.Key<Integer> FIGHT_COUNT_WAR_GEAR = new Advancement.Value.Key<>(user -> {
return FightPlayer.countFights(user.getId(), "WarGear");
});
public static final Advancement.Value.Key<Integer> FIGHT_COUNT_MINI_WAR_GEAR = new Advancement.Value.Key<>(user -> {
return FightPlayer.countFights(user.getId(), "MiniWarGear");
});
public static final Advancement.Value.Key<Integer> FIGHT_COUNT_WAR_SHIP = new Advancement.Value.Key<>(user -> {
return FightPlayer.countFights(user.getId(), "WarShip");
});
public static final Advancement.Value.Key<Long> EVENT_FIGHT_COUNT = new Advancement.Value.Key<>(user -> {
return EventFight.countEventFights(user);
});
public static final Advancement.Value.Key<Integer> EVENT_FIGHT_FIRST_PLACE_COUNT = new Advancement.Value.Key<>(user -> {
return EventFight.countPlacement(user, 1);
});
public static final Advancement.Value.Key<Integer> EVENT_FIGHT_SECOND_PLACE_COUNT = new Advancement.Value.Key<>(user -> {
return EventFight.countPlacement(user, 2);
});
public static final Advancement.Value.Key<Integer> EVENT_FIGHT_THIRDPLACE_COUNT = new Advancement.Value.Key<>(user -> {
return EventFight.countPlacement(user, 3);
});
public static final Advancement.Value.Key<Long> CHECKED_SCHEMATIC_COUNT = new Advancement.Value.Key<>(user -> {
return CheckedSchematic.countChecked(user);
});
public static final Advancement.Value.Key<Long> ACCEPTED_SCHEMATIC_COUNT = new Advancement.Value.Key<>(user -> {
return CheckedSchematic.countAccepted(user);
});
public static final Advancement.Value.Key<Long> ACCEPTED_SCHEMATIC_COUNT_WAR_GEAR = new Advancement.Value.Key<>(user -> {
return CheckedSchematic.countAccepted(user, "WarGear");
});
public static final Advancement.Value.Key<Long> ACCEPTED_SCHEMATIC_COUNT_MINI_WAR_GEAR = new Advancement.Value.Key<>(user -> {
return CheckedSchematic.countAccepted(user, "MiniWarGear");
});
public static final Advancement.Value.Key<Long> ACCEPTED_SCHEMATIC_COUNT_WAR_SHIP = new Advancement.Value.Key<>(user -> {
return CheckedSchematic.countAccepted(user, "WarShip");
});
public static final Advancement ROOT = new Advancement(
"steamwar:advancements/root",
Optional.empty(),
new Advancement.Display(
Component.text("SteamWar"),
Component.text("Join SteamWar for the first time!"),
"cactus_flower",
Advancement.Display.FrameType.CHALLENGE,
Optional.of("minecraft:gui/advancements/backgrounds/adventure"),
0f,
3f
),
Advancement.HidePolicy.NEVER,
1,
user -> 1
);
static {
Advancement previous = ROOT;
int[] playTimes = new int[]{1, 10, 100, 500, 1000, 2500, 5000, 7500, 10000, 15000, 20000};
for (int i = 0; i < playTimes.length; i++) {
int neededPlayTime = playTimes[i];
previous = new Advancement(
"steamwar:advancements/playtime_" + neededPlayTime + "_hour",
Optional.of(previous),
new Advancement.Display(
Component.text("Play " + neededPlayTime + " Hour" + (neededPlayTime > 1 ? "s" : "")),
Component.text("Play " + neededPlayTime + " hour" + (neededPlayTime > 1 ? "s" : "") + " on SteamWar"),
"clock",
Advancement.Display.FrameType.TASK,
i + 1f,
3f
),
Advancement.HidePolicy.PREVIOUS_UNFINISHED,
Math.min(neededPlayTime, 100),
PLAY_TIME_KEY.max(neededPlayTime)
);
playtime.add(previous);
}
}
static {
Advancement previous = ROOT;
int[] fightCounts = new int[]{1, 10, 50, 100, 200, 500, 1000, 2500, 5000, 7500, 10000, 15000, 20000};
for (int i = 0; i < fightCounts.length; i++) {
int fightCount = fightCounts[i];
previous = new Advancement(
"steamwar:advancements/fights_" + fightCount,
Optional.of(previous),
new Advancement.Display(
Component.text(fightCount + " Fight" + (fightCount > 1 ? "s" : "")),
Component.text(fightCount + " Fight" + (fightCount > 1 ? "s" : "")),
"iron_sword",
Advancement.Display.FrameType.TASK,
i + 1f,
4f
),
Advancement.HidePolicy.PREVIOUS_UNFINISHED,
Math.min(fightCount, 100),
FIGHT_COUNT.max(fightCount)
);
if (i == 0) {
fightsPerType(previous, 5f, "WarGear", FIGHT_COUNT_WAR_GEAR, "stone_bricks");
fightsPerType(previous, 6f, "MiniWarGear", FIGHT_COUNT_MINI_WAR_GEAR, "stone_brick_slab");
fightsPerType(previous, 7f, "WarShip", FIGHT_COUNT_WAR_SHIP, "dark_oak_boat");
}
}
}
private static void fightsPerType(Advancement previous, float yCoord, String type, Advancement.Value.Key<Integer> typeKey, String item) {
int[] fightCounts = new int[]{1, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000};
for (int i = 0; i < fightCounts.length; i++) {
int fightCount = fightCounts[i];
previous = new Advancement(
"steamwar:advancements/fights_" + type + "_" + fightCount,
Optional.of(previous),
new Advancement.Display(
Component.text(type + " " + fightCount + " Fight" + (fightCount > 1 ? "s" : "")),
Component.text(type + " " + fightCount + " Fight" + (fightCount > 1 ? "s" : "")),
item,
Advancement.Display.FrameType.TASK,
i + 2f,
yCoord
),
i == 0 ? Advancement.HidePolicy.WITH_PREVIOUS : Advancement.HidePolicy.PREVIOUS_UNFINISHED,
Math.min(fightCount, 100),
typeKey.max(fightCount)
);
}
}
static {
Advancement previous = ROOT;
int[] eventFightCounts = new int[]{1, 5, 10, 15, 25, 50, 100, 150, 200, 250};
for (int i = 0; i < eventFightCounts.length; i++) {
int eventFightCount = eventFightCounts[i];
previous = new Advancement(
"steamwar:advancements/event_fights_" + eventFightCount,
Optional.of(previous),
new Advancement.Display(
Component.text(eventFightCount + " Event-Fight" + (eventFightCount > 1 ? "s" : "")),
Component.text(eventFightCount + " Event-Fight" + (eventFightCount > 1 ? "s" : "")),
"golden_sword",
Advancement.Display.FrameType.TASK,
i + 1f,
8f
),
Advancement.HidePolicy.PREVIOUS_UNFINISHED,
Math.min(eventFightCount, 100),
EVENT_FIGHT_COUNT.max(eventFightCount)
);
if (i == 0) {
placementsCounts(previous, 9f, 1, "gold_block", EVENT_FIGHT_FIRST_PLACE_COUNT, Advancement.Display.FrameType.CHALLENGE);
placementsCounts(previous, 10f, 2, "iron_block", EVENT_FIGHT_SECOND_PLACE_COUNT, Advancement.Display.FrameType.GOAL);
placementsCounts(previous, 11f, 3, "copper_block", EVENT_FIGHT_THIRDPLACE_COUNT, Advancement.Display.FrameType.TASK);
}
}
}
private static void placementsCounts(Advancement previous, float yCoord, int placement, String item, Advancement.Value.Key<Integer> typeKey, Advancement.Display.FrameType frameType) {
for (int placementCount = 1; placementCount <= 10; placementCount++) {
int finalPlacementCount = placementCount;
previous = new Advancement(
"steamwar:advancements/event_placement_" + placement + "_" + placementCount,
Optional.of(previous),
new Advancement.Display(
Component.text(placementCount + "x " + placement + ". Place in Event"),
Component.text(""),
item,
frameType,
2f + (placementCount - 1f),
yCoord
),
placementCount == 1 ? Advancement.HidePolicy.WITH_PREVIOUS : Advancement.HidePolicy.PREVIOUS_UNFINISHED,
1,
typeKey.reached(placementCount)
);
}
}
static {
Advancement previous = ROOT;
int[] checkedCounts = new int[]{1, 10, 100, 250, 500, 750, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000};
for (int i = 0; i < checkedCounts.length; i++) {
int checkedCount = checkedCounts[i];
previous = new Advancement(
"steamwar:advancements/checked_" + checkedCount,
Optional.of(previous),
new Advancement.Display(
Component.text(checkedCount + " Check Session" + (checkedCount > 1 ? "s" : "")),
Component.text(checkedCount + " Check Session" + (checkedCount > 1 ? "s" : "")),
"paper",
Advancement.Display.FrameType.TASK,
i + 1f,
0f
),
i == 0 ? Advancement.HidePolicy.NO_PROGRESS : Advancement.HidePolicy.PREVIOUS_UNFINISHED,
Math.min(checkedCount, 100),
CHECKED_SCHEMATIC_COUNT.max(checkedCount)
);
}
}
static {
Advancement previous = ROOT;
int[] acceptedCounts = new int[]{1, 5, 10, 15, 25, 50, 100, 150, 200, 250, 500, 750, 1000};
for (int i = 0; i < acceptedCounts.length; i++) {
int acceptedCount = acceptedCounts[i];
previous = new Advancement(
"steamwar:advancements/accepted_" + acceptedCount,
Optional.of(previous),
new Advancement.Display(
Component.text(acceptedCount + " Accepted Schematic" + (acceptedCount > 1 ? "s" : "")),
Component.text(acceptedCount + " Accepted Schematic" + (acceptedCount > 1 ? "s" : "")),
"cauldron",
Advancement.Display.FrameType.TASK,
i + 1f,
2f
),
Advancement.HidePolicy.PREVIOUS_UNFINISHED,
Math.min(acceptedCount, 100),
ACCEPTED_SCHEMATIC_COUNT.max(acceptedCount)
);
if (i == 0) {
acceptedPerType(previous, 2f, "WarGear", ACCEPTED_SCHEMATIC_COUNT_WAR_GEAR, "end_stone_bricks");
acceptedPerType(previous, 3f, "MiniWarGear", ACCEPTED_SCHEMATIC_COUNT_MINI_WAR_GEAR, "end_stone_brick_slab");
acceptedPerType(previous, 4f, "WarShip", ACCEPTED_SCHEMATIC_COUNT_WAR_SHIP, "oak_boat");
}
}
}
private static void acceptedPerType(Advancement previous, float xCoord, String type, Advancement.Value.Key<Long> typeKey, String item) {
new Advancement(
"steamwar:advancements/accepted_" + type,
Optional.of(previous),
new Advancement.Display(
Component.text(type + " Accepted"),
Component.text(""),
item,
Advancement.Display.FrameType.GOAL,
xCoord,
1f
),
Advancement.HidePolicy.WITH_PREVIOUS,
1,
typeKey.reached(1)
);
}
}
@@ -1,99 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.velocitycore.advancements;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.DisconnectEvent;
import com.velocitypowered.api.event.connection.PostLoginEvent;
import com.velocitypowered.api.event.player.ServerPostConnectEvent;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.StateRegistry;
import de.steamwar.linkage.Linked;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.velocitycore.listeners.BasicListener;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import java.lang.reflect.Field;
import java.util.Optional;
@Linked
public class AdvancementsManager extends BasicListener {
private static SelectAdvancementTabPacket selectAdvancementTabPacket;
static {
selectAdvancementTabPacket = new SelectAdvancementTabPacket(Optional.of("steamwar:advancements/root"));
registerPacketId(ProtocolVersion.MINECRAFT_1_21_9, 0x53, 0x80);
registerPacketId(ProtocolVersion.MINECRAFT_1_21_7, 0x4E, 0x7B);
registerPacketId(ProtocolVersion.MINECRAFT_1_21_6, 0x4E, 0x7B);
registerPacketId(ProtocolVersion.MINECRAFT_1_21_5, 0x4E, 0x7B);
registerPacketId(ProtocolVersion.MINECRAFT_1_21_4, 0x4F, 0x7B);
}
private static void registerPacketId(ProtocolVersion version, int selectAdvancementTabPacket, int advancementPacket) {
try {
StateRegistry.PacketRegistry.ProtocolRegistry registry = StateRegistry.PLAY.getProtocolRegistry(ProtocolUtils.Direction.CLIENTBOUND, version);
Field field = StateRegistry.PacketRegistry.ProtocolRegistry.class.getDeclaredField("packetClassToId");
field.setAccessible(true);
Object2IntMap<Class<? extends MinecraftPacket>> map = (Object2IntMap) field.get(registry);
map.put(SelectAdvancementTabPacket.class, selectAdvancementTabPacket);
map.put(Advancement.Packet.class, advancementPacket);
} catch (Exception e) {
// Ignore
}
}
@Subscribe(priority = -1000)
public void onPostLogin(PostLoginEvent event) {
sendAdvancements(event.getPlayer());
}
@Subscribe(priority = -1000)
public void onServerPostConnect(ServerPostConnectEvent event) {
sendAdvancements(event.getPlayer());
}
private void sendAdvancements(Player player) {
// Only enable for 1.21.4 or higher
if (player.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_21_4)) {
return;
}
((ConnectedPlayer) player).getConnection().write(selectAdvancementTabPacket);
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
for (Advancement advancement : Advancements.getAll()) {
advancement.get(user).update();
}
}
@Subscribe
public void onDisconnect(DisconnectEvent event) {
SteamwarUser user = SteamwarUser.get(event.getPlayer().getUniqueId());
for (Advancement advancement : Advancements.getAll()) {
advancement.data.remove(user);
}
Advancement.values.remove(user);
}
}
@@ -1,55 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.velocitycore.advancements;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
import java.util.Optional;
@AllArgsConstructor
public class SelectAdvancementTabPacket implements MinecraftPacket {
private Optional<String> identifier;
@Override
public void decode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
throw new UnsupportedOperationException("Packet is not implemented");
}
@Override
public void encode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
if (this.identifier.isPresent()) {
byteBuf.writeBoolean(true);
ProtocolUtils.writeString(byteBuf, this.identifier.get());
} else {
byteBuf.writeBoolean(false);
}
}
@Override
public boolean handle(MinecraftSessionHandler minecraftSessionHandler) {
return false;
}
}
@@ -19,7 +19,6 @@
package de.steamwar.velocitycore.commands;
import com.velocitypowered.api.command.SimpleCommand;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ServerConnection;
import de.steamwar.command.SWCommand;
@@ -63,89 +62,61 @@ public class CheckCommand extends SWCommand {
public static Message getWaitTime(SchematicNode schematic) {
long waitedMillis = Timestamp.from(Instant.now()).getTime() - schematic.getLastUpdate().getTime();
String color;
if (waitedMillis > 48L * 60 * 60 * 1000) color = "4";
else if (waitedMillis > 24L * 60 * 60 * 1000) color = "c";
else if (waitedMillis > 12L * 60 * 60 * 1000) color = "6";
else if (waitedMillis > 4L * 60 * 60 * 1000) color = "e";
else color = "a";
String ce = waitedMillis > 86400000 ? "c" : "e";
String color = waitedMillis > 14400000 ? ce : "a";
long hours = waitedMillis / 3600000;
long minutes = (waitedMillis - hours * 3600000) / 60000;
return new Message("CHECK_LIST_WAIT", color, hours, (minutes < 10) ? "0" + minutes : minutes);
}
public CheckCommand() {
super("check");
VelocityCore.schedule(() -> Chatter.allStream().forEach(CheckCommand::sendReminder)).delay(10, TimeUnit.MINUTES).repeat(10, TimeUnit.MINUTES).schedule();
}
super("check", UserPerm.CHECK);
@Override
protected boolean hasPermission(SimpleCommand.Invocation invocation) {
SteamwarUser user = Chatter.of(invocation.source()).user();
if (user.perms().contains(UserPerm.CHECK)) return true;
return GameModeConfig.getAll()
.stream()
.filter(GameModeConfig::isActive)
.anyMatch(gameMode -> gameMode.Checkers.contains(user.getId()));
}
private static Map<SchematicNode, SteamwarUser> getSchematics(SteamwarUser user) {
Map<SchematicNode, SteamwarUser> map = new HashMap<>();
for (SchematicNode schematicNode : getSchemsToCheck()) {
if (!mayCheck(user, schematicNode)) continue;
CheckSession checkSession = currentSchems.get(schematicNode.getId());
map.put(schematicNode, checkSession == null ? null : checkSession.checker.user());
}
return map;
}
private static boolean mayCheck(SteamwarUser user, SchematicNode schematic) {
GameModeConfig<String, String> gameModeConfig = ArenaMode.getBySchemType(schematic.getSchemtype());
if (gameModeConfig == null) gameModeConfig = GameModeConfig.getDefaults();
if (user.hasPerm(UserPerm.ADMINISTRATION)) return true;
if (gameModeConfig.Checkers.isEmpty() && user.hasPerm(UserPerm.CHECK)) return true;
return gameModeConfig.Checkers.contains(user.getId());
VelocityCore.schedule(() -> sendReminder(Chatter.serverteam())).repeat(10, TimeUnit.MINUTES).schedule();
}
public static void sendReminder(Chatter chatter) {
Map<SchematicNode, SteamwarUser> schematics = getSchematics(chatter.user());
if (schematics.isEmpty()) return;
long needsChecking = schematics.entrySet().stream().filter(entry -> entry.getValue() == null).count();
if (needsChecking == 0) return;
chatter.system("CHECK_REMINDER", new Message("CHECK_REMINDER_HOVER"), ClickEvent.runCommand("/check list"), needsChecking);
List<SchematicNode> schematics = getSchemsToCheck();
if (schematics.size() == currentCheckers.size()) return;
chatter.system("CHECK_REMINDER", new Message("CHECK_REMINDER_HOVER"), ClickEvent.runCommand("/check list"), schematics.size() - currentCheckers.size());
}
@Register(value = "list", description = "CHECK_HELP_LIST")
public void list(Chatter sender) {
Map<SchematicNode, SteamwarUser> schematics = getSchematics(sender.user());
List<SchematicNode> schematicList = getSchemsToCheck();
sender.system("CHECK_LIST_HEADER", schematics.size());
sender.system("CHECK_LIST_HEADER", schematicList.size());
for (Map.Entry<SchematicNode, SteamwarUser> entry : schematics.entrySet()) {
String message;
ClickEvent clickEvent;
Message hoverMessage;
String checker;
if (entry.getValue() == null) {
message = "CHECK_LIST_TO_CHECK";
clickEvent = ClickEvent.runCommand("/check schematic " + entry.getKey().getId());
hoverMessage = new Message("CHECK_LIST_TO_CHECK_HOVER");
checker = "";
} else {
message = "CHECK_LIST_CHECKING";
clickEvent = ClickEvent.runCommand("/join " + entry.getValue().getUserName());
hoverMessage = new Message("CHECK_LIST_CHECKING_HOVER");
checker = entry.getValue().getUserName();
for (SchematicNode schematic : schematicList) {
GameModeConfig<String, String> gameModeConfig = ArenaMode.getBySchemType(schematic.getSchemtype());
if (gameModeConfig == null) gameModeConfig = GameModeConfig.getDefaults();
CheckSession current = currentSchems.get(schematic.getId());
ClickEvent clickEvent = null;
Message hoverMessage = null;
if (gameModeConfig.Checkers.isEmpty() || gameModeConfig.Checkers.contains(sender.user().getId())) {
if (current == null) {
clickEvent = ClickEvent.runCommand("/check schematic " + schematic.getId());
hoverMessage = new Message("CHECK_LIST_TO_CHECK_HOVER");
} else {
clickEvent = ClickEvent.runCommand("/join " + current.checker.user().getUserName());
hoverMessage = new Message("CHECK_LIST_CHECKING_HOVER");
}
}
sender.prefixless(message,
hoverMessage,
clickEvent,
getWaitTime(entry.getKey()),
entry.getKey().getSchemtype().getKuerzel(),
SteamwarUser.byId(entry.getKey().getOwner()).getUserName(),
entry.getKey().getName(),
checker);
if (current == null) {
sender.prefixless("CHECK_LIST_TO_CHECK",
hoverMessage,
clickEvent,
getWaitTime(schematic),
schematic.getSchemtype().getKuerzel(), SteamwarUser.byId(schematic.getOwner()).getUserName(), schematic.getName());
} else {
sender.prefixless("CHECK_LIST_CHECKING",
hoverMessage,
clickEvent,
getWaitTime(schematic),
schematic.getSchemtype().getKuerzel(), SteamwarUser.byId(schematic.getOwner()).getUserName(), schematic.getName(), current.checker.user().getUserName());
}
}
}
@@ -171,7 +142,8 @@ public class CheckCommand extends SWCommand {
}
int playerTeam = sender.user().hasPerm(UserPerm.MODERATION) ? 0 : sender.user().getTeam();
if (playerTeam != 0 && SteamwarUser.byId(schem.getOwner()).getTeam() == playerTeam) {
// Ignore 795 SteamWar Team
if (playerTeam != 0 && playerTeam != 795 && SteamwarUser.byId(schem.getOwner()).getTeam() == playerTeam) {
sender.system("CHECK_SCHEMATIC_OWN_TEAM");
return;
}
@@ -237,6 +209,11 @@ public class CheckCommand extends SWCommand {
return schematicList;
}
public static String getChecker(SchematicNode schematic) {
if (currentSchems.get(schematic.getId()) == null) return null;
return currentSchems.get(schematic.getId()).checker.user().getUserName();
}
private static boolean notChecking(Player player) {
if (!isChecking(player)) {
Chatter.of(player).system("CHECK_NOT_CHECKING");
@@ -35,9 +35,6 @@ import de.steamwar.sql.CheckedSchematic;
import de.steamwar.sql.SchematicType;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.UserPerm;
import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.advancements.Advancement;
import de.steamwar.velocitycore.advancements.Advancements;
import de.steamwar.velocitycore.commands.*;
import de.steamwar.velocitycore.discord.DiscordBot;
import de.steamwar.velocitycore.discord.util.DiscordRanks;
@@ -48,7 +45,6 @@ import net.kyori.adventure.text.event.ClickEvent;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Linked
public class ConnectionListener extends BasicListener {
@@ -84,7 +80,8 @@ public class ConnectionListener extends BasicListener {
Player player = event.getPlayer();
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
Chatter chatter = Chatter.of(player);
CheckCommand.sendReminder(chatter);
if (user.hasPerm(UserPerm.CHECK)) CheckCommand.sendReminder(chatter);
for (Subserver subserver : Subserver.getServerList()) {
if (Subserver.isArena(subserver)) {
@@ -105,12 +102,8 @@ public class ConnectionListener extends BasicListener {
}
if (newPlayers.contains(player.getUniqueId())) {
Advancements.ROOT.get(user, (advancement, __) -> new Advancement.Data(advancement, user, 0));
Chatter.broadcast().system("JOIN_FIRST", player);
newPlayers.remove(player.getUniqueId());
VelocityCore.schedule(() -> {
Advancements.ROOT.get(user).update();
}).delay(1, TimeUnit.SECONDS).schedule();
}
if (!StreamingCommand.isNotStreaming(user)) {
+1
View File
@@ -118,6 +118,7 @@ dependencyResolutionManagement {
library("nms", "de.steamwar:spigot:1.21.6")
library("axiom", "de.steamwar:axiompaper:RELEASE")
library("worldedit", "com.sk89q.worldedit:worldedit-bukkit:7.3.16")
library("fawe", "de.steamwar:fastasyncworldedit:1.21")
library("velocity", "de.steamwar:velocity:RELEASE")