Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ea0bb44416 | |||
| 4cb0ff292e | |||
| ee9eb995f5 | |||
| 147e34c0d6 | |||
| 313b22cb44 | |||
| 230ac09b61 | |||
| 48ea88e1a7 | |||
| 05dc42355d | |||
| 17704487c9 | |||
| 76bbfd0381 | |||
| ae9166528d | |||
| 119fae4b51 | |||
| 43621b18b4 | |||
| e5bdbac3c7 | |||
| fd738f539a | |||
| b4c7576433 | |||
| 8204e2ad21 | |||
| 684a74b60d | |||
| 1f58b51af6 | |||
| c9cfb48c4e | |||
| ace567ba33 | |||
| 2094120150 | |||
| e143268caa | |||
| 7802fdd7d9 | |||
| 7fb3d3d137 | |||
| 61d84492dc | |||
| f74780d395 | |||
| 62dac000d4 | |||
| 424c80ec81 | |||
| 306444356c | |||
| 29dff8dce6 | |||
| cbaacd4e85 | |||
| e24dada435 | |||
| d04ffd5cf6 | |||
| 9da1de9b6c | |||
| 866c376ee5 | |||
| 5b3c3f36b4 | |||
| e1bcdd59ba | |||
| 4a816696ec | |||
| 038f54c3b3 | |||
| 4c6ab2c1a0 | |||
| 20c90d9af5 | |||
| c799046f43 |
@@ -109,7 +109,7 @@ public class FlatteningWrapper15 implements FlatteningWrapper {
|
||||
|
||||
@Override
|
||||
public void setSelection(Player p, Point minPoint, Point maxPoint) {
|
||||
WORLDEDIT_PLUGIN.getSession(p).setRegionSelector(BUKKITWORLD, new CuboidRegionSelector(BUKKITWORLD, toBlockVector3(minPoint), toBlockVector3(maxPoint)));
|
||||
WORLDEDIT_PLUGIN.getSession(p).setRegionSelector(BUKKITWORLD, new CuboidRegionSelector(BUKKITWORLD, minPoint.toBlockVector3(), maxPoint.toBlockVector3()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -178,9 +178,9 @@ public class FlatteningWrapper15 implements FlatteningWrapper {
|
||||
pastePoint.set(v);
|
||||
|
||||
if (pasteBuilder.isReset()) {
|
||||
e.setBlocks(new CuboidRegion(toBlockVector3(pasteBuilder.getMinPoint()), toBlockVector3(pasteBuilder.getMaxPoint())), Objects.requireNonNull(BlockTypes.AIR).getDefaultState().toBaseBlock());
|
||||
e.setBlocks(new CuboidRegion(pasteBuilder.getMinPoint().toBlockVector3(), pasteBuilder.getMaxPoint().toBlockVector3()), Objects.requireNonNull(BlockTypes.AIR).getDefaultState().toBaseBlock());
|
||||
if (pasteBuilder.getWaterLevel() != 0) {
|
||||
e.setBlocks(new CuboidRegion(toBlockVector3(pasteBuilder.getMinPoint()), toBlockVector3(pasteBuilder.getMaxPoint()).withY(pasteBuilder.getWaterLevel())), Objects.requireNonNull(BlockTypes.WATER).getDefaultState().toBaseBlock());
|
||||
e.setBlocks(new CuboidRegion(pasteBuilder.getMinPoint().toBlockVector3(), pasteBuilder.getMaxPoint().toBlockVector3().withY(pasteBuilder.getWaterLevel())), Objects.requireNonNull(BlockTypes.WATER).getDefaultState().toBaseBlock());
|
||||
}
|
||||
}
|
||||
Operations.completeBlindly(ch.createPaste(e).to(v).ignoreAirBlocks(pasteBuilder.isIgnoreAir()).build());
|
||||
@@ -193,7 +193,7 @@ public class FlatteningWrapper15 implements FlatteningWrapper {
|
||||
@Override
|
||||
public Clipboard copy(Point minPoint, Point maxPoint, Point copyPoint) {
|
||||
BukkitWorld bukkitWorld = new BukkitWorld(Bukkit.getWorlds().get(0));
|
||||
CuboidRegion region = new CuboidRegion(bukkitWorld, toBlockVector3(minPoint), toBlockVector3(maxPoint));
|
||||
CuboidRegion region = new CuboidRegion(bukkitWorld, minPoint.toBlockVector3(), maxPoint.toBlockVector3());
|
||||
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
|
||||
try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(bukkitWorld, -1)) {
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(
|
||||
@@ -204,7 +204,7 @@ public class FlatteningWrapper15 implements FlatteningWrapper {
|
||||
copy.setCopyingBiomes(false);
|
||||
|
||||
Operations.complete(copy);
|
||||
clipboard.setOrigin(toBlockVector3(copyPoint));
|
||||
clipboard.setOrigin(copyPoint.toBlockVector3());
|
||||
return clipboard;
|
||||
} catch (WorldEditException e) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e);
|
||||
@@ -224,10 +224,6 @@ public class FlatteningWrapper15 implements FlatteningWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
private BlockVector3 toBlockVector3(Point point) {
|
||||
return BlockVector3.at(point.getX(), point.getY(), point.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inWater(org.bukkit.World world, Vector tntPosition) {
|
||||
Block block = world.getBlockAt(tntPosition.getBlockX(), tntPosition.getBlockY(), tntPosition.getBlockZ());
|
||||
|
||||
@@ -947,6 +947,9 @@ SPEED_TAB_NAME=Input speed
|
||||
WORLDEDIT_WAND=WorldEdit Wand
|
||||
WORLDEDIT_LEFTCLICK=Left click: select pos #1
|
||||
WORLDEDIT_RIGHTCLICK=Right click: select pos #2
|
||||
TNT_DETAILS_COMMAND=§8/§etntdetails §8-§7 Toggle information printed after clicking on a TNT
|
||||
TNT_DETAILS_ON = §eTNTDetails §aactivated
|
||||
TNT_DETAILS_OFF = §eTNTDetails §cdeactivated
|
||||
TNT_CLICK_HEADER=§8---=== §eTNT §8===---
|
||||
TNT_CLICK_ORDER=§eEntity Order§8: §e{0}
|
||||
TNT_CLICK_FUSE_TIME=§eFuseTime§8: §e{0}
|
||||
|
||||
@@ -889,6 +889,9 @@ SPEED_TAB_NAME=Geschwindigkeit eingeben
|
||||
WORLDEDIT_WAND=WorldEdit Wand
|
||||
WORLDEDIT_LEFTCLICK=Left click: select pos #1
|
||||
WORLDEDIT_RIGHTCLICK=Right click: select pos #2
|
||||
TNT_DETAILS_COMMAND=§8/§etntdetails §8-§7 Aktiviert/Deaktiviert das senden von Details beim Klick auf TNT
|
||||
TNT_DETAILS_ON = §eTNTDetails §aaktiviert
|
||||
TNT_DETAILS_OFF = §eTNTDetails §cdeaktiviert
|
||||
TNT_CLICK_HEADER=§8---=== §eTNT §8===---
|
||||
TNT_CLICK_ORDER=§eEntity Order§8: §e{0}
|
||||
TNT_CLICK_FUSE_TIME=§eFuseTime§8: §e{0}
|
||||
|
||||
@@ -11,8 +11,9 @@ import de.steamwar.linkage.Linked;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.data.type.NoteBlock;
|
||||
import org.bukkit.block.data.type.Switch;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
@@ -60,6 +61,24 @@ public class FreezeListener implements Listener, ScoreboardElement {
|
||||
@EventHandler
|
||||
public void onPhysicsEvent(BlockPhysicsEvent e) {
|
||||
if (Region.getRegion(e.getBlock().getLocation()).get(Flag.FREEZE) == FreezeMode.ACTIVE) {
|
||||
if (e.getSourceBlock().getType() == Material.NOTE_BLOCK) {
|
||||
BlockState state = e.getSourceBlock().getState();
|
||||
NoteBlock noteBlock = (NoteBlock) state.getBlockData();
|
||||
if (noteBlock.isPowered()) {
|
||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||
state.update(true, false);
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
if (e.getBlock().getType() == Material.NOTE_BLOCK) {
|
||||
BlockState state = e.getBlock().getState();
|
||||
NoteBlock noteBlock = (NoteBlock) state.getBlockData();
|
||||
if (noteBlock.isPowered()) {
|
||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||
state.update(true, false);
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
@@ -71,6 +90,105 @@ public class FreezeListener implements Listener, ScoreboardElement {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onNotePlay(NotePlayEvent event) {
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=45, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=45, z=98},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=45, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=45, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=45, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=44, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=45, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=98},type=BARRIER,data=Block{minecraft:barrier},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=45, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=45, z=97},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=45, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=45, z=99},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=custom_head,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=47, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=custom_head,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=47, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=custom_head,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=98},type=BARRIER,data=Block{minecraft:barrier},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=custom_head,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=48, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=custom_head,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=custom_head,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=45, z=97},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=96},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=98},type=BARRIER,data=Block{minecraft:barrier},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=45, z=99},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=98},type=BARRIER,data=Block{minecraft:barrier},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-108, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=98},type=BARRIER,data=Block{minecraft:barrier},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=45, z=98},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=47, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=98},type=BARRIER,data=Block{minecraft:barrier},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-104, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=45, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=47, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=47, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=47, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=98},type=BARRIER,data=Block{minecraft:barrier},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=48, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
|
||||
|
||||
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=100},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=46, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=100},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=46, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=100},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=45, z=100},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=100},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=100},type=STONE_SLAB,data=Block{minecraft:stone_slab}[type=bottom,waterlogged=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=100},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=99},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=100},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=100},type=STONE_SLAB,data=Block{minecraft:stone_slab}[type=bottom,waterlogged=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=49, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=48, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=48, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=99},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=48, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
////[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=100},type=STONE_SLAB,data=Block{minecraft:stone_slab}[type=bottom,waterlogged=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=48, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=100},type=STONE_SLAB,data=Block{minecraft:stone_slab}[type=bottom,waterlogged=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=102},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-108, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=100},type=STONE_SLAB,data=Block{minecraft:stone_slab}[type=bottom,waterlogged=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=46, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=100},type=STONE_SLAB,data=Block{minecraft:stone_slab}[type=bottom,waterlogged=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-104, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=46, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=47, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=47, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=48, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
//[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
public void onPistonRetract(BlockPistonRetractEvent e) {
|
||||
if (Region.getRegion(e.getBlock().getLocation()).get(Flag.FREEZE) == FreezeMode.ACTIVE) {
|
||||
|
||||
@@ -51,7 +51,7 @@ public class TpsLib implements LuaLib {
|
||||
tpsLib.set("fiveMinute", getter(() -> TPSWatcher.getTPS(TPSWatcher.TPSType.FIVE_MINUTES)));
|
||||
tpsLib.set("tenMinute", getter(() -> TPSWatcher.getTPS(TPSWatcher.TPSType.TEN_MINUTES)));
|
||||
tpsLib.set("current", getter(TPSWatcher::getTPS));
|
||||
tpsLib.set("limit", getter(tpsSystem::getCurrentTPSLimit));
|
||||
tpsLib.set("limit", getter(TPSSystem::getCurrentTPSLimit));
|
||||
return tpsLib;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ public class SimulatorCommand extends SWCommand {
|
||||
|
||||
@Register(value = "start", description = "SIMULATOR_START_HELP")
|
||||
public void start(@Validator Player p, @ErrorMessage("SIMULATOR_NOT_EXISTS") Simulator simulator) {
|
||||
SimulatorExecutor.run(simulator);
|
||||
SimulatorExecutor.run(simulator, () -> {});
|
||||
}
|
||||
|
||||
@Register(value = "rename", description = "SIMULATOR_RENAME_HELP")
|
||||
|
||||
@@ -168,9 +168,19 @@ public class SimulatorCursor implements Listener {
|
||||
}
|
||||
return;
|
||||
}
|
||||
Simulator simulator = SimulatorStorage.getSimulator(player);
|
||||
SimulatorWatcher.show(simulator, player);
|
||||
|
||||
Simulator simulator = SimulatorStorage.getSimulator(player);
|
||||
if (simulator != null && simulator.getStabGenerator() != null) {
|
||||
removeCursor(player);
|
||||
SimulatorWatcher.show(null, player);
|
||||
SWUtils.sendToActionbar(player, "§cGenerating Stab");
|
||||
synchronized (calculating) {
|
||||
calculating.remove(player);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
SimulatorWatcher.show(simulator, player);
|
||||
List<REntity> entities = SimulatorWatcher.getEntitiesOfSimulator(simulator);
|
||||
RayTraceUtils.RRayTraceResult rayTraceResult = RayTraceUtils.traceREntity(player, player.getLocation(), entities);
|
||||
if (rayTraceResult == null) {
|
||||
@@ -357,7 +367,7 @@ public class SimulatorCursor implements Listener {
|
||||
if (simulator == null) {
|
||||
return;
|
||||
}
|
||||
SimulatorExecutor.run(simulator);
|
||||
SimulatorExecutor.run(simulator, () -> {});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
package de.steamwar.bausystem.features.simulator.data;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.execute.SimulatorAction;
|
||||
import de.steamwar.bausystem.features.simulator.execute.SimulatorStabGenerator;
|
||||
import de.steamwar.inventory.InvCallback;
|
||||
import de.steamwar.inventory.SWItem;
|
||||
import lombok.Getter;
|
||||
@@ -30,13 +31,13 @@ import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@RequiredArgsConstructor
|
||||
public final class Simulator {
|
||||
private SimulatorStabGenerator stabGenerator = null;
|
||||
private Material material = Material.BARREL;
|
||||
private final String name;
|
||||
private boolean autoTrace = false;
|
||||
|
||||
@@ -60,6 +60,7 @@ public final class TNTPhase extends SimulatorPhase {
|
||||
|
||||
@Override
|
||||
public void toSimulatorActions(Vector position, BiConsumer<Integer, SimulatorAction> tickStart, BiConsumer<Integer, SimulatorAction> tickEnd) {
|
||||
if (count <= 0) return;
|
||||
tickStart.accept(tickOffset, new SimulatorAction(order, count) {
|
||||
@Override
|
||||
public void accept(World world) {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 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.simulator.execute;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
@AllArgsConstructor
|
||||
public enum Direction {
|
||||
X(Vector::getBlockX),
|
||||
Y(Vector::getBlockY),
|
||||
Z(Vector::getBlockZ);
|
||||
|
||||
public final Function<Vector, Integer> component;
|
||||
}
|
||||
@@ -46,7 +46,7 @@ public class SimulatorExecutor implements Listener {
|
||||
private static Map<Long, Map<Integer, List<SimulatorAction>>> tickStartActions = new HashMap<>();
|
||||
private static Map<Long, List<SimulatorAction>> tickEndActions = new HashMap<>();
|
||||
|
||||
public static boolean run(Simulator simulator) {
|
||||
public static boolean run(Simulator simulator, Runnable onEnd) {
|
||||
if (currentlyRunning.contains(simulator)) return false;
|
||||
currentlyRunning.add(simulator);
|
||||
|
||||
@@ -69,7 +69,7 @@ public class SimulatorExecutor implements Listener {
|
||||
public void accept(World world) {
|
||||
currentlyRunning.remove(simulator);
|
||||
|
||||
if (simulator.isAutoTrace()) {
|
||||
if (simulator.isAutoTrace() && onEnd == null) {
|
||||
simulator.getGroups()
|
||||
.stream()
|
||||
.map(SimulatorGroup::getElements)
|
||||
@@ -82,10 +82,12 @@ public class SimulatorExecutor implements Listener {
|
||||
TraceRecorder.instance.stopRecording(region);
|
||||
});
|
||||
}
|
||||
|
||||
onEnd.run();
|
||||
}
|
||||
});
|
||||
|
||||
if (simulator.isAutoTrace()) {
|
||||
if (simulator.isAutoTrace() && onEnd == null) {
|
||||
simulator.getGroups()
|
||||
.stream()
|
||||
.map(SimulatorGroup::getElements)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 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.simulator.execute;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement;
|
||||
import de.steamwar.bausystem.region.Region;
|
||||
import de.steamwar.bausystem.utils.bossbar.BossBarService;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class SimulatorStabGenerator {
|
||||
|
||||
private final StabData stabData;
|
||||
|
||||
public SimulatorStabGenerator(Region region, Simulator simulator, TNTElement tntElement, int depthLimit) {
|
||||
stabData = new StabData(region, simulator, tntElement, tntElement.getPhases(), depthLimit);
|
||||
new StabSetup(stabData);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
stabData.cancel = true;
|
||||
stabData.simulator.setStabGenerator(null);
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
BossBarService.instance.remove(player, stabData.region, "simulator_stab_generator");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 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.simulator.execute;
|
||||
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase;
|
||||
import de.steamwar.bausystem.region.Region;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class StabData {
|
||||
|
||||
protected static final int MAX_RECORDINGS = 5;
|
||||
protected static final int MAX_TICK_DIFFERENCE = 3;
|
||||
protected static final Level LEVEL = Level.INFO;
|
||||
protected static final int TNT_INCREASE = 10;
|
||||
protected static final int MIN_BLOCK_TO_COUNT_AS_DEPTH = 20;
|
||||
|
||||
protected final Region region;
|
||||
protected final Simulator simulator;
|
||||
protected final TNTElement tntElement;
|
||||
protected final List<TNTPhase> phases;
|
||||
protected final int depthLimit;
|
||||
|
||||
protected Clipboard clipboard;
|
||||
protected boolean cancel = false;
|
||||
|
||||
protected Direction direction = null;
|
||||
protected int currentDepth = 0;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 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.simulator.execute;
|
||||
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorPhase;
|
||||
import de.steamwar.bausystem.features.tracer.TNTPoint;
|
||||
import de.steamwar.bausystem.features.tracer.Trace;
|
||||
import de.steamwar.bausystem.features.tracer.TraceManager;
|
||||
import de.steamwar.bausystem.features.tracer.TraceRecorder;
|
||||
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class StabDirection extends StabStep {
|
||||
|
||||
public StabDirection(StabData data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void start() {
|
||||
try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(new BukkitWorld(Bukkit.getWorlds().get(0)), -1)) {
|
||||
e.setBlocks((com.sk89q.worldedit.regions.Region) new CuboidRegion(data.region.getMinPointTestblockExtension().toBlockVector3(), data.region.getMaxPointTestblockExtension().toBlockVector3()), Objects.requireNonNull(BlockTypes.AIR).getDefaultState().toBaseBlock());
|
||||
}
|
||||
|
||||
Trace trace = TraceRecorder.instance.startRecording(data.region);
|
||||
runSimulator(() -> {
|
||||
TraceRecorder.instance.stopRecording(data.region);
|
||||
calculateDirection(trace);
|
||||
});
|
||||
}
|
||||
|
||||
private void calculateDirection(Trace trace) {
|
||||
long tickSinceStart = -1;
|
||||
List<TNTPoint> points = null;
|
||||
for (List<TNTPoint> current : trace.getHistories()) {
|
||||
long ticks = current.get(0).getTicksSinceStart();
|
||||
if (points == null || ticks > tickSinceStart) {
|
||||
tickSinceStart = ticks;
|
||||
points = current;
|
||||
} else if (ticks == tickSinceStart && points.get(0).getTntId() < current.get(0).getTntId()) {
|
||||
points = current;
|
||||
}
|
||||
}
|
||||
TraceManager.instance.remove(trace);
|
||||
if (points == null) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
TNTPoint current = points.getLast();
|
||||
Vector velocity = current.getVelocity();
|
||||
if (velocity.getX() < 0) velocity.setX(-velocity.getX());
|
||||
if (velocity.getY() < 0) velocity.setY(-velocity.getY());
|
||||
if (velocity.getZ() < 0) velocity.setZ(-velocity.getZ());
|
||||
if (velocity.getX() > velocity.getY() && velocity.getX() > velocity.getZ()) {
|
||||
data.direction = Direction.X;
|
||||
} else if (velocity.getY() > velocity.getX() && velocity.getY() > velocity.getZ()) {
|
||||
data.direction = Direction.Y;
|
||||
} else if (velocity.getZ() > velocity.getX() && velocity.getZ() > velocity.getY()) {
|
||||
data.direction = Direction.Z;
|
||||
} else {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
Bukkit.getLogger().log(StabData.LEVEL, "Direction: {0}", data.direction);
|
||||
data.phases.getFirst().setOrder(SimulatorPhase.ORDER_LIMIT);
|
||||
data.phases.getFirst().setCount(StabData.TNT_INCREASE);
|
||||
new StabGenerator(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bossbar(BauSystemBossbar bossbar, boolean finished) {
|
||||
bossbar.setProgress(0);
|
||||
bossbar.setTitle("§eCalculating Stab Direction");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 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.simulator.execute;
|
||||
|
||||
import de.steamwar.bausystem.features.tracer.Trace;
|
||||
import de.steamwar.bausystem.features.tracer.TraceRecorder;
|
||||
import de.steamwar.bausystem.region.flags.Flag;
|
||||
import de.steamwar.bausystem.region.flags.flagvalues.ColorMode;
|
||||
import de.steamwar.bausystem.region.utils.RegionExtensionType;
|
||||
import de.steamwar.bausystem.region.utils.RegionType;
|
||||
import de.steamwar.bausystem.utils.PasteBuilder;
|
||||
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
|
||||
|
||||
public class StabFinalizer extends StabStep {
|
||||
|
||||
public StabFinalizer(StabData data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void start() {
|
||||
try {
|
||||
PasteBuilder.ClipboardProvider clipboardProvider = new PasteBuilder.ClipboardProviderImpl(data.clipboard);
|
||||
PasteBuilder pasteBuilder = new PasteBuilder(clipboardProvider)
|
||||
.color(data.region.getPlain(Flag.COLOR, ColorMode.class).getColor());
|
||||
data.region.reset(pasteBuilder, RegionType.TESTBLOCK, RegionExtensionType.EXTENSION);
|
||||
} catch (SecurityException e) {
|
||||
stop();
|
||||
throw e;
|
||||
}
|
||||
|
||||
TraceRecorder.instance.startRecording(data.region);
|
||||
runSimulator(() -> {
|
||||
TraceRecorder.instance.stopRecording(data.region);
|
||||
stop();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bossbar(BauSystemBossbar bossbar, boolean stopped) {
|
||||
bossbar.setProgress(Math.min(data.currentDepth / (double) data.depthLimit, 1.0));
|
||||
bossbar.setTitle("§e" + data.currentDepth + "§8/§7" + data.depthLimit);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 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.simulator.execute;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase;
|
||||
import de.steamwar.bausystem.region.Region;
|
||||
import de.steamwar.bausystem.region.flags.Flag;
|
||||
import de.steamwar.bausystem.region.flags.flagvalues.ColorMode;
|
||||
import de.steamwar.bausystem.region.utils.RegionExtensionType;
|
||||
import de.steamwar.bausystem.region.utils.RegionType;
|
||||
import de.steamwar.bausystem.utils.PasteBuilder;
|
||||
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static de.steamwar.bausystem.features.simulator.execute.Direction.Y;
|
||||
|
||||
public class StabGenerator extends StabStep implements Listener {
|
||||
|
||||
private int recordings = 0;
|
||||
private List<Integer> currentDepths = new ArrayList<>();
|
||||
private int lastDepth = 0;
|
||||
|
||||
private int retries = 0;
|
||||
|
||||
private final Map<Integer, Set<Location>> destroyedBlocksPerSlice = new HashMap<>();
|
||||
|
||||
private Set<Integer> gabStart = new HashSet<>();
|
||||
private Set<TNTPhase> failedAtLeastOnce = new HashSet<>();
|
||||
|
||||
@EventHandler
|
||||
public void onEntityExplode(EntityExplodeEvent event) {
|
||||
if (Region.getRegion(event.getEntity().getLocation()) == data.region) {
|
||||
event.blockList().forEach(block -> {
|
||||
if (!data.region.inRegion(block.getLocation(), RegionType.TESTBLOCK, RegionExtensionType.EXTENSION)) return;
|
||||
int component = data.direction.component.apply(block.getLocation().toVector());
|
||||
destroyedBlocksPerSlice.computeIfAbsent(component, __ -> new HashSet<>())
|
||||
.add(block.getLocation());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public StabGenerator(StabData data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void start() {
|
||||
try {
|
||||
PasteBuilder.ClipboardProvider clipboardProvider = new PasteBuilder.ClipboardProviderImpl(data.clipboard);
|
||||
PasteBuilder pasteBuilder = new PasteBuilder(clipboardProvider)
|
||||
.color(data.region.getPlain(Flag.COLOR, ColorMode.class).getColor());
|
||||
data.region.reset(pasteBuilder, RegionType.TESTBLOCK, RegionExtensionType.EXTENSION);
|
||||
} catch (SecurityException e) {
|
||||
stop();
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (data.cancel) {
|
||||
HandlerList.unregisterAll(this);
|
||||
return;
|
||||
}
|
||||
|
||||
runSimulator(this::calculateStab);
|
||||
}
|
||||
|
||||
private void calculateStab() {
|
||||
TNTPhase lastPhase = data.phases.getLast();
|
||||
|
||||
List<Map.Entry<Integer, Set<Location>>> locations = destroyedBlocksPerSlice.entrySet()
|
||||
.stream()
|
||||
.sorted(Comparator.comparingInt(Map.Entry::getKey))
|
||||
.collect(Collectors.toList());
|
||||
int depth = 0;
|
||||
for (int i = 0; i < locations.size(); i++) {
|
||||
if (data.direction != Y && i > 0 && Math.abs(locations.get(i - 1).getKey() - locations.get(i).getKey()) > 3) {
|
||||
if (gabStart.add(locations.get(i).getKey())) {
|
||||
Bukkit.getLogger().log(StabData.LEVEL, "Increasing tnt count by {0} because of gap", StabData.TNT_INCREASE);
|
||||
lastPhase.setCount(lastPhase.getCount() + StabData.TNT_INCREASE);
|
||||
recordings = 0;
|
||||
currentDepths.clear();
|
||||
|
||||
run();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (i == 0 || i == locations.size() - 1) {
|
||||
if (locations.get(i).getValue().size() > StabData.MIN_BLOCK_TO_COUNT_AS_DEPTH) {
|
||||
depth++;
|
||||
}
|
||||
} else {
|
||||
depth++;
|
||||
}
|
||||
}
|
||||
|
||||
if (depth > 0) {
|
||||
Bukkit.getLogger().log(StabData.LEVEL, "{0} {1} {2}", new Object[]{depth, destroyedBlocksPerSlice.size(), destroyedBlocksPerSlice.values().stream().map(Set::size).collect(Collectors.toList())});
|
||||
destroyedBlocksPerSlice.clear();
|
||||
currentDepths.add(depth);
|
||||
} else {
|
||||
destroyedBlocksPerSlice.clear();
|
||||
lastPhase.setTickOffset(lastPhase.getTickOffset() + 1);
|
||||
Bukkit.getLogger().log(StabData.LEVEL, "No dimension - Increasing tickOffset to: {0}", lastPhase.getTickOffset());
|
||||
lastPhase.setOrder(0);
|
||||
if (lastPhase.getTickOffset() > 80) {
|
||||
stop();
|
||||
} else {
|
||||
run();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int minDepth = currentDepths.stream().min(Integer::compareTo).orElse(0);
|
||||
int maxDepth = currentDepths.stream().max(Integer::compareTo).orElse(0);
|
||||
data.currentDepth = maxDepth;
|
||||
|
||||
int countWithoutLast = 0;
|
||||
for (int i = 0; i < data.phases.size() - 1; i++) {
|
||||
countWithoutLast += data.phases.get(i).getCount();
|
||||
}
|
||||
countWithoutLast -= gabStart.size();
|
||||
|
||||
boolean moreTNTNeeded = maxDepth - countWithoutLast >= lastPhase.getCount() - 5;
|
||||
if (moreTNTNeeded) {
|
||||
Bukkit.getLogger().log(StabData.LEVEL, "Increasing tnt count by {0}", StabData.TNT_INCREASE);
|
||||
lastPhase.setCount(lastPhase.getCount() + StabData.TNT_INCREASE);
|
||||
recordings = 0;
|
||||
currentDepths.clear();
|
||||
|
||||
run();
|
||||
return;
|
||||
}
|
||||
|
||||
if (recordings++ < StabData.MAX_RECORDINGS) {
|
||||
run();
|
||||
return;
|
||||
}
|
||||
|
||||
recordings = 0;
|
||||
currentDepths.clear();
|
||||
|
||||
if (maxDepth - minDepth > lastPhase.getCount()) {
|
||||
Bukkit.getLogger().log(StabData.LEVEL, "Stab failed at least once. Adding one tnt to {0}", minDepth - 3);
|
||||
int current = 0;
|
||||
TNTPhase last = null;
|
||||
for (TNTPhase phase : data.phases) {
|
||||
if (current < minDepth - 3) {
|
||||
current += phase.getCount();
|
||||
last = phase;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (failedAtLeastOnce.add(last)) {
|
||||
last = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (last != null) {
|
||||
last.setCount(last.getCount() + 1);
|
||||
Bukkit.getLogger().log(StabData.LEVEL, "Added to phase {0} now has {1} tnt", new Object[]{data.phases.indexOf(last), last.getCount()});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (last != null) {
|
||||
run();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Bukkit.getLogger().log(StabData.LEVEL, "No more TNT needed on phase adjusting - {0} new count; {1} current count", new Object[]{maxDepth - countWithoutLast, lastPhase.getCount()});
|
||||
lastPhase.setCount(maxDepth - countWithoutLast);
|
||||
if (lastPhase.getCount() <= 0) {
|
||||
Bukkit.getLogger().log(StabData.LEVEL, "Count was 0 or negative - removing last phase");
|
||||
data.phases.removeLast();
|
||||
}
|
||||
|
||||
if (maxDepth > data.depthLimit) {
|
||||
Bukkit.getLogger().log(StabData.LEVEL, "Depth is greater than {0} - finished", data.depthLimit);
|
||||
new StabFinalizer(data);
|
||||
return;
|
||||
}
|
||||
if (maxDepth <= lastDepth) {
|
||||
if (lastPhase.getCount() <= 0) {
|
||||
retries++;
|
||||
}
|
||||
if (lastPhase.getCount() > 0 || retries > StabData.MAX_TICK_DIFFERENCE) {
|
||||
Bukkit.getLogger().log(StabData.LEVEL, "Depth is equal to last depth recorded {0} - finished", maxDepth);
|
||||
new StabFinalizer(data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
lastDepth = maxDepth;
|
||||
|
||||
newPhase(data, lastPhase);
|
||||
run();
|
||||
}
|
||||
|
||||
public static void newPhase(StabData data, TNTPhase lastPhase) {
|
||||
Bukkit.getLogger().log(StabData.LEVEL, "Adding new phase in next tick");
|
||||
TNTPhase nextPhase = new TNTPhase();
|
||||
nextPhase.setCount(StabData.TNT_INCREASE);
|
||||
nextPhase.setTickOffset(lastPhase.getTickOffset() + 1);
|
||||
nextPhase.setXJump(lastPhase.isXJump());
|
||||
nextPhase.setYJump(lastPhase.isYJump());
|
||||
nextPhase.setZJump(lastPhase.isZJump());
|
||||
data.phases.add(nextPhase);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bossbar(BauSystemBossbar bossbar, boolean finished) {
|
||||
bossbar.setProgress(Math.min(data.currentDepth / (double) data.depthLimit, 1.0));
|
||||
if (finished) {
|
||||
bossbar.setTitle("§e" + data.currentDepth + "§8/§7" + data.depthLimit);
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder st = new StringBuilder();
|
||||
st.append("§7Direction §e").append(data.direction);
|
||||
st.append(" §e").append(data.currentDepth).append("§8/§7").append(data.depthLimit);
|
||||
if (recordings > 0) {
|
||||
st.append(" §7Retries§8:§e ").append(recordings).append("§8/§7").append(StabData.MAX_RECORDINGS);
|
||||
}
|
||||
bossbar.setTitle(st.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 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.simulator.execute;
|
||||
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase;
|
||||
import de.steamwar.bausystem.features.tracer.TraceRecorder;
|
||||
import de.steamwar.bausystem.utils.FlatteningWrapper;
|
||||
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class StabSetup extends StabStep {
|
||||
|
||||
public StabSetup(StabData data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void start() {
|
||||
TNTPhase tntPhase = data.simulator.getGroups().stream()
|
||||
.filter(simulatorGroup -> !simulatorGroup.isDisabled())
|
||||
.map(SimulatorGroup::getElements)
|
||||
.flatMap(List::stream)
|
||||
.filter(TNTElement.class::isInstance)
|
||||
.map(TNTElement.class::cast)
|
||||
.filter(tntElement -> !tntElement.isDisabled())
|
||||
.filter(tntElement -> data.tntElement != tntElement)
|
||||
.map(tntElement -> tntElement.getPhases().stream().max(Comparator.comparingInt(TNTPhase::getTickOffset)))
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.peek(phase -> {
|
||||
if (phase.getOrder() > TNTPhase.ORDER_LIMIT) {
|
||||
phase.setOrder(TNTPhase.ORDER_LIMIT);
|
||||
}
|
||||
})
|
||||
.filter(phase -> phase != data.phases.get(0))
|
||||
.max(Comparator.comparingInt(TNTPhase::getTickOffset))
|
||||
.orElse(null);
|
||||
if (tntPhase == null) {
|
||||
throw new SecurityException("");
|
||||
}
|
||||
|
||||
TNTPhase phase = data.phases.get(0);
|
||||
data.phases.clear();
|
||||
data.phases.add(phase);
|
||||
phase.setCount(1);
|
||||
phase.setTickOffset(tntPhase.getTickOffset());
|
||||
phase.setOrder(100);
|
||||
|
||||
TraceRecorder.instance.stopRecording(data.region);
|
||||
if (TraceRecorder.instance.isAutoTraceEnabledInRegion(data.region)) {
|
||||
TraceRecorder.instance.removeAutoTraceRegion(data.region);
|
||||
}
|
||||
data.clipboard = FlatteningWrapper.impl.copy(data.region.getMinPointTestblockExtension(), data.region.getMaxPointTestblockExtension(), data.region.getTestBlockPoint());
|
||||
|
||||
new StabDirection(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bossbar(BauSystemBossbar bossbar, boolean finished) {
|
||||
bossbar.setProgress(0);
|
||||
bossbar.setTitle("§eSetting up Simulator");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 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.simulator.execute;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
|
||||
import de.steamwar.bausystem.utils.bossbar.BossBarService;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.boss.BarColor;
|
||||
import org.bukkit.boss.BarStyle;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
public abstract class StabStep {
|
||||
|
||||
protected final StabData data;
|
||||
|
||||
protected StabStep(StabData data) {
|
||||
this.data = data;
|
||||
run();
|
||||
}
|
||||
|
||||
protected final void run() {
|
||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
BauSystemBossbar bossbar = BossBarService.instance.get(player, data.region, "simulator_stab_generator");
|
||||
bossbar.setColor(BarColor.GREEN);
|
||||
bossbar.setStyle(BarStyle.SEGMENTED_10);
|
||||
bossbar(bossbar, false);
|
||||
}
|
||||
}, 1);
|
||||
|
||||
if (this instanceof Listener) {
|
||||
Bukkit.getPluginManager().registerEvents((Listener) this, BauSystem.getInstance());
|
||||
}
|
||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::start, 20);
|
||||
}
|
||||
|
||||
protected abstract void start();
|
||||
|
||||
protected final void runSimulator(Runnable onFinish) {
|
||||
SimulatorExecutor.run(data.simulator, () -> {
|
||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||
if (this instanceof Listener) {
|
||||
HandlerList.unregisterAll((Listener) this);
|
||||
}
|
||||
onFinish.run();
|
||||
}, 20);
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract void bossbar(BauSystemBossbar bossbar, boolean stopped);
|
||||
|
||||
protected final void stop() {
|
||||
data.simulator.setStabGenerator(null);
|
||||
SimulatorWatcher.update(data.simulator);
|
||||
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
BauSystemBossbar bossbar = BossBarService.instance.get(player, data.region, "simulator_stab_generator");
|
||||
bossbar.setColor(BarColor.GREEN);
|
||||
bossbar.setStyle(BarStyle.SEGMENTED_10);
|
||||
bossbar(bossbar, true);
|
||||
}
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(4000);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
} finally {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
BossBarService.instance.remove(player, data.region, "simulator_stab_generator");
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
@@ -24,8 +24,11 @@ import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement;
|
||||
import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase;
|
||||
import de.steamwar.bausystem.features.simulator.execute.SimulatorStabGenerator;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorScrollGui;
|
||||
import de.steamwar.bausystem.region.Region;
|
||||
import de.steamwar.inventory.SWItem;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -97,6 +100,14 @@ public class SimulatorTNTGui extends SimulatorScrollGui<TNTPhase> {
|
||||
tnt.setDisabled(!tnt.isDisabled());
|
||||
SimulatorWatcher.update(simulator);
|
||||
}));
|
||||
inventory.setItem(49, new SWItem(Material.CALIBRATED_SCULK_SENSOR, "§eCreate Stab", click -> {
|
||||
new SimulatorAnvilGui<>(player, "Depth Limit", "", Integer::parseInt, depthLimit -> {
|
||||
if (depthLimit <= 0) return false;
|
||||
simulator.setStabGenerator(new SimulatorStabGenerator(Region.getRegion(player.getLocation()), simulator, tnt, depthLimit));
|
||||
SimulatorWatcher.update(simulator);
|
||||
return true;
|
||||
}, null).open();
|
||||
}));
|
||||
inventory.setItem(50, new SWItem(Material.CHEST, parent.getElements().size() == 1 ? "§eMake Group" : "§eAdd another TNT to Group", clickType -> {
|
||||
TNTElement tntElement = new TNTElement(tnt.getPosition().clone());
|
||||
tntElement.add(new TNTPhase());
|
||||
|
||||
@@ -44,7 +44,7 @@ public class SimulatorAnvilGui<T extends Number> {
|
||||
if (error.get()) {
|
||||
anvilInv.open();
|
||||
} else {
|
||||
back.open();
|
||||
if (back != null) back.open();
|
||||
}
|
||||
error.set(false);
|
||||
}, 0);
|
||||
|
||||
@@ -22,7 +22,6 @@ package de.steamwar.bausystem.features.simulator.gui.base;
|
||||
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
|
||||
import de.steamwar.bausystem.features.simulator.data.Simulator;
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.core.TrickyTrialsWrapper;
|
||||
import de.steamwar.inventory.SWInventory;
|
||||
import de.steamwar.inventory.SWItem;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -64,7 +63,11 @@ public abstract class SimulatorBaseGui {
|
||||
if (Core.getVersion() > 19) {
|
||||
player.getOpenInventory().setTitle(title());
|
||||
}
|
||||
populate();
|
||||
if (simulator != null && simulator.getStabGenerator() != null) {
|
||||
populateStabGenerator();
|
||||
} else {
|
||||
populate();
|
||||
}
|
||||
if (player.getOpenInventory().getTopInventory() == inv) {
|
||||
inventory.open();
|
||||
SimulatorWatcher.watch(player, simulator, this::open);
|
||||
@@ -84,10 +87,21 @@ public abstract class SimulatorBaseGui {
|
||||
});
|
||||
|
||||
SimulatorWatcher.watch(player, simulator, this::open);
|
||||
populate();
|
||||
if (simulator != null && simulator.getStabGenerator() != null) {
|
||||
populateStabGenerator();
|
||||
} else {
|
||||
populate();
|
||||
}
|
||||
inventory.open();
|
||||
}
|
||||
|
||||
private void populateStabGenerator() {
|
||||
inventory.setItem(22, new SWItem(Material.BARRIER, "§cCancel Stab Generator", click -> {
|
||||
simulator.getStabGenerator().cancel();
|
||||
SimulatorWatcher.update(simulator);
|
||||
}));
|
||||
}
|
||||
|
||||
public boolean shouldOpen() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
package de.steamwar.bausystem.features.smartplace;
|
||||
|
||||
import de.steamwar.Reflection;
|
||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||
import de.steamwar.Reflection;
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.Permission;
|
||||
import de.steamwar.bausystem.configplayer.Config;
|
||||
@@ -223,7 +223,7 @@ public class SmartPlaceListener implements Listener {
|
||||
Block block = event.getBlock().getRelative(BlockFace.DOWN);
|
||||
BlockState old = block.getState();
|
||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||
block.setType(Material.GLASS, false);
|
||||
block.setType(Material.GLASS, true);
|
||||
old.update(true, false);
|
||||
}, 1);
|
||||
}
|
||||
|
||||
@@ -42,16 +42,16 @@ public class TPSCommand extends SWCommand {
|
||||
public void genericCommand(Player p, String... args) {
|
||||
BauSystem.MESSAGE.sendPrefixless("OTHER_TPS_HEAD", p);
|
||||
BauSystem.MESSAGE.sendPrefixless("OTHER_TPS_MESSAGE", p,
|
||||
TPSWatcher.getTPS(TPSWatcher.TPSType.ONE_SECOND),
|
||||
TPSWatcher.getTPS(TPSWatcher.TPSType.TEN_SECONDS),
|
||||
TPSWatcher.getTPS(TPSWatcher.TPSType.ONE_MINUTE),
|
||||
TPSWatcher.getTPS(TPSWatcher.TPSType.FIVE_MINUTES),
|
||||
TPSWatcher.getTPS(TPSWatcher.TPSType.TEN_MINUTES)
|
||||
TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.ONE_SECOND),
|
||||
TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.TEN_SECONDS),
|
||||
TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.ONE_MINUTE),
|
||||
TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.FIVE_MINUTES),
|
||||
TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.TEN_MINUTES)
|
||||
);
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(Player p, TPSWatcher.TPSType type) {
|
||||
BauSystem.MESSAGE.sendPrefixless("OTHER_TPS_SINGLE", p, tpsSystem.getTPS(type));
|
||||
BauSystem.MESSAGE.sendPrefixless("OTHER_TPS_SINGLE", p, TPSWatcher.getTPSUnlimited(type));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,11 +56,7 @@ import java.util.Arrays;
|
||||
public class TPSSystem implements Listener {
|
||||
|
||||
@Getter
|
||||
private double currentTPSLimit = 20;
|
||||
|
||||
public double getTPS(TPSWatcher.TPSType tpsType) {
|
||||
return TPSWatcher.getTPSUnlimited(tpsType);
|
||||
}
|
||||
private static double currentTPSLimit = 20;
|
||||
|
||||
public TPSSystem() {
|
||||
if (TPSFreezeUtils.isCanFreeze()) {
|
||||
@@ -338,26 +334,26 @@ public class TPSSystem implements Listener {
|
||||
} else if (TPSFreezeUtils.frozen()) {
|
||||
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: " + BauSystem.MESSAGE.parse("SCOREBOARD_TPS_FROZEN", p);
|
||||
} else {
|
||||
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: " + tpsColor() + tpsSystem.getTPS(TPSWatcher.TPSType.ONE_SECOND) + tpsLimit();
|
||||
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: " + tpsColor() + TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.ONE_SECOND) + tpsLimit();
|
||||
}
|
||||
}
|
||||
|
||||
private String tpsColor() {
|
||||
double tps = tpsSystem.getTPS(TPSWatcher.TPSType.ONE_SECOND);
|
||||
if (tps > tpsSystem.getCurrentTPSLimit() * 0.9) {
|
||||
double tps = TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.ONE_SECOND);
|
||||
if (tps > TPSSystem.getCurrentTPSLimit() * 0.9) {
|
||||
return "§a";
|
||||
}
|
||||
if (tps > tpsSystem.getCurrentTPSLimit() * 0.5) {
|
||||
if (tps > TPSSystem.getCurrentTPSLimit() * 0.5) {
|
||||
return "§e";
|
||||
}
|
||||
return "§c";
|
||||
}
|
||||
|
||||
private String tpsLimit() {
|
||||
if (tpsSystem.getCurrentTPSLimit() == 20) {
|
||||
if (TPSSystem.getCurrentTPSLimit() == 20) {
|
||||
return "";
|
||||
}
|
||||
return "§8/§7" + tpsSystem.getCurrentTPSLimit();
|
||||
return "§8/§7" + TPSSystem.getCurrentTPSLimit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,11 +102,14 @@ public class TraceRecorder implements Listener {
|
||||
*
|
||||
* @param region region to be recorded
|
||||
*/
|
||||
public void startRecording(Region region) {
|
||||
if (activeTraces.containsKey(region)) return;
|
||||
public Trace startRecording(Region region) {
|
||||
if (activeTraces.containsKey(region)) {
|
||||
return activeTraces.get(region).getTrace();
|
||||
}
|
||||
|
||||
TraceRecordingWrapper wrappedTrace = new TraceRecordingWrapper(region);
|
||||
activeTraces.put(region, wrappedTrace);
|
||||
return wrappedTrace.getTrace();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
package de.steamwar.bausystem.features.tracer.rendering;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.configplayer.Config;
|
||||
import de.steamwar.bausystem.features.tracer.TNTPoint;
|
||||
import de.steamwar.bausystem.features.tracer.Trace;
|
||||
import de.steamwar.bausystem.features.tracer.TraceManager;
|
||||
@@ -30,10 +31,13 @@ import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import yapion.hierarchy.types.YAPIONValue;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static de.steamwar.bausystem.features.util.TNTClickListener.TNT_CLICK_DETAILS;
|
||||
|
||||
/**
|
||||
* Wrapper for the rendering of a record bundle
|
||||
*/
|
||||
@@ -66,6 +70,7 @@ public class TraceEntity extends RFallingBlockEntity {
|
||||
* @param player the player the message should be printed for
|
||||
*/
|
||||
public void printIntoChat(Player player) {
|
||||
if (!Config.getInstance().get(player).getOrSetDefault(TNT_CLICK_DETAILS, new YAPIONValue<>(true)).asBoolean().orElse(true)) return;
|
||||
TNTPoint representative = records.get(0);
|
||||
|
||||
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_HEADER", player);
|
||||
|
||||
@@ -21,22 +21,46 @@ package de.steamwar.bausystem.features.util;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.Permission;
|
||||
import de.steamwar.bausystem.configplayer.Config;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.TNTPrimed;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import yapion.hierarchy.types.YAPIONObject;
|
||||
import yapion.hierarchy.types.YAPIONValue;
|
||||
|
||||
@Linked
|
||||
public class TNTClickListener implements Listener {
|
||||
public class TNTClickListener extends SWCommand implements Listener {
|
||||
|
||||
public static final String TNT_CLICK_DETAILS = "tnt_click_details";
|
||||
|
||||
public TNTClickListener() {
|
||||
super("tntdetails");
|
||||
}
|
||||
|
||||
@Register(description = "TNT_DETAILS_COMMAND")
|
||||
public void toggle(Player player) {
|
||||
YAPIONObject yapionObject = Config.getInstance().get(player);
|
||||
if (yapionObject.getOrSetDefault(TNT_CLICK_DETAILS, new YAPIONValue<>(true)).asBoolean().orElse(true)) {
|
||||
yapionObject.put(TNT_CLICK_DETAILS, false);
|
||||
BauSystem.MESSAGE.send("TNT_DETAILS_OFF", player);
|
||||
} else {
|
||||
yapionObject.put(TNT_CLICK_DETAILS, true);
|
||||
BauSystem.MESSAGE.send("TNT_DETAILS_ON", player);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
|
||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||
if (event.getHand() != EquipmentSlot.HAND) return;
|
||||
if (!Config.getInstance().get(event.getPlayer()).getOrSetDefault(TNT_CLICK_DETAILS, new YAPIONValue<>(true)).asBoolean().orElse(true)) return;
|
||||
|
||||
Entity entity = event.getRightClicked();
|
||||
if (event.getRightClicked() instanceof TNTPrimed) {
|
||||
|
||||
@@ -73,4 +73,8 @@ public class Point {
|
||||
public Location toLocation(Player player, double dx, double dy, double dz) {
|
||||
return new Location(player.getWorld(), x + dx, y + dy, z + dz, player.getLocation().getYaw(), player.getLocation().getPitch());
|
||||
}
|
||||
|
||||
public BlockVector3 toBlockVector3() {
|
||||
return BlockVector3.at(this.x, this.y, this.z);
|
||||
}
|
||||
}
|
||||
@@ -184,6 +184,7 @@ public class MWTeam {
|
||||
|
||||
public void leave(Player p) {
|
||||
if (!players.contains(p)) return;
|
||||
players.remove(p);
|
||||
|
||||
for (ItemStack stack : p.getInventory().getContents()) {
|
||||
if (stack == null) continue;
|
||||
@@ -198,7 +199,6 @@ public class MWTeam {
|
||||
if (players.isEmpty() && MissileWars.getFightState() == FightState.FIGHTING)
|
||||
MissileWars.end(WinReasons.NO_ENEMY, enemy());
|
||||
|
||||
players.remove(p);
|
||||
sbteam.removePlayer(p);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ public class BountifulWrapper21 extends BountifulWrapper9 {
|
||||
return (packet, x, y, z, pitch, yaw) -> {
|
||||
PositionMoveRotation pos = field.get(packet);
|
||||
|
||||
field.set(packet, new PositionMoveRotation(new Vec3D(x, y, z), pos == null ? new Vec3D(0, 0, 0) : pos.b(), yaw, pitch));
|
||||
field.set(packet, new PositionMoveRotation(new Vec3D(x, y, z), pos.b(), yaw, pitch));
|
||||
};
|
||||
} catch (IllegalArgumentException e) {
|
||||
return super.getPositionSetter(packetClass, fieldOffset);
|
||||
|
||||
@@ -177,30 +177,9 @@ public final class Reflection {
|
||||
}
|
||||
|
||||
public void set(Object target, Object value) {
|
||||
// This now works for Fields in records!
|
||||
try {
|
||||
long offset = Unsafe.getUnsafe().objectFieldOffset(f);
|
||||
Class<?> type = f.getType();
|
||||
if (type == int.class) {
|
||||
Unsafe.getUnsafe().putInt(target, offset, (Integer) value);
|
||||
} else if (type == float.class) {
|
||||
Unsafe.getUnsafe().putFloat(target, offset, (Float) value);
|
||||
} else if (type == double.class) {
|
||||
Unsafe.getUnsafe().putDouble(target, offset, (Double) value);
|
||||
} else if (type == boolean.class) {
|
||||
Unsafe.getUnsafe().putBoolean(target, offset, (Boolean) value);
|
||||
} else if (type == byte.class) {
|
||||
Unsafe.getUnsafe().putByte(target, offset, (Byte) value);
|
||||
} else if (type == char.class) {
|
||||
Unsafe.getUnsafe().putChar(target, offset, (Character) value);
|
||||
} else if (type == short.class) {
|
||||
Unsafe.getUnsafe().putShort(target, offset, (Short) value);
|
||||
} else if (type == long.class) {
|
||||
Unsafe.getUnsafe().putLong(target, offset, (Long) value);
|
||||
} else {
|
||||
Unsafe.getUnsafe().putReference(target, offset, value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
f.set(target, value);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalArgumentException("Cannot write field", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import de.steamwar.Reflection;
|
||||
import de.steamwar.command.*;
|
||||
import de.steamwar.core.authlib.AuthlibInjector;
|
||||
import de.steamwar.core.events.*;
|
||||
import de.steamwar.inventory.ui.test.TestInvCommand;
|
||||
import de.steamwar.message.Message;
|
||||
import de.steamwar.network.NetworkReceiver;
|
||||
import de.steamwar.network.handlers.ServerDataHandler;
|
||||
@@ -67,6 +68,7 @@ public class Core extends JavaPlugin{
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
new TestInvCommand();
|
||||
errorHandler = new ErrorHandler();
|
||||
crashDetector = new CrashDetector();
|
||||
|
||||
|
||||
@@ -396,26 +396,10 @@ public class REntity {
|
||||
public static final Class<?> teleportPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket");
|
||||
public static final Reflection.Field<Integer> teleportEntity = Reflection.getField(teleportPacket, int.class, 0);
|
||||
public static final BountifulWrapper.PositionSetter teleportPosition = BountifulWrapper.impl.getPositionSetter(teleportPacket, Core.getVersion() == 8 ? 1 : 0);
|
||||
public static final Class<?> relative;
|
||||
public static final Reflection.Field<Set> relatives;
|
||||
static {
|
||||
if (Core.getVersion() >= 21) {
|
||||
relative = Reflection.getClass("net.minecraft.world.entity.Relative");
|
||||
relatives = Reflection.getField(teleportPacket, Set.class, 0);
|
||||
} else {
|
||||
relative = null;
|
||||
relatives = null;
|
||||
}
|
||||
}
|
||||
private Object getTeleportPacket(){
|
||||
Object packet = Reflection.newInstance(teleportPacket);
|
||||
teleportEntity.set(packet, entityId);
|
||||
teleportPosition.set(packet, x, y, z, pitch, yaw);
|
||||
if (Core.getVersion() >= 21) {
|
||||
// https://mappings.dev/1.21.3/net/minecraft/world/entity/Relative.html
|
||||
Object[] constants = relative.getEnumConstants();
|
||||
relatives.set(packet, new HashSet<>(Arrays.asList(constants[0], constants[1], constants[2], constants[3], constants[4], constants[5])));
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.inventory.ui;
|
||||
|
||||
import de.steamwar.inventory.ui.util.UpdateStream;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public abstract class StatefulUIInventory<T> extends UIInventory implements UpdateStream.Subscriber<T> {
|
||||
|
||||
private T state;
|
||||
private final UpdateStream<T> stream;
|
||||
private UpdateStream.Unsubscriber unsubscriber;
|
||||
|
||||
protected abstract UIComponent render(T state);
|
||||
protected abstract void update(T state);
|
||||
|
||||
public StatefulUIInventory(UpdateStream<T> stateObservable, int playerSlots) {
|
||||
super(playerSlots);
|
||||
this.stream = stateObservable;
|
||||
}
|
||||
|
||||
public StatefulUIInventory(UpdateStream<T> stateObservable) {
|
||||
super();
|
||||
this.stream = stateObservable;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
unsubscriber.unsubscribe();
|
||||
this.unsubscriber = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UIComponent render() {
|
||||
return render(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(T current) {
|
||||
state = current;
|
||||
update(current);
|
||||
updateUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
void onClose() {
|
||||
if (viewers.isEmpty()) {
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViewer(Player... players) {
|
||||
if (viewers.isEmpty()) {
|
||||
unsubscriber = stream.subscribe(this);
|
||||
}
|
||||
|
||||
super.addViewer(players);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.inventory.ui;
|
||||
|
||||
import de.steamwar.inventory.ui.item.Enchanted;
|
||||
import de.steamwar.inventory.ui.item.OnClick;
|
||||
import de.steamwar.inventory.ui.layout.FixedSizeContainer;
|
||||
import de.steamwar.inventory.ui.util.*;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface UIComponent {
|
||||
ComponentRender render(RenderContext context);
|
||||
|
||||
default UIComponent onClick(Consumer<InventoryClickEvent> event) {
|
||||
return onClick(false, event);
|
||||
}
|
||||
|
||||
default UIComponent onClick(boolean allowDoubleClick, Consumer<InventoryClickEvent> event) {
|
||||
return new OnClick(this, allowDoubleClick, inventoryClickEvent -> {
|
||||
event.accept(inventoryClickEvent);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
default UIComponent onClickWithUpdate(Function<InventoryClickEvent, Boolean> event) {
|
||||
return onClickWithUpdate(false, event);
|
||||
}
|
||||
|
||||
default UIComponent onClickWithUpdate(boolean allowDoubleClick, Function<InventoryClickEvent, Boolean> event) {
|
||||
return new OnClick(this, allowDoubleClick, event);
|
||||
}
|
||||
|
||||
default UIComponent onClickNoUpdate(Consumer<InventoryClickEvent> event) {
|
||||
return onClickNoUpdate(false, event);
|
||||
}
|
||||
|
||||
default UIComponent onClickNoUpdate(boolean allowDoubleClick, Consumer<InventoryClickEvent> event) {
|
||||
return new OnClick(this, allowDoubleClick, inventoryClickEvent -> {
|
||||
event.accept(inventoryClickEvent);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
default UIComponent cancelOnClick() {
|
||||
return new OnClick(this, true, inventoryClickEvent -> false);
|
||||
}
|
||||
|
||||
default UIComponent enchanted() {
|
||||
return new Enchanted(this);
|
||||
}
|
||||
|
||||
default UIComponent enchanted(boolean enchanted) {
|
||||
if (enchanted)
|
||||
return enchanted();
|
||||
else
|
||||
return this;
|
||||
}
|
||||
|
||||
default UIComponent size(Size size) {
|
||||
return new FixedSizeContainer(size, this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.inventory.ui;
|
||||
|
||||
import de.steamwar.inventory.ui.util.ComponentRender;
|
||||
import de.steamwar.inventory.ui.util.RenderContext;
|
||||
|
||||
public abstract class UIFragment implements UIComponent {
|
||||
|
||||
abstract public UIComponent build(RenderContext context);
|
||||
|
||||
@Override
|
||||
public ComponentRender render(RenderContext context) {
|
||||
return build(context).render(context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* 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.inventory.ui;
|
||||
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.inventory.ui.util.ComponentRender;
|
||||
import de.steamwar.inventory.ui.util.RenderContext;
|
||||
import de.steamwar.inventory.ui.util.RenderItem;
|
||||
import de.steamwar.inventory.ui.util.Size;
|
||||
import de.steamwar.message.Message;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class UIInventory {
|
||||
protected final List<Player> viewers = new ArrayList<>();
|
||||
private final Map<Player, OpenPlayerInventory> callbacks = new HashMap<>();
|
||||
private final Map<Player, ItemStack[]> originalItems = new HashMap<>();
|
||||
|
||||
private UIInventory parent;
|
||||
private Player currentRender;
|
||||
private final int playerSlots;
|
||||
|
||||
private List<MemoHookMeta<?>> memoHooks = new ArrayList<>();
|
||||
private int buildHookCount = 0;
|
||||
|
||||
protected UIInventory() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
protected UIInventory(int playerSlots) {
|
||||
this.playerSlots = playerSlots;
|
||||
}
|
||||
|
||||
public abstract UIComponent render();
|
||||
public abstract Inventory createInventory(Player player);
|
||||
public abstract Message getMessages();
|
||||
|
||||
void onClose() { }
|
||||
|
||||
public <T> T useMemo(Supplier<T> supplier, List<Object> dependencies) {
|
||||
int currentHook = buildHookCount++;
|
||||
|
||||
if (currentHook >= memoHooks.size()) {
|
||||
T value = supplier.get();
|
||||
memoHooks.add(new MemoHookMeta<>(dependencies, value));
|
||||
return value;
|
||||
}
|
||||
|
||||
MemoHookMeta<T> hook = (MemoHookMeta<T>) memoHooks.get(currentHook);
|
||||
|
||||
if (!hook.getDependencies().equals(dependencies)) {
|
||||
hook.setDependencies(dependencies);
|
||||
T value = supplier.get();
|
||||
hook.setValue(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
return hook.getValue();
|
||||
}
|
||||
|
||||
public <T> T useMemo(Supplier<T> supplier) {
|
||||
return useMemo(supplier, Collections.emptyList());
|
||||
}
|
||||
|
||||
public void addViewer(Player... players) {
|
||||
viewers.addAll(Arrays.asList(players));
|
||||
|
||||
for (Player player : players) {
|
||||
openInventory(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void openInventory(Player player) {
|
||||
if (playerSlots > 0) {
|
||||
originalItems.put(player, player.getInventory().getContents());
|
||||
}
|
||||
Inventory inventory = createInventory(player);
|
||||
renderPlayer(player, inventory);
|
||||
InventoryView view = player.openInventory(inventory);
|
||||
Core.getInstance().getLogger().info("[UIINV] Opened " + view.getTitle() + " for " + player.getName());
|
||||
}
|
||||
|
||||
private void renderPlayer(Player player, Inventory inventory) {
|
||||
int width = Math.min(inventory.getSize(), 9);
|
||||
if (width < 9 && playerSlots > 0) {
|
||||
throw new IllegalArgumentException("Player Inventory is only supported in Chests");
|
||||
}
|
||||
|
||||
int inventoryHeight = Math.max(inventory.getSize() / 9, 1);
|
||||
int height = inventoryHeight + playerSlots;
|
||||
int invSize = inventoryHeight * width;
|
||||
|
||||
currentRender = player;
|
||||
buildHookCount = 0;
|
||||
ComponentRender render = render().render(new RenderContext(new Size(width, height), new Size(width, height), this));
|
||||
buildHookCount = -1;
|
||||
currentRender = null;
|
||||
|
||||
if (render.getSize().getWidth() > width || render.getSize().getHeight() > height) {
|
||||
throw new IllegalArgumentException("The UIComponent does not fit in the inventory");
|
||||
}
|
||||
|
||||
Message message = getMessages();
|
||||
|
||||
ItemStack[] itemStacks = new ItemStack[inventory.getSize()];
|
||||
ItemStack[] playerStacks = new ItemStack[playerSlots > 0 ? 4 * 9 : 0];
|
||||
|
||||
for (RenderItem item : render.getItems()) {
|
||||
int slot = item.getX() + item.getY() * 9;
|
||||
if (slot < invSize) {
|
||||
itemStacks[item.getX() + item.getY() * 9] = item.getItemStack().message(message).build(player);
|
||||
} else {
|
||||
playerStacks[(item.getX() + item.getY() * 9) - invSize] = item.getItemStack().message(message).build(player);
|
||||
}
|
||||
}
|
||||
|
||||
inventory.setContents(itemStacks);
|
||||
if (playerSlots > 0) {
|
||||
ItemStack[] lastRow = new ItemStack[9];
|
||||
System.arraycopy(playerStacks, playerStacks.length - 9, lastRow, 0, 9);
|
||||
System.arraycopy(playerStacks, 0, playerStacks, 9, playerStacks.length - 9);
|
||||
System.arraycopy(lastRow, 0, playerStacks, 0, 9);
|
||||
|
||||
// TODO: Update to Client-Side Only Update
|
||||
player.getInventory().setContents(playerStacks);
|
||||
}
|
||||
|
||||
Map<Integer, Function<InventoryClickEvent, Boolean>> clickEventMap = render.getItems().stream()
|
||||
.filter(item -> item.getClickEvent() != null)
|
||||
.collect(Collectors.toMap(renderItem -> renderItem.getX() + renderItem.getY() * 9, RenderItem::getClickEvent));
|
||||
|
||||
callbacks.computeIfAbsent(player, p -> new OpenPlayerInventory(p, clickEventMap).register()).setCallbacks(clickEventMap);
|
||||
}
|
||||
|
||||
protected void updateTitle(String title, Object... params) {
|
||||
if (currentRender != null) {
|
||||
currentRender.getOpenInventory().setTitle(getMessages().parse(title, currentRender, params));
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateUI() {
|
||||
viewers.forEach(player -> renderPlayer(player, player.getOpenInventory().getTopInventory()));
|
||||
}
|
||||
|
||||
protected void push(Player player, UIInventory inventory) {
|
||||
inventory.parent = this;
|
||||
inventory.addViewer(player);
|
||||
viewers.remove(player);
|
||||
}
|
||||
|
||||
protected void pop(Player player) {
|
||||
if(parent == null)
|
||||
return;
|
||||
|
||||
parent.addViewer(player);
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@Setter
|
||||
private class OpenPlayerInventory implements Listener {
|
||||
private final Player player;
|
||||
private Map<Integer, Function<InventoryClickEvent, Boolean>> callbacks;
|
||||
|
||||
OpenPlayerInventory register() {
|
||||
Core.getInstance().getServer().getPluginManager().registerEvents(this, Core.getInstance());
|
||||
return this;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClick(InventoryClickEvent e) {
|
||||
if (!player.equals(e.getWhoClicked()))
|
||||
return;
|
||||
|
||||
if (callbacks.containsKey(e.getRawSlot()) && callbacks.get(e.getRawSlot()) != null) {
|
||||
e.setCancelled(true);
|
||||
Core.getInstance().getLogger().info("[UIINV] " + e.getWhoClicked().getName() + " " + e.getClick().name() + " clicked " + e.getRawSlot() + " on " + (e.getCurrentItem() != null ? e.getCurrentItem().getItemMeta().getDisplayName() : "[EMPTY]") + " in " + e.getView().getTitle());
|
||||
if (callbacks.get(e.getRawSlot()).apply(e)) {
|
||||
updateUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClose(InventoryCloseEvent e){
|
||||
if(!player.equals(e.getPlayer()))
|
||||
return;
|
||||
|
||||
InventoryClickEvent.getHandlerList().unregister(this);
|
||||
InventoryCloseEvent.getHandlerList().unregister(this);
|
||||
Core.getInstance().getLogger().info("[UIINV] " + player.getName() + " closed " + e.getView().getTitle());
|
||||
if(callbacks.containsKey(-1))
|
||||
callbacks.get(-1).apply(null);
|
||||
|
||||
viewers.remove(player);
|
||||
UIInventory.this.callbacks.remove(player);
|
||||
if (playerSlots > 0) {
|
||||
player.getInventory().setContents(originalItems.remove(player));
|
||||
}
|
||||
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
private class MemoHookMeta<T> {
|
||||
private List<Object> dependencies;
|
||||
private T value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.inventory.ui.fragments;
|
||||
|
||||
import de.steamwar.inventory.ui.UIComponent;
|
||||
import de.steamwar.inventory.ui.UIFragment;
|
||||
import de.steamwar.inventory.ui.item.ItemBuilder;
|
||||
import de.steamwar.inventory.ui.item.UIItem;
|
||||
import de.steamwar.inventory.ui.layout.Row;
|
||||
import de.steamwar.inventory.ui.util.RenderContext;
|
||||
import de.steamwar.inventory.ui.util.Size;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.Material;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ActionBar extends UIFragment {
|
||||
private static final UIComponent DEFAULT_FILLER = new UIItem(ItemBuilder.of(Material.GRAY_STAINED_GLASS_PANE).displayName("§e")).cancelOnClick();
|
||||
|
||||
private final Map<Integer, UIComponent> actionBar;
|
||||
private UIComponent filler = DEFAULT_FILLER;
|
||||
|
||||
public ActionBar(Map<Integer, UIComponent> actionBar) {
|
||||
this.actionBar = actionBar;
|
||||
}
|
||||
|
||||
public ActionBar filler(UIComponent filler) {
|
||||
this.filler = filler;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UIComponent build(RenderContext context) {
|
||||
UIComponent[] components = context.useMemo(() -> {
|
||||
UIComponent[] cmp = new UIComponent[context.getContainerSize().getWidth()];
|
||||
for (int i = 0; i < cmp.length; i++) {
|
||||
cmp[i] = actionBar.getOrDefault(i, filler);
|
||||
}
|
||||
|
||||
return cmp;
|
||||
}, Arrays.asList(actionBar));
|
||||
|
||||
return new Row(Arrays.asList(components)).size(new Size(context.getContainerSize().getWidth(), 1));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.inventory.ui.fragments;
|
||||
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.inventory.ui.UIComponent;
|
||||
import de.steamwar.inventory.ui.UIFragment;
|
||||
import de.steamwar.inventory.ui.item.ItemBuilder;
|
||||
import de.steamwar.inventory.ui.item.UIItem;
|
||||
import de.steamwar.inventory.ui.layout.Column;
|
||||
import de.steamwar.inventory.ui.layout.FixedSizeContainer;
|
||||
import de.steamwar.inventory.ui.layout.Row;
|
||||
import de.steamwar.inventory.ui.util.RenderContext;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.DyeColor;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Setter
|
||||
public class HorizontalScrollLayout extends UIFragment {
|
||||
private List<UIComponent> data;
|
||||
private int scroll = 0;
|
||||
private final Map<Integer, UIComponent> actionBar = new HashMap<>();
|
||||
|
||||
public HorizontalScrollLayout(List<UIComponent> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
private int maxScroll() {
|
||||
return Math.max(0, Math.min(scroll, data.size() - 9 + 1));
|
||||
}
|
||||
|
||||
public HorizontalScrollLayout actionBar(Map<Integer, UIComponent> actionBar) {
|
||||
this.actionBar.clear();
|
||||
this.actionBar.putAll(actionBar);
|
||||
return this;
|
||||
}
|
||||
|
||||
public HorizontalScrollLayout data(List<UIComponent> data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UIComponent build(RenderContext context) {
|
||||
scroll = maxScroll();
|
||||
boolean hasPrev = scroll > 0;
|
||||
boolean hasNext = data.size() - scroll > 9;
|
||||
|
||||
Map<Integer, UIComponent> actionBar = context.useMemo(() -> {
|
||||
Map<Integer, UIComponent> content = new HashMap<>(this.actionBar);
|
||||
|
||||
content.put(0, new UIItem(ItemBuilder.color(hasPrev ? DyeColor.LIME : DyeColor.GRAY).message(Core.MESSAGE).translateName(hasPrev ? "SWLISINV_PREVIOUS_PAGE_ACTIVE" : "SWLISINV_PREVIOUS_PAGE_INACTIVE")).onClickWithUpdate(inventoryClickEvent -> {
|
||||
if (scroll > 0) {
|
||||
scroll = Math.max(0, scroll - 9);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
content.put(8, new UIItem(ItemBuilder.color(hasNext ? DyeColor.LIME : DyeColor.GRAY).message(Core.MESSAGE).translateName(hasNext ? "SWLISINV_NEXT_PAGE_ACTIVE" : "SWLISINV_NEXT_PAGE_INACTIVE")).onClickWithUpdate(inventoryClickEvent -> {
|
||||
if (hasNext) {
|
||||
scroll = Math.min(scroll + 9, data.size() - 9);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
|
||||
return content;
|
||||
}, Arrays.asList(hasPrev, hasNext));
|
||||
|
||||
return new Column(
|
||||
new FixedSizeContainer(context.getContainerSize().shrink(0, 1),
|
||||
new Row(data.subList(scroll, Math.min(data.size(), scroll + 9)))
|
||||
),
|
||||
new ActionBar(actionBar)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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.inventory.ui.fragments;
|
||||
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.inventory.ui.UIComponent;
|
||||
import de.steamwar.inventory.ui.UIFragment;
|
||||
import de.steamwar.inventory.ui.item.ItemBuilder;
|
||||
import de.steamwar.inventory.ui.item.UIItem;
|
||||
import de.steamwar.inventory.ui.layout.Column;
|
||||
import de.steamwar.inventory.ui.layout.FixedSizeContainer;
|
||||
import de.steamwar.inventory.ui.layout.Grid;
|
||||
import de.steamwar.inventory.ui.util.RenderContext;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class PageLayout<T> extends UIFragment {
|
||||
|
||||
private final List<UIListEntry<T>> items;
|
||||
private final UIListCallback<T> callback;
|
||||
private int page = 0;
|
||||
private Consumer<Integer> onPageChange = null;
|
||||
private Map<Integer, UIItem> itemsOnBar = Collections.emptyMap();
|
||||
|
||||
public PageLayout(List<UIListEntry<T>> items, UIListCallback<T> callback) {
|
||||
System.out.println(items.size());
|
||||
this.items = items;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UIComponent build(RenderContext context) {
|
||||
|
||||
int itemsOnPage = context.getContainerSize().getWidth() * (context.getContainerSize().getHeight() - 1);
|
||||
|
||||
List<UIComponent> uiItems = context.useMemo(() -> {
|
||||
int i = page * itemsOnPage;
|
||||
|
||||
int ipageLimit = items.size() - page * itemsOnPage;
|
||||
if (ipageLimit > itemsOnPage) {
|
||||
ipageLimit = itemsOnPage;
|
||||
}
|
||||
|
||||
List<UIComponent> pageItems = new ArrayList<>();
|
||||
for (int ipage = 0; ipage < ipageLimit; ipage++) {
|
||||
UIListEntry<T> e = items.get(i);
|
||||
|
||||
pageItems.add(new UIItem(e.item).onClickNoUpdate(inventoryClickEvent -> callback.clicked(inventoryClickEvent.getClick(), e.object)));
|
||||
i++;
|
||||
}
|
||||
|
||||
return pageItems;
|
||||
}, Arrays.asList(page, items.size(), itemsOnPage));
|
||||
|
||||
Map<Integer, UIComponent> uiBar = context.useMemo(() -> {
|
||||
Map<Integer, UIComponent> content = new HashMap<>(itemsOnBar);
|
||||
|
||||
if (page != 0) {
|
||||
content.put(0, new UIItem(ItemBuilder.color(DyeColor.LIME).message(Core.MESSAGE).translateName("SWLISINV_PREVIOUS_PAGE_ACTIVE")).onClick(inventoryClickEvent -> page--));
|
||||
} else {
|
||||
content.put(0, new UIItem(ItemBuilder.color(DyeColor.GRAY).message(Core.MESSAGE).translateName("SWLISINV_PREVIOUS_PAGE_INACTIVE")).cancelOnClick());
|
||||
}
|
||||
if (page < items.size() / itemsOnPage - (items.size() % itemsOnPage == 0 ? 1 : 0)) {
|
||||
content.put(8, new UIItem(ItemBuilder.color(DyeColor.LIME).message(Core.MESSAGE).translateName("SWLISINV_NEXT_PAGE_ACTIVE")).onClick(inventoryClickEvent -> page++));
|
||||
} else {
|
||||
content.put(8, new UIItem(ItemBuilder.color(DyeColor.GRAY).message(Core.MESSAGE).translateName("SWLISINV_NEXT_PAGE_INACTIVE")).cancelOnClick());
|
||||
}
|
||||
|
||||
return content;
|
||||
}, Arrays.asList(page, items.size(), itemsOnPage));
|
||||
|
||||
return new Column(
|
||||
new FixedSizeContainer(context.getContainerSize().shrink(0, 1),
|
||||
new Grid(uiItems)),
|
||||
new ActionBar(uiBar)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public interface UIListCallback<T>{
|
||||
void clicked(ClickType click, T element);
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class UIListEntry<T>{
|
||||
final ItemBuilder item;
|
||||
final T object;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.inventory.ui.item;
|
||||
|
||||
import de.steamwar.inventory.ui.UIComponent;
|
||||
import de.steamwar.inventory.ui.util.ComponentRender;
|
||||
import de.steamwar.inventory.ui.util.RenderContext;
|
||||
import de.steamwar.inventory.ui.util.RenderItem;
|
||||
|
||||
public class Enchanted implements UIComponent {
|
||||
private final UIComponent children;
|
||||
|
||||
public Enchanted(UIComponent children) {
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentRender render(RenderContext context) {
|
||||
ComponentRender render = children.render(context);
|
||||
|
||||
for (RenderItem item : render.getItems()) {
|
||||
item.getItemStack().enchanted();
|
||||
}
|
||||
|
||||
return render;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* 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.inventory.ui.item;
|
||||
|
||||
import de.steamwar.core.FlatteningWrapper;
|
||||
import de.steamwar.core.TrickyTrialsWrapper;
|
||||
import de.steamwar.inventory.SWItem;
|
||||
import de.steamwar.message.Message;
|
||||
import de.steamwar.message.SubMessage;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ItemBuilder {
|
||||
private static final Map<DyeColor, Integer> DYE_COLOR_INTEGER_MAP = new EnumMap<>(DyeColor.class);
|
||||
|
||||
static {
|
||||
DYE_COLOR_INTEGER_MAP.put(DyeColor.BLACK, 16);
|
||||
DYE_COLOR_INTEGER_MAP.put(DyeColor.RED, 1);
|
||||
DYE_COLOR_INTEGER_MAP.put(DyeColor.GREEN, 2);
|
||||
DYE_COLOR_INTEGER_MAP.put(DyeColor.BROWN, 3);
|
||||
DYE_COLOR_INTEGER_MAP.put(DyeColor.BLUE, 4);
|
||||
DYE_COLOR_INTEGER_MAP.put(DyeColor.PURPLE, 5);
|
||||
DYE_COLOR_INTEGER_MAP.put(DyeColor.CYAN, 6);
|
||||
DYE_COLOR_INTEGER_MAP.put(DyeColor.LIGHT_GRAY, 7);
|
||||
DYE_COLOR_INTEGER_MAP.put(DyeColor.GRAY, 8);
|
||||
DYE_COLOR_INTEGER_MAP.put(DyeColor.PINK, 9);
|
||||
DYE_COLOR_INTEGER_MAP.put(DyeColor.LIME, 10);
|
||||
DYE_COLOR_INTEGER_MAP.put(DyeColor.YELLOW, 11);
|
||||
DYE_COLOR_INTEGER_MAP.put(DyeColor.LIGHT_BLUE, 12);
|
||||
DYE_COLOR_INTEGER_MAP.put(DyeColor.MAGENTA, 13);
|
||||
DYE_COLOR_INTEGER_MAP.put(DyeColor.ORANGE, 14);
|
||||
DYE_COLOR_INTEGER_MAP.put(DyeColor.WHITE, 15);
|
||||
}
|
||||
|
||||
private final ItemStack itemStack;
|
||||
private final ItemMeta itemMeta;
|
||||
private Message message = null;
|
||||
private SubMessage translateName = null;
|
||||
private List<SubMessage> translateLore = null;
|
||||
|
||||
private ItemBuilder(Material material) {
|
||||
this(new ItemStack(material));
|
||||
}
|
||||
private ItemBuilder(ItemStack item) {
|
||||
this.itemStack = item;
|
||||
this.itemMeta = itemStack.getItemMeta();
|
||||
}
|
||||
|
||||
public static ItemBuilder of(Material material) {
|
||||
return new ItemBuilder(material);
|
||||
}
|
||||
|
||||
public static ItemBuilder of(ItemStack itemStack) {
|
||||
return new ItemBuilder(itemStack.getType()).amount(itemStack.getAmount());
|
||||
}
|
||||
|
||||
private static ItemBuilder of(Material material, Byte meta) {
|
||||
ItemStack itemStack;
|
||||
try {
|
||||
itemStack = new ItemStack(material, 1, (short)0, meta);
|
||||
} catch (IllegalArgumentException e) {
|
||||
itemStack = new ItemStack(material, 1);
|
||||
}
|
||||
|
||||
return new ItemBuilder(itemStack);
|
||||
}
|
||||
|
||||
public static ItemBuilder color(DyeColor color) {
|
||||
return ItemBuilder.of(SWItem.getDye(DYE_COLOR_INTEGER_MAP.get(color)), DYE_COLOR_INTEGER_MAP.get(color).byteValue());
|
||||
}
|
||||
|
||||
public static ItemBuilder skull(OfflinePlayer player) {
|
||||
return skull(player.getName());
|
||||
}
|
||||
|
||||
public static ItemBuilder skull(String name) {
|
||||
return ItemBuilder.of(FlatteningWrapper.impl.setSkullOwner(name));
|
||||
}
|
||||
|
||||
public ItemBuilder message(Message message) {
|
||||
if (this.message == null) {
|
||||
this.message = message;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStack build(Player player) {
|
||||
if (message != null) {
|
||||
if (translateName != null) {
|
||||
itemMeta.setDisplayName(message.parse(translateName.getMessage(), player, translateName.getParams()));
|
||||
}
|
||||
if (translateLore != null) {
|
||||
itemMeta.setLore(translateLore.stream().map(subMessage -> message.parse(subMessage.getMessage(), player, subMessage.getParams())).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
itemStack.setItemMeta(itemMeta);
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
public ItemBuilder amount(int amount) {
|
||||
itemStack.setAmount(amount);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemBuilder displayName(String name) {
|
||||
itemMeta.setDisplayName(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemBuilder lore(String... lore) {
|
||||
if (itemMeta.hasLore()) {
|
||||
List<String> loreList = itemMeta.getLore();
|
||||
loreList.addAll(Arrays.asList(lore));
|
||||
itemMeta.setLore(loreList);
|
||||
} else {
|
||||
itemMeta.setLore(Arrays.asList(lore));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemBuilder translateName(String name, Object... params) {
|
||||
this.translateName = new SubMessage(name, params);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemBuilder addTranslateLore(SubMessage... lore) {
|
||||
if (this.translateLore == null) {
|
||||
this.translateLore = Arrays.asList(lore);
|
||||
} else {
|
||||
this.translateLore.addAll(Arrays.asList(lore));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemBuilder enchanted() {
|
||||
itemMeta.addEnchant(TrickyTrialsWrapper.impl.getUnbreakingEnchantment(), 10, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemBuilder enchanted(boolean enchanted) {
|
||||
if(enchanted) {
|
||||
return enchanted();
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public ItemBuilder hideFlags() {
|
||||
for (ItemFlag flag : EnumSet.allOf(ItemFlag.class)) {
|
||||
itemMeta.addItemFlags(flag);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemBuilder customModel(int modelData) {
|
||||
itemMeta.setCustomModelData(modelData);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ItemBuilder that = (ItemBuilder) o;
|
||||
return Objects.equals(itemStack, that.itemStack) && Objects.equals(itemMeta, that.itemMeta) && Objects.equals(message, that.message) && Objects.equals(translateName, that.translateName) && Objects.equals(translateLore, that.translateLore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ItemBuilder{" +
|
||||
"itemStack=" + itemStack +
|
||||
", itemMeta=" + itemMeta +
|
||||
", message=" + message +
|
||||
", translateName=" + translateName +
|
||||
", translateLore=" + translateLore +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.inventory.ui.item;
|
||||
|
||||
import de.steamwar.inventory.ui.UIComponent;
|
||||
import de.steamwar.inventory.ui.util.ComponentRender;
|
||||
import de.steamwar.inventory.ui.util.RenderContext;
|
||||
import de.steamwar.inventory.ui.util.RenderItem;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class OnClick implements UIComponent {
|
||||
private final UIComponent children;
|
||||
private final boolean allowDoubleClick;
|
||||
private final Function<InventoryClickEvent, Boolean> event;
|
||||
|
||||
public OnClick(UIComponent children, boolean allowDoubleClick, Function<InventoryClickEvent, Boolean> event) {
|
||||
this.children = children;
|
||||
this.allowDoubleClick = allowDoubleClick;
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentRender render(RenderContext context) {
|
||||
ComponentRender render = children.render(context);
|
||||
|
||||
for (RenderItem item : render.getItems()) {
|
||||
item.setClickEvent(ev -> {
|
||||
if (ev.getClick() != ClickType.DOUBLE_CLICK || allowDoubleClick) {
|
||||
return event.apply(ev);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
return render;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OnClick{" +
|
||||
"children=" + children +
|
||||
", allowDoubleClick=" + allowDoubleClick +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
OnClick onClick = (OnClick) o;
|
||||
return allowDoubleClick == onClick.allowDoubleClick && children.equals(onClick.children);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.inventory.ui.item;
|
||||
|
||||
import de.steamwar.inventory.ui.UIComponent;
|
||||
import de.steamwar.inventory.ui.util.ComponentRender;
|
||||
import de.steamwar.inventory.ui.util.RenderContext;
|
||||
import de.steamwar.inventory.ui.util.Size;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Space implements UIComponent {
|
||||
@Override
|
||||
public ComponentRender render(RenderContext context) {
|
||||
return new ComponentRender(
|
||||
new ArrayList<>(),
|
||||
new Size(1, 1)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof Space;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.inventory.ui.item;
|
||||
|
||||
import de.steamwar.inventory.ui.UIComponent;
|
||||
import de.steamwar.inventory.ui.util.*;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
public class UIItem implements UIComponent {
|
||||
|
||||
private final ItemBuilder itemStack;
|
||||
|
||||
public UIItem(ItemStack itemStack) {
|
||||
this(ItemBuilder.of(itemStack));
|
||||
}
|
||||
|
||||
public UIItem(ItemBuilder itemStack) {
|
||||
this.itemStack = itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentRender render(RenderContext context) {
|
||||
return new ComponentRender(
|
||||
Arrays.asList(new RenderItem(0, 0, itemStack, null)),
|
||||
new Size(1, 1)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UIItem{" +
|
||||
"itemStack=" + itemStack +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
UIItem uiItem = (UIItem) o;
|
||||
return Objects.equals(itemStack, uiItem.itemStack);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.inventory.ui.layout;
|
||||
|
||||
public enum Alignment {
|
||||
START,
|
||||
CENTER,
|
||||
END,
|
||||
BETWEEN
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.inventory.ui.layout;
|
||||
|
||||
import de.steamwar.inventory.ui.UIComponent;
|
||||
import de.steamwar.inventory.ui.util.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Column implements UIComponent {
|
||||
|
||||
private final List<UIComponent> components;
|
||||
|
||||
private Alignment alignment;
|
||||
private boolean shrinkWrap = false;
|
||||
|
||||
public Column(UIComponent... components) {
|
||||
this(Arrays.asList(components));
|
||||
}
|
||||
|
||||
public Column(List<UIComponent> components) {
|
||||
this.components = components;
|
||||
}
|
||||
|
||||
public Column centered() {
|
||||
this.alignment = Alignment.CENTER;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Column setShrinkWrap(boolean shrinkWrap) {
|
||||
this.shrinkWrap = shrinkWrap;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentRender render(RenderContext context) {
|
||||
List<RenderItem> renderItems = new ArrayList<>();
|
||||
|
||||
int height = 0;
|
||||
int maxWidth = 0;
|
||||
|
||||
for (UIComponent component : components) {
|
||||
ComponentRender render = component.render(context.withContainerSize(context.getContainerSize().withHeight(context.getContainerSize().getHeight() - height)));
|
||||
for(RenderItem item : render.getItems()){
|
||||
renderItems.add(item.shift(0, height));
|
||||
}
|
||||
maxWidth = Math.max(maxWidth, render.getSize().getWidth());
|
||||
height += render.getSize().getHeight();
|
||||
}
|
||||
|
||||
if (alignment == Alignment.CENTER) {
|
||||
int shiftAmount = (context.getContainerSize().getHeight() - height) / 2;
|
||||
for (RenderItem item : renderItems) {
|
||||
item.shift(0, shiftAmount);
|
||||
}
|
||||
} else if (alignment == Alignment.BETWEEN) {
|
||||
int shiftAmount = (context.getContainerSize().getHeight() - height) / (components.size() - 1);
|
||||
for (int i = 0; i < components.size() - 1; i++) {
|
||||
RenderItem item = renderItems.get(i);
|
||||
item.shift(0, shiftAmount * i);
|
||||
}
|
||||
} else if (alignment == Alignment.END) {
|
||||
int shiftAmount = (context.getContainerSize().getHeight() - height);
|
||||
for (RenderItem item : renderItems) {
|
||||
item.shift(0, shiftAmount);
|
||||
}
|
||||
}
|
||||
|
||||
return new ComponentRender(
|
||||
renderItems,
|
||||
new Size(maxWidth, shrinkWrap ? height : context.getContainerSize().getHeight())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.inventory.ui.layout;
|
||||
|
||||
import de.steamwar.inventory.ui.UIComponent;
|
||||
import de.steamwar.inventory.ui.util.ComponentRender;
|
||||
import de.steamwar.inventory.ui.util.RenderContext;
|
||||
import de.steamwar.inventory.ui.util.Size;
|
||||
|
||||
public class FixedSizeContainer implements UIComponent {
|
||||
private final UIComponent children;
|
||||
private final Size size;
|
||||
|
||||
public FixedSizeContainer(Size size, UIComponent children) {
|
||||
this.children = children;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentRender render(RenderContext context) {
|
||||
return children.render(context.withContainerSize(size)).withSize(size);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.inventory.ui.layout;
|
||||
|
||||
import de.steamwar.inventory.ui.UIComponent;
|
||||
import de.steamwar.inventory.ui.util.ComponentRender;
|
||||
import de.steamwar.inventory.ui.util.RenderContext;
|
||||
import de.steamwar.inventory.ui.util.RenderItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Grid implements UIComponent {
|
||||
private final List<UIComponent> children;
|
||||
|
||||
public Grid(UIComponent... children) {
|
||||
this(Arrays.asList(children));
|
||||
}
|
||||
|
||||
public Grid(List<UIComponent> children) {
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentRender render(RenderContext context) {
|
||||
List<RenderItem> renderItems = new ArrayList<>();
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int currentRowMaxHeight = 0;
|
||||
|
||||
for (UIComponent child : children) {
|
||||
ComponentRender render = child.render(context.withContainerSize(
|
||||
context.getContainerSize()
|
||||
.withWidth(context.getContainerSize().getWidth() - x)
|
||||
.withHeight(context.getContainerSize().getHeight() - y)));
|
||||
currentRowMaxHeight = Math.max(currentRowMaxHeight, render.getSize().getHeight());
|
||||
for (RenderItem item : render.getItems()) {
|
||||
renderItems.add(item.shift(x, y));
|
||||
}
|
||||
x += render.getSize().getWidth();
|
||||
if(x >= context.getContainerSize().getWidth()){
|
||||
x = 0;
|
||||
y += currentRowMaxHeight;
|
||||
currentRowMaxHeight = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return new ComponentRender(renderItems, context.getContainerSize());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.inventory.ui.layout;
|
||||
|
||||
import de.steamwar.inventory.ui.UIComponent;
|
||||
import de.steamwar.inventory.ui.util.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Row implements UIComponent {
|
||||
|
||||
private final List<UIComponent> components;
|
||||
|
||||
private Alignment alignment;
|
||||
private boolean shrinkWrap = false;
|
||||
|
||||
public Row(UIComponent... components) {
|
||||
this(Arrays.asList(components));
|
||||
}
|
||||
|
||||
public Row(List<UIComponent> components) {
|
||||
this.components = components;
|
||||
}
|
||||
|
||||
public Row centered() {
|
||||
this.alignment = Alignment.CENTER;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Row alignment(Alignment alignment) {
|
||||
this.alignment = alignment;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Row setShrinkWrap(boolean shrinkWrap) {
|
||||
this.shrinkWrap = shrinkWrap;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentRender render(RenderContext context) {
|
||||
List<RenderItem> renderItems = new ArrayList<>();
|
||||
|
||||
int width = 0;
|
||||
int maxHeight = 0;
|
||||
|
||||
for (UIComponent component : components) {
|
||||
ComponentRender render = component.render(context.withContainerSize(context.getContainerSize().withWidth(context.getContainerSize().getWidth() - width)));
|
||||
for(RenderItem item : render.getItems()){
|
||||
renderItems.add(item.shift(width, 0));
|
||||
}
|
||||
maxHeight = Math.max(maxHeight, render.getSize().getHeight());
|
||||
width += render.getSize().getWidth();
|
||||
}
|
||||
|
||||
if (alignment == Alignment.CENTER) {
|
||||
int shiftAmount = (context.getContainerSize().getWidth() - width) / 2;
|
||||
for (RenderItem item : renderItems) {
|
||||
item.shift(shiftAmount, 0);
|
||||
}
|
||||
} else if (alignment == Alignment.BETWEEN) {
|
||||
int shiftAmount = (context.getContainerSize().getWidth() - width) / (components.size() - 1);
|
||||
for (int i = 0; i < components.size() - 1; i++) {
|
||||
RenderItem item = renderItems.get(i);
|
||||
item.shift(shiftAmount * i, 0);
|
||||
}
|
||||
} else if (alignment == Alignment.END) {
|
||||
int shiftAmount = (context.getContainerSize().getWidth() - width);
|
||||
for (RenderItem item : renderItems) {
|
||||
item.shift(shiftAmount, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return new ComponentRender(
|
||||
renderItems,
|
||||
new Size(shrinkWrap ? width : context.getContainerSize().getWidth(), maxHeight)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.inventory.ui.test;
|
||||
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.inventory.ui.util.UpdateStream;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TestInvCommand extends SWCommand {
|
||||
|
||||
public static final UpdateStream<List<Integer>> STREAM = new UpdateStream<>(new ArrayList<>());
|
||||
|
||||
public TestInvCommand() {
|
||||
super("testinv");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void run(Player player) {
|
||||
new TestInventory(STREAM).addViewer(player);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.inventory.ui.test;
|
||||
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.inventory.ui.StatefulUIInventory;
|
||||
import de.steamwar.inventory.ui.UIComponent;
|
||||
import de.steamwar.inventory.ui.fragments.HorizontalScrollLayout;
|
||||
import de.steamwar.inventory.ui.item.ItemBuilder;
|
||||
import de.steamwar.inventory.ui.item.UIItem;
|
||||
import de.steamwar.inventory.ui.util.UpdateStream;
|
||||
import de.steamwar.message.Message;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static de.steamwar.inventory.ui.test.TestInvCommand.STREAM;
|
||||
|
||||
public class TestInventory extends StatefulUIInventory<List<Integer>> {
|
||||
|
||||
private HorizontalScrollLayout scrollLayout;
|
||||
private static int counter = 1;
|
||||
|
||||
public TestInventory(UpdateStream<List<Integer>> stateObservable) {
|
||||
super(stateObservable);
|
||||
scrollLayout = new HorizontalScrollLayout(new ArrayList<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UIComponent render(List<Integer> state) {
|
||||
return scrollLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void update(List<Integer> state) {
|
||||
System.out.println("Update");
|
||||
List<UIComponent> items = state.stream().map(integer -> new UIItem(ItemBuilder.of(Material.ACACIA_PLANKS).displayName(String.valueOf(integer))).onClickNoUpdate(inventoryClickEvent -> STREAM.update(current -> {
|
||||
current.remove(integer);
|
||||
return current;
|
||||
}))).collect(Collectors.toList());
|
||||
items.add(new UIItem(ItemBuilder.of(Material.BUCKET).displayName("Add")).onClickNoUpdate(inventoryClickEvent -> STREAM.update(current -> {
|
||||
current.add(counter++);
|
||||
return current;
|
||||
})));
|
||||
scrollLayout = scrollLayout.data(items);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory createInventory(Player player) {
|
||||
return Bukkit.createInventory(null, 9 * 6, "Test Inventory");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message getMessages() {
|
||||
return Core.MESSAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.inventory.ui.util;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.With;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@With
|
||||
public class ComponentRender {
|
||||
private final List<RenderItem> items;
|
||||
private final Size size;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.inventory.ui.util;
|
||||
|
||||
import de.steamwar.inventory.ui.UIInventory;
|
||||
import lombok.Data;
|
||||
import lombok.With;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Data
|
||||
@With
|
||||
public class RenderContext {
|
||||
private final Size inventorySize;
|
||||
private final Size containerSize;
|
||||
private final UIInventory inventory;
|
||||
|
||||
public <T> T useMemo(Supplier<T> supplier, List<Object> dependencies) {
|
||||
return inventory.useMemo(supplier, dependencies);
|
||||
}
|
||||
|
||||
public <T> T useMemo(Supplier<T> supplier) {
|
||||
return inventory.useMemo(supplier);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.inventory.ui.util;
|
||||
|
||||
import de.steamwar.inventory.ui.item.ItemBuilder;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.With;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
@Data
|
||||
@With
|
||||
@AllArgsConstructor
|
||||
public class RenderItem {
|
||||
private int x;
|
||||
private int y;
|
||||
private ItemBuilder itemStack;
|
||||
private Function<InventoryClickEvent, Boolean> clickEvent;
|
||||
|
||||
public RenderItem shift(int deltaX, int deltaY) {
|
||||
return withX(x + deltaX).withY(y + deltaY);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.inventory.ui.util;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.With;
|
||||
|
||||
@Data
|
||||
@With
|
||||
public class Size {
|
||||
private final int width;
|
||||
private final int height;
|
||||
|
||||
public Size shrink(int width, int height) {
|
||||
return new Size(this.width - width, this.height - height);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.inventory.ui.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class UpdateStream<T> {
|
||||
|
||||
private T current;
|
||||
|
||||
private final List<Subscriber<T>> subscribers = new ArrayList<>();
|
||||
|
||||
public UpdateStream(T current) {
|
||||
this.current = current;
|
||||
}
|
||||
|
||||
public Unsubscriber subscribe(Subscriber<T> subscriber) {
|
||||
subscribers.add(subscriber);
|
||||
subscriber.onUpdate(current);
|
||||
return () -> subscribers.remove(subscriber);
|
||||
}
|
||||
|
||||
public T get() {
|
||||
return current;
|
||||
}
|
||||
|
||||
public void emit(T newCurrent) {
|
||||
current = newCurrent;
|
||||
subscribers.forEach(subscriber -> subscriber.onUpdate(newCurrent));
|
||||
}
|
||||
|
||||
public void update(Updater<T> updater) {
|
||||
current = updater.update(current);
|
||||
subscribers.forEach(subscriber -> subscriber.onUpdate(current));
|
||||
}
|
||||
|
||||
public interface Subscriber<T> {
|
||||
void onUpdate(T current);
|
||||
}
|
||||
|
||||
public interface Unsubscriber {
|
||||
void unsubscribe();
|
||||
}
|
||||
|
||||
public interface Updater<T> {
|
||||
T update(T current);
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,8 @@ import org.bukkit.event.player.PlayerAttemptPickupItemEvent
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent
|
||||
import org.bukkit.event.player.PlayerJoinEvent
|
||||
import org.bukkit.event.player.PlayerMoveEvent
|
||||
import org.bukkit.event.player.*
|
||||
import org.bukkit.persistence.PersistentDataType
|
||||
|
||||
object IngameListener : Listener {
|
||||
|
||||
@@ -75,9 +77,9 @@ object IngameListener : Listener {
|
||||
|
||||
@EventHandler
|
||||
fun onPickupCoins(e: PlayerAttemptPickupItemEvent) {
|
||||
if (e.item.itemStack.isSimilar(DealerInventory.coins)) {
|
||||
TNTLeagueGame.getTeam(e.player)?.coins =
|
||||
e.item.itemStack.amount + (TNTLeagueGame.getTeam(e.player)?.coins ?: 0)
|
||||
if (e.item.itemStack.persistentDataContainer.has(DealerInventory.coinKey)) {
|
||||
val numberOfCoins = e.item.itemStack.persistentDataContainer[DealerInventory.coinKey, PersistentDataType.INTEGER] ?: 0
|
||||
TNTLeagueGame.getTeam(e.player)?.coins = (e.item.itemStack.amount * numberOfCoins) + (TNTLeagueGame.getTeam(e.player)?.coins ?: 0)
|
||||
|
||||
e.item.itemStack.amount = 0
|
||||
e.isCancelled = true
|
||||
|
||||
@@ -24,8 +24,6 @@ import de.steamwar.message.SubMessage
|
||||
import de.steamwar.network.NetworkSender
|
||||
import de.steamwar.network.packets.common.FightInfoPacket
|
||||
import de.steamwar.scoreboard.SWScoreboard
|
||||
import de.steamwar.sql.Fight
|
||||
import de.steamwar.sql.FightPlayer
|
||||
import de.steamwar.sql.SteamwarUser
|
||||
import de.steamwar.tntleague.colorByTeam
|
||||
import de.steamwar.tntleague.config.TNTLeagueConfig
|
||||
@@ -37,10 +35,9 @@ import de.steamwar.tntleague.events.LobbyListener
|
||||
import de.steamwar.tntleague.inventory.DealerInventory
|
||||
import de.steamwar.tntleague.message
|
||||
import de.steamwar.tntleague.plugin
|
||||
import de.steamwar.tntleague.util.*
|
||||
import de.steamwar.tntleague.util.TNTLeagueScoreboard
|
||||
import org.bukkit.GameMode
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.Sound
|
||||
import org.bukkit.entity.Item
|
||||
import org.bukkit.entity.Player
|
||||
@@ -51,6 +48,7 @@ import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
import java.sql.Timestamp
|
||||
import java.time.Instant
|
||||
import kotlin.random.Random
|
||||
|
||||
object TNTLeagueGame {
|
||||
var state: GameState = GameState.LOBBY
|
||||
@@ -87,18 +85,24 @@ object TNTLeagueGame {
|
||||
|
||||
message.broadcast("GAME_STARTED")
|
||||
|
||||
val tnt = ItemStack(Material.TNT)
|
||||
|
||||
start = Timestamp.from(Instant.now())
|
||||
|
||||
var spawnCount = 0
|
||||
spawnerTask = plugin.server.scheduler.runTaskTimer(plugin, bukkit {
|
||||
val coinsToSpawn = if (spawnCount % 28 == 0) {
|
||||
DealerInventory.huge_coins
|
||||
} else if (spawnCount % 7 == 0) {
|
||||
DealerInventory.big_coins
|
||||
} else {
|
||||
DealerInventory.coins
|
||||
}
|
||||
spawnCount++
|
||||
|
||||
if (world.getNearbyEntitiesByType(Item::class.java, TNTLeagueWorldConfig.blueTeam.itemSpawn, 3.0).sumOf { it.itemStack.amount } <= 256) {
|
||||
spawnItems(TNTLeagueWorldConfig.blueTeam.itemSpawn, tnt)
|
||||
spawnItems(TNTLeagueWorldConfig.blueTeam.itemSpawn, DealerInventory.coins)
|
||||
spawnItems(TNTLeagueWorldConfig.blueTeam.itemSpawn, coinsToSpawn)
|
||||
}
|
||||
if (world.getNearbyEntitiesByType(Item::class.java, TNTLeagueWorldConfig.redTeam.itemSpawn, 3.0).sumOf { it.itemStack.amount } <= 256) {
|
||||
spawnItems(TNTLeagueWorldConfig.redTeam.itemSpawn, tnt)
|
||||
spawnItems(TNTLeagueWorldConfig.redTeam.itemSpawn, DealerInventory.coins)
|
||||
spawnItems(TNTLeagueWorldConfig.redTeam.itemSpawn, coinsToSpawn)
|
||||
}
|
||||
}, 5, 10)
|
||||
|
||||
|
||||
@@ -59,13 +59,31 @@ class DealerInventory(player: Player): KotlinInventory(player) {
|
||||
companion object {
|
||||
private val priceKey = NamespacedKey(plugin, "price")
|
||||
private val amountKey = NamespacedKey(plugin, "amount")
|
||||
private val coinKey = NamespacedKey(plugin, "coin")
|
||||
val coinKey = NamespacedKey(plugin, "coin")
|
||||
|
||||
val coins = ItemStack(Material.RAW_GOLD).apply {
|
||||
itemMeta = itemMeta.apply {
|
||||
displayName(Component.text("Coins").color(NamedTextColor.GOLD))
|
||||
persistentDataContainer.apply {
|
||||
set(coinKey, PersistentDataType.BOOLEAN, true)
|
||||
set(coinKey, PersistentDataType.INTEGER, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val big_coins = ItemStack(Material.GOLD_INGOT).apply {
|
||||
itemMeta = itemMeta.apply {
|
||||
displayName(Component.text("Big Coins").color(NamedTextColor.GOLD))
|
||||
persistentDataContainer.apply {
|
||||
set(coinKey, PersistentDataType.INTEGER, 3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val huge_coins = ItemStack(Material.GOLD_BLOCK).apply {
|
||||
itemMeta = itemMeta.apply {
|
||||
displayName(Component.text("Huge Coins").color(NamedTextColor.GOLD))
|
||||
persistentDataContainer.apply {
|
||||
set(coinKey, PersistentDataType.INTEGER, 9)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,20 +17,23 @@
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
PREFIX=<EFBFBD>eTowerRun<EFBFBD>8<EFBFBD><EFBFBD>r
|
||||
PREFIX=§eTowerRun§8§§r
|
||||
|
||||
PLAYER_DIED=<EFBFBD>c{0} <EFBFBD>7died<EFBFBD>8!
|
||||
PLAYER_ESCAPE=<EFBFBD>a{0} <EFBFBD>7escaped<EFBFBD>8!
|
||||
GAME_START=<EFBFBD>aThe game has started<EFBFBD>8!
|
||||
GAME_WIN=<EFBFBD>a{0} <EFBFBD>7has won the game<EFBFBD>8!
|
||||
GAME_STARTING=<EFBFBD>7Starting: <EFBFBD>e{0}s<EFBFBD>8!
|
||||
GAME_WAITING=<EFBFBD>7Waiting for players<EFBFBD>8...
|
||||
SERVER_STOPPING=<EFBFBD>cThe server stops in <EFBFBD>e{0}s<EFBFBD>8!
|
||||
SERVER_RESET=<EFBFBD>cThe server will be reset in <EFBFBD>e{0}s<EFBFBD>8!
|
||||
KEY_NAME=<EFBFBD>eKey
|
||||
KEY_FOUND=<EFBFBD>a{0} <EFBFBD>7found a key<EFBFBD>8!
|
||||
GAME_TIE=<EFBFBD>aThe game ended in a tie<EFBFBD>8!
|
||||
GAME_TIME=<EFBFBD>a{0}:{1}
|
||||
CATCH_UP_WARNING=<EFBFBD>4!! <EFBFBD>cYou should catch up <EFBFBD>4!!
|
||||
PLAYER_DIED=§c{0} §7died§8!
|
||||
PLAYER_ESCAPE=§a{0} §7escaped§8!
|
||||
GAME_START=§aThe game has started§8!
|
||||
GAME_WIN=§a{0} §7has won the game§8!
|
||||
GAME_STARTING=§7Starting: §e{0}s§8!
|
||||
GAME_WAITING=§7Waiting for players§8...
|
||||
SERVER_STOPPING=§cThe server stops in §e{0}s§8!
|
||||
SERVER_RESET=§cThe server will be reset in §e{0}s§8!
|
||||
KEY_NAME=§eKey
|
||||
KEY_FOUND=§a{0} §7found a key§8!
|
||||
GAME_TIE=§aThe game ended in a tie§8!
|
||||
GAME_TIME=§a{0}:{1}
|
||||
CATCH_UP_WARNING=§4!! §cYou should catch up §4!!
|
||||
|
||||
COMMAND_START=<EFBFBD>aThe game will start soon<EFBFBD>8!
|
||||
COMMAND_START=§aThe game will start soon§8!
|
||||
|
||||
PARTICIPANT_CHAT={0} {1}§8» §7{2}
|
||||
SPECTATOR_CHAT=§7{0}§8» §7{1}
|
||||
@@ -17,19 +17,19 @@
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
PLAYER_DIED=<EFBFBD>c{0} <EFBFBD>7ist gestorben<EFBFBD>8!
|
||||
PLAYER_ESCAPE=<EFBFBD>a{0} <EFBFBD>7ist entkommen<EFBFBD>8!
|
||||
GAME_START=<EFBFBD>aDas Spiel beginnt<EFBFBD>8!
|
||||
GAME_WIN=<EFBFBD>a{0} <EFBFBD>7hat das Spiel gewonnen<EFBFBD>8!
|
||||
GAME_STARTING=<EFBFBD>7Das Spiel startet in <EFBFBD>e{0}s<EFBFBD>8!
|
||||
GAME_WAITING=<EFBFBD>7Warte auf weitere Spieler<EFBFBD>8...
|
||||
SERVER_STOPPING=<EFBFBD>cDer Server stoppt in <EFBFBD>e{0}s<EFBFBD>8!
|
||||
SERVER_RESET=<EFBFBD>cDer Server wird in <EFBFBD>e{0}s <EFBFBD>czur<EFBFBD>ckgesetzt<EFBFBD>8!
|
||||
GAME_TIE=<EFBFBD>7Keiner hat gewonnen<EFBFBD>8!
|
||||
PLAYER_DIED=§c{0} §7ist gestorben§8!
|
||||
PLAYER_ESCAPE=§a{0} §7ist entkommen§8!
|
||||
GAME_START=§aDas Spiel beginnt§8!
|
||||
GAME_WIN=§a{0} §7hat das Spiel gewonnen§8!
|
||||
GAME_STARTING=§7Das Spiel startet in §e{0}s§8!
|
||||
GAME_WAITING=§7Warte auf weitere Spieler§8...
|
||||
SERVER_STOPPING=§cDer Server stoppt in §e{0}s§8!
|
||||
SERVER_RESET=§cDer Server wird in §e{0}s §czur§ckgesetzt§8!
|
||||
GAME_TIE=§7Keiner hat gewonnen§8!
|
||||
|
||||
KEY_NAME=<EFBFBD>eSchl<EFBFBD>ssel
|
||||
KEY_FOUND=<EFBFBD>a{0} <EFBFBD>7hat einen Schl<EFBFBD>ssel gefunden<EFBFBD>8!
|
||||
KEY_NAME=§eSchl§ssel
|
||||
KEY_FOUND=§a{0} §7hat einen Schl§ssel gefunden§8!
|
||||
|
||||
CATCH_UP_WARNING=<EFBFBD>4!! <EFBFBD>cDu solltest aufholen <EFBFBD>4!!
|
||||
CATCH_UP_WARNING=§4!! §cDu solltest aufholen §4!!
|
||||
|
||||
COMMAND_START=<EFBFBD>7Das Spiel startet bald<EFBFBD>8!
|
||||
COMMAND_START=§7Das Spiel startet bald§8!
|
||||
@@ -35,7 +35,8 @@ import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@UtilityClass
|
||||
public class WorldConfig {
|
||||
@@ -54,7 +55,7 @@ public class WorldConfig {
|
||||
public static final int MAP_MIN_Z;
|
||||
public static final int MAP_MAX_X;
|
||||
public static final int MAP_MAX_Z;
|
||||
public static final Map<Material, Integer> MELTING_TIMES;
|
||||
public static final boolean MELTING;
|
||||
public static final TowerGeneratorConfig TOWER_GENERATOR_CONFIG;
|
||||
|
||||
public static final List<WinCondition> WINCONDITIONS = new ArrayList<>();
|
||||
@@ -161,16 +162,7 @@ public class WorldConfig {
|
||||
MAP_MAX_X = config.getInt("maxX");
|
||||
MAP_MAX_Z = config.getInt("maxZ");
|
||||
|
||||
ConfigurationSection meltingBlocksSection = tower.getConfigurationSection("meltingBlocks");
|
||||
if (meltingBlocksSection != null) {
|
||||
Map<Material, Integer> meltingTimes = new HashMap<>();
|
||||
meltingBlocksSection.getKeys(false).forEach(s -> {
|
||||
meltingTimes.put(Material.valueOf(s), meltingBlocksSection.getInt(s));
|
||||
});
|
||||
MELTING_TIMES = Collections.unmodifiableMap(meltingTimes);
|
||||
} else {
|
||||
MELTING_TIMES = Collections.emptyMap();
|
||||
}
|
||||
MELTING = tower.getBoolean("melting") || tower.contains("meltingBlocks"); // Backwards compatibility with meltingBlocks key!
|
||||
|
||||
ACTIVE_WINCONDITIONS = config.getStringList("winconditions");
|
||||
WINCONDITIONS.stream().filter(winCondition -> ACTIVE_WINCONDITIONS.contains(winCondition.getName())).forEach(winCondition -> winCondition.setActive(true));
|
||||
|
||||
@@ -46,6 +46,10 @@ public class TowerRunGame {
|
||||
public static final List<TowerRunPlayer> PLAYERS_ESCAPED = new ArrayList<>();
|
||||
private static final World world = Bukkit.getWorlds().get(0);
|
||||
|
||||
public static boolean isEscaped(TowerRunPlayer player) {
|
||||
return PLAYERS_ESCAPED.contains(player);
|
||||
}
|
||||
|
||||
public static boolean isAlive(TowerRunPlayer player) {
|
||||
return PLAYERS_ALIVE.contains(player);
|
||||
}
|
||||
|
||||
@@ -19,20 +19,20 @@
|
||||
|
||||
package de.steamwar.towerrun.listener;
|
||||
|
||||
import de.steamwar.towerrun.TowerRun;
|
||||
import de.steamwar.towerrun.config.WorldConfig;
|
||||
import de.steamwar.towerrun.game.TowerRunGame;
|
||||
import de.steamwar.towerrun.game.TowerRunPlayer;
|
||||
import de.steamwar.towerrun.state.GameState;
|
||||
import de.steamwar.towerrun.state.GameStateBukkitListener;
|
||||
import de.steamwar.towerrun.state.GameStates;
|
||||
import lombok.val;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
import org.bukkit.event.player.*;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
@@ -67,4 +67,25 @@ public class GlobalListener extends GameStateBukkitListener implements Listener
|
||||
public void onPlayerRespawn(PlayerRespawnEvent event) {
|
||||
event.setRespawnLocation(WorldConfig.SPAWN);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onAsyncPlayerChat(AsyncPlayerChatEvent event) {
|
||||
TowerRunPlayer player = TowerRunPlayer.get(event.getPlayer());
|
||||
if (GameState.getCurrentState() == GameStates.RUNNING && (TowerRunGame.isAlive(player) || TowerRunGame.isEscaped(player))) {
|
||||
String prefix;
|
||||
if (TowerRunGame.isAlive(player)) {
|
||||
if (event.getPlayer().getGameMode() == GameMode.SPECTATOR) {
|
||||
prefix = "§c☠";
|
||||
} else {
|
||||
prefix = "§6❤";
|
||||
}
|
||||
} else {
|
||||
prefix = "§a✔";
|
||||
}
|
||||
TowerRun.getMessage().broadcastPrefixless("PARTICIPANT_CHAT", prefix, event.getPlayer().getName(), event.getMessage());
|
||||
} else {
|
||||
TowerRun.getMessage().broadcastPrefixless("SPECTATOR_CHAT", event.getPlayer().getName(), event.getMessage());
|
||||
}
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,13 +62,13 @@ public class IngameListener extends GameStateBukkitListener {
|
||||
blocksToMeltRunnable = new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
List<Block> blocks = blocksToMelt.get(time);
|
||||
List<Block> blocks = blocksToMelt.remove(time);
|
||||
time++;
|
||||
if (blocks == null) {
|
||||
return;
|
||||
}
|
||||
blocks.forEach(block -> {
|
||||
if (!WorldConfig.MELTING_TIMES.containsKey(block.getType())) return;
|
||||
if (block.getType() == Material.AIR || block.getType() == Material.LAVA) return;
|
||||
block.setType(Material.AIR);
|
||||
block.getWorld().playSound(block.getLocation(), Sound.BLOCK_FIRE_EXTINGUISH, 0.1F, 1);
|
||||
});
|
||||
@@ -189,6 +189,9 @@ public class IngameListener extends GameStateBukkitListener {
|
||||
|
||||
@EventHandler
|
||||
public void onBlockPhysics(BlockPhysicsEvent event) {
|
||||
if (!WorldConfig.MELTING) {
|
||||
return;
|
||||
}
|
||||
if (event.getSourceBlock().getType() != Material.LAVA) {
|
||||
return;
|
||||
}
|
||||
@@ -202,11 +205,9 @@ public class IngameListener extends GameStateBukkitListener {
|
||||
}
|
||||
|
||||
private void shouldMelt(Block block) {
|
||||
int meltingTime = WorldConfig.MELTING_TIMES.getOrDefault(block.getType(), -1);
|
||||
if (meltingTime == -1) {
|
||||
return;
|
||||
}
|
||||
blocksToMelt.computeIfAbsent(time + meltingTime * 20, integer -> new ArrayList<>()).add(block);
|
||||
if (block.getType().isBurnable()) return;
|
||||
int meltingTime = (int) (block.getType().getHardness() * 48 * 20);
|
||||
blocksToMelt.computeIfAbsent(time + meltingTime, integer -> new ArrayList<>()).add(block);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
|
||||
@@ -154,7 +154,7 @@ UNPUNISHMENT_USAGE=§8/§7{0} §8[§eplayer§8]
|
||||
PUNISHMENT_UNTIL=until {0}
|
||||
PUNISHMENT_PERMA=permanent
|
||||
|
||||
BAN_TEAM={0} §e{1} §7was §e§lbanned§7 by §e{2} {3}§8: §f{4}
|
||||
BAN_TEAM=§e{0} §7was §e§lbanned§7 by §e{1} {2}§8: §f{3}
|
||||
BAN_PERMA=§7You are §e§lbanned §epermanently§8: §e{0}
|
||||
BAN_UNTIL=§7You are §e§lbanned §euntil {0}§8: §e{1}
|
||||
UNBAN_ERROR=§cThe player isn't banned.
|
||||
@@ -164,49 +164,49 @@ BAN_AVOIDING_ALERT=§cPotential ban bypass by §r{0}§c: {1}
|
||||
BAN_AVOIDING_LIST=§c{0} §e{1}
|
||||
BAN_AVOIDING_BAN_HOVER=§cBan player because of bann bypass.
|
||||
|
||||
MUTE_TEAM={0} §e{1} §7was §e§lmuted§7 by §e{2} {3}§8: §f{4}
|
||||
MUTE_TEAM=§e{0} §7was §e§lmuted§7 by §e{1} {2}§8: §f{3}
|
||||
MUTE_PERMA=§7You are §epermanently §e§lmuted§8: §e{0}
|
||||
MUTE_UNTIL=§7You are §e§lmuted §euntil {0}§8: §e{1}
|
||||
UNMUTE_ERROR=§cThe player isn't muted.
|
||||
UNMUTE=§7You have §e§lunmuted §e{0}.
|
||||
|
||||
NOSCHEMRECEIVING_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lrecieving schematics§8: §f{4}
|
||||
NOSCHEMRECEIVING_TEAM=§e{0} §7was excluded from §e{1} {2} §7from §e§lrecieving schematics§8: §f{3}
|
||||
NOSCHEMRECEIVING_PERMA=§7You are §epermanently§7 excluded from receiving §e§lschematics§8: §e{0}
|
||||
NOSCHEMRECEIVING_UNTIL=§7You are excluded from receiving §e§lschematics §euntil {0}§8: §e{1}
|
||||
UNNOSCHEMRECEIVING_ERROR=§cThe player is not excluded from receiving schematics.
|
||||
UNNOSCHEMRECEIVING=§e{0} §7may now receive §e§lschematics§7 again§8.
|
||||
|
||||
NOSCHEMSHARING_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lsharing schematics§8: §f{4}
|
||||
NOSCHEMSHARING_TEAM=§e{0} §7was excluded from §e{1} {2} §7from §e§lsharing schematics§8: §f{3}
|
||||
NOSCHEMSHARING_PERMA=§7You are §epermanently§7 excluded from sharing §e§lschematics§8: §e{0}
|
||||
NOSCHEMSHARING_UNTIL=§7You are excluded from sharing §e§lschematics §euntil {0}§8: §e{1}
|
||||
UNNOSCHEMSHARING_ERROR=§cThe player is not excluded from sharing schematics.
|
||||
UNNOSCHEMSHARING=§e{0} §7may now share §e§lschematics§7 again§8.
|
||||
|
||||
NOSCHEMSUBMITTING_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lsubmitting schematics§8: §f{4}
|
||||
NOSCHEMSUBMITTING_TEAM=§e{0} §7was excluded from §e{1} {2} §7from §e§lsubmitting schematics§8: §f{3}
|
||||
NOSCHEMSUBMITTING_PERMA=§7You are §epermanently§7 excluded from submitting §e§lschematics§8: §e{0}
|
||||
NOSCHEMSUBMITTING_UNTIL=§7You are excluded from submitting §e§lschematics §euntil {0}§8: §e{1}
|
||||
UNNOSCHEMSUBMITTING_ERROR=§cThe player is not excluded from submitting schematics.
|
||||
UNNOSCHEMSUBMITTING=§e{0} §7may now submit §e§lschematics§7 again§8.
|
||||
|
||||
NODEVSERVER_TEAM={0} §e{1} §7has annoyed §e{2} §7with reason §f{4}§7 and therefore has received §e§ldev server prohibition§7§8, §f{3}
|
||||
NODEVSERVER_TEAM=§e{0} §7has annoyed §e{1} §7with reason §f{3}§7 and therefore has received §e§ldev server prohibition§7§8, §f{2}
|
||||
NODEVSERVER_PERMA=§7You are §epermanently§7 excluded from §e§ldev servers§8: §e{0}
|
||||
NODEVSERVER_UNTIL=§7You are excluded from §e§ldev servers§7 §euntil {0}§8: §e{1}
|
||||
UNNODEVSERVER_ERROR=§cThe player is not excluded from dev servers.
|
||||
UNNODEVSERVER=§e{0} §7may now join §e§ldev servers§7 again§8.
|
||||
|
||||
NOFIGHTSERVER_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lfighting§8: §f{4}
|
||||
NOFIGHTSERVER_TEAM=§e{0} §7was excluded from §e{1} {2} §7from §e§lfighting§8: §f{3}
|
||||
NOFIGHTSERVER_PERMA=§7You are §epermanently§7 excluded from §e§lfighting§8: §e{0}
|
||||
NOFIGHTSERVER_UNTIL=§7You are excluded from §e§lfighting§7 §euntil {0}§8: §e{1}
|
||||
UNNOFIGHTSERVER_ERROR=§cThe player is not excluded from fighting.
|
||||
UNNOFIGHTSERVER=§e{0} §7may now join §e§lfights§7 again§8.
|
||||
|
||||
NOTEAMSERVER_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lteam servers§8: §f{4}
|
||||
NOTEAMSERVER_TEAM=§e{0} §7was excluded from §e{1} {2} §7from §e§lteam servers§8: §f{3}
|
||||
NOTEAMSERVER_PERMA=§7You are §epermanently§7 excluded from §e§lteam servers§8: §e{0}
|
||||
NOTEAMSERVER_UNTIL=§7You are excluded from §e§lteam servers§7 §euntil {0}§8: §e{1}
|
||||
UNNOTEAMSERVER_ERROR=§cThe player is not excluded from team servers.
|
||||
UNNOTEAMSERVER=§e{0} §7may now set §e§lteam servers§7 again§8.
|
||||
|
||||
NOTE_TEAM={0} §e{1} §7received a §e§lnote§7 from §e{2} {3}: §f{4}
|
||||
NOTE_TEAM=§e{0} §7received a §e§lnote§7 from §e{1} {2}: §f{3}
|
||||
|
||||
#BugCommand
|
||||
BUG_MESSAGE=§7Please describe the issue in a Discord ticket with the bug ID §e{0} §7further§8.
|
||||
@@ -572,6 +572,7 @@ CHAT_NO_RECEIVER=§cNobody receives your message
|
||||
CHAT_EMPTY=§cDon\'t write meaningless empty messages.
|
||||
|
||||
CHAT_SERVERTEAM=§8STC §e{0}§8» §f{2}
|
||||
CHAT_DISCORD_SERVERTEAM=§8STC §e{0}§8» §f{2}
|
||||
CHAT_GLOBAL={3}{4}{5}{6}{0}§8» {7}{2}
|
||||
CHAT_DISCORD_GLOBAL=§8Dc {5}{6}{0}§8» {7}{2}
|
||||
CHAT_TEAM=§8TC §e{0}§8» §f{2}
|
||||
|
||||
@@ -138,7 +138,7 @@ UNPUNISHMENT_USAGE=§8/§7{0} §8[§eSpieler§8]
|
||||
PUNISHMENT_UNTIL=bis zum {0}
|
||||
PUNISHMENT_PERMA=permanent
|
||||
|
||||
BAN_TEAM={0} §e{1} §7wurde von §e{2} {3} §e§lgebannt§8. §7Grund§8: §f{4}
|
||||
BAN_TEAM=§e{1} §7wurde von §e{2} {3} §e§lgebannt§8. §7Grund§8: §f{4}
|
||||
BAN_PERMA=§7Du bist §epermanent §e§lgebannt§8. §7Grund§8: §e{0}
|
||||
BAN_UNTIL=§7Du bist §ebis zum {0} §e§lgebannt§8. §7Grund§8: §e{1}
|
||||
UNBAN_ERROR=§cDer Spieler ist nicht gebannt.
|
||||
@@ -148,49 +148,49 @@ BAN_AVOIDING_ALERT=§cMögliche Bannumgehung durch §r{0}§c: {1}
|
||||
BAN_AVOIDING_LIST=§c{0} §e{1}
|
||||
BAN_AVOIDING_BAN_HOVER=§cBanne Spieler wegen Bannumgehung
|
||||
|
||||
MUTE_TEAM={0} §e{1} §7wurde von §e{2} {3} §e§lgemuted§8. §7Grund§8: §f{4}
|
||||
MUTE_TEAM=§e{0} §7wurde von §e{1} {2} §e§lgemuted§8. §7Grund§8: §f{3}
|
||||
MUTE_PERMA=§7Du bist §epermanent §e§lgemuted§8. §7Grund§8: §e{0}
|
||||
MUTE_UNTIL=§7Du bist §ebis zum {0} §e§lgemuted§8. §7Grund§8: §e{1}
|
||||
UNMUTE_ERROR=§cDer Spieler ist nicht gemuted.
|
||||
UNMUTE=§7Du hast §e{0} §e§lentmuted.
|
||||
|
||||
NOSCHEMRECEIVING_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematicerhalten§7 ausgeschlossen§8: §f{4}
|
||||
NOSCHEMRECEIVING_TEAM=§e{0} §7wurde von §e{1} {2} §7vom §e§lSchematicerhalten§7 ausgeschlossen§8: §f{3}
|
||||
NOSCHEMRECEIVING_PERMA=§7Du bist §epermanent §7vom Erhalten von §e§lSchematics§7 ausgeschlossen§8: §e{0}
|
||||
NOSCHEMRECEIVING_UNTIL=§7Du bist §ebis zum {0} §7vom Erhalten von §e§lSchematics§7 ausgeschlossen§8: §e{1}
|
||||
UNNOSCHEMRECEIVING_ERROR=§cDer Spieler ist nicht vom Erhalten von Schematics ausgeschlossen.
|
||||
UNNOSCHEMRECEIVING=§e{0} §7darf nun wieder §e§lSchematics§7 erhalten§8.
|
||||
|
||||
NOSCHEMSHARING_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematicverteilen§7 ausgeschlossen§8: §f{4}
|
||||
NOSCHEMSHARING_TEAM=§e{0} §7wurde von §e{1} {2} §7vom §e§lSchematicverteilen§7 ausgeschlossen§8: §f{3}
|
||||
NOSCHEMSHARING_PERMA=§7Du bist §epermanent §7vom §e§lVerteilen von Schematics§7 ausgeschlossen§8: §e{0}
|
||||
NOSCHEMSHARING_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lVerteilen von Schematics§7 ausgeschlossen§8: §e{1}
|
||||
UNNOSCHEMSHARING_ERROR=§cDer Spieler ist nicht vom Verteilen von Schematics ausgeschlossen.
|
||||
UNNOSCHEMSHARING=§e{0} §7darf nun wieder §e§lSchematics§7 verteilen§8.
|
||||
|
||||
NOSCHEMSUBMITTING_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematiceinsenden§7 ausgeschlossen§8: §f{4}
|
||||
NOSCHEMSUBMITTING_TEAM=§e{0} §7wurde von §e{1} {2} §7vom §e§lSchematiceinsenden§7 ausgeschlossen§8: §f{3}
|
||||
NOSCHEMSUBMITTING_PERMA=§7Du bist §epermanent §7vom §e§lEinsenden von Schematics§7 ausgeschlossen§8: §e{0}
|
||||
NOSCHEMSUBMITTING_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lEinsenden von Schematics§7 ausgeschlossen§8: §e{1}
|
||||
UNNOSCHEMSUBMITTING_ERROR=§cDer Spieler ist nicht vom Einsenden von Schematics ausgeschlossen.
|
||||
UNNOSCHEMSUBMITTING=§e{0} §7darf nun wieder §e§lSchematis§7 einsenden§8.
|
||||
|
||||
NODEVSERVER_TEAM={0} §e{1} §7hat §e{2} §7mit Grund §f{4}§7 zu genervt und hat daher §e§lDevserververbot§7 erhalten§8, §f{3}
|
||||
NODEVSERVER_TEAM=§e{0} §7hat §e{1} §7mit Grund §f{3}§7 zu genervt und hat daher §e§lDevserververbot§7 erhalten§8, §f{2}
|
||||
NODEVSERVER_PERMA=§7Du bist §epermanent §7vom §e§lDevserver§7 ausgeschlossen§8: §e{0}
|
||||
NODEVSERVER_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lDevserver§7 ausgeschlossen§8: §e{1}
|
||||
UNNODEVSERVER_ERROR=§cDer Spieler ist nicht vom Devserver ausgeschlossen.
|
||||
UNNODEVSERVER=§e{0} §7darf nun wieder dem §e§lDevserver§7 beitreten§8.
|
||||
|
||||
NOFIGHTSERVER_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lKämpfen§7 ausgeschlossen§8: §f{4}
|
||||
NOFIGHTSERVER_TEAM=§e{0} §7wurde von §e{1} {2} §7vom §e§lKämpfen§7 ausgeschlossen§8: §f{3}
|
||||
NOFIGHTSERVER_PERMA=§7Du bist §epermanent §7vom §e§lKämpfen§7 ausgeschlossen§8: §e{0}
|
||||
NOFIGHTSERVER_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lKämpfen§7 ausgeschlossen§8: §e{1}
|
||||
UNNOFIGHTSERVER_ERROR=§cDer Spieler ist nicht vom Kämpfen ausgeschlossen.
|
||||
UNNOFIGHTSERVER=§e{0} §7darf nun wieder §e§lKämpfen§7 beitreten§8.
|
||||
|
||||
NOTEAMSERVER_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lTeamserver§7 setzen ausgeschlossen§8: §f{4}
|
||||
NOTEAMSERVER_TEAM=§e{0} §7wurde von §e{1} {2} §7vom §e§lTeamserver§7 setzen ausgeschlossen§8: §f{3}
|
||||
NOTEAMSERVER_PERMA=§7Du bist §epermanent §7vom §e§lTeamserver§7 setzen ausgeschlossen§8: §e{0}
|
||||
NOTEAMSERVER_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lTeamserver§7 setzen ausgeschlossen§8: §e{1}
|
||||
UNNOTEAMSERVER_ERROR=§cDer Spieler ist nicht vom Teamserver setzten ausgeschlossen.
|
||||
UNNOTEAMSERVER=§e{0} §7darf nun wieder §e§lTeamserver§7 setzen§8.
|
||||
|
||||
NOTE_TEAM={0} §e{1} §7erhielt von §e{2} {3} §7die §e§lNotiz§7§8: §f{4}
|
||||
NOTE_TEAM=§e{0} §7erhielt von §e{1} {2} §7die §e§lNotiz§7§8: §f{3}
|
||||
|
||||
#BugCommand
|
||||
BUG_MESSAGE=§7Bitte beschreibe das Problem in einem Discordticket genauer und gebe dabei die Bug-ID §e{0} §7an§8.
|
||||
@@ -536,9 +536,9 @@ CHAT_YOYONOW_3=Vielen Dank.
|
||||
CHAT_YOYONOW_4=Ich wünsche dir noch weiterhin ein reibungsloses Spielerlebnis.
|
||||
CHAT_CHAOSCAOT_1=Du hast mich gerufen!
|
||||
CHAT_CHAOSCAOT_2=Wenn etwas nicht funktioniert, dann nen es einfach ein Feature.
|
||||
CHAT_CHAOSCAOT_3=Und wenn es ein Feature ist, dann kann es nicht kaputt.
|
||||
CHAT_CHAOSCAOT_4=Kaputt ist nur eine Definition. Wenn du es als Feature definiert, dann kann es nicht kaputt sein.
|
||||
CHAT_CHAOSCAOT_5=Und wenn du es als kaputt definiert, dann sag uns bescheid mit dem Befehl "/bug <MESSAGE>".
|
||||
CHAT_CHAOSCAOT_3=Und wenn es ein Feature ist, dann kann es nicht kaputt sein.
|
||||
CHAT_CHAOSCAOT_4=Kaputt ist nur eine Definition. Wenn du alles als Feature definierst, dann kann es auch keine Bugs geben.
|
||||
CHAT_CHAOSCAOT_5=Solltest du es aber doch als Bug definieren, dann sag uns bescheid mit dem Befehl "/bug <MESSAGE>".
|
||||
CHAT_CHAOSCAOT_6=Vielen Dank.
|
||||
CHAT_RECEIVE=§cUm Chatnachrichten versenden zu können, musst du auch welche empfangen!
|
||||
CHAT_NO_LINKS=§cDu darfst keine Links versenden.
|
||||
@@ -547,6 +547,7 @@ CHAT_NO_RECEIVER=§cNiemand empfängt deine Nachricht
|
||||
CHAT_EMPTY=§cSchreibe keine inhaltslosen Nachrichten.
|
||||
|
||||
CHAT_SERVERTEAM=§8STC §e{0}§8» §f{2}
|
||||
CHAT_DISCORD_SERVERTEAM=§8STC §e{0}§8» §f{2}
|
||||
CHAT_GLOBAL={3}{4}{5}{6}{0}§8» {7}{2}
|
||||
CHAT_DISCORD_GLOBAL=§8Dc {5}{6}{0}§8» {7}{2}
|
||||
CHAT_TEAM=§8TC §e{0}§8» §f{2}
|
||||
|
||||
@@ -22,6 +22,7 @@ package de.steamwar.velocitycore;
|
||||
import de.steamwar.sql.SchematicType;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
public class ArenaMode extends GameModeConfig {
|
||||
@@ -76,7 +77,7 @@ public class ArenaMode extends GameModeConfig {
|
||||
public static List<String> getAllChatNames(boolean historic) {
|
||||
List<String> chatNames = new LinkedList<>();
|
||||
for(ArenaMode mode : byInternal.values()){
|
||||
if(historic == mode.isHistoric())
|
||||
if(mode.isActive() && historic == mode.isHistoric())
|
||||
chatNames.addAll(mode.getServer().getChatNames());
|
||||
}
|
||||
return chatNames;
|
||||
@@ -94,6 +95,9 @@ public class ArenaMode extends GameModeConfig {
|
||||
@Getter
|
||||
private String config;
|
||||
|
||||
@Getter
|
||||
private List<Integer> ActiveMonths = Collections.emptyList();
|
||||
|
||||
public String hasMap(String map){
|
||||
for(String m : getMaps()) {
|
||||
if(m.equalsIgnoreCase(map))
|
||||
@@ -114,8 +118,10 @@ public class ArenaMode extends GameModeConfig {
|
||||
return getServer().getChatNames().get(0);
|
||||
}
|
||||
|
||||
public boolean withoutChatName(){
|
||||
return getServer().getChatNames().isEmpty();
|
||||
public boolean isActive() {
|
||||
if (getServer().getChatNames().isEmpty()) return false;
|
||||
if (ActiveMonths.isEmpty()) return true;
|
||||
return ActiveMonths.contains(LocalDateTime.now().getMonth().getValue());
|
||||
}
|
||||
|
||||
public String getSchemTypeOrInternalName() {
|
||||
|
||||
@@ -135,12 +135,12 @@ public class DevCommand extends SWCommand {
|
||||
});
|
||||
|
||||
devServerPorts.forEach((username, value) -> {
|
||||
if (devServers.containsKey(username))
|
||||
return;
|
||||
|
||||
SteamwarUser user = SteamwarUser.get(username);
|
||||
String name = "Dev " + user.getUserName();
|
||||
((VelocityViaConfig) Via.getConfig()).getVelocityServerProtocols().put(name, ServerVersion.get(devServerVersions.get(username)).getProtocolVersion().getProtocol());
|
||||
|
||||
if (devServers.containsKey(username))
|
||||
return;
|
||||
devServers.put(user.getUserName().toLowerCase(), VelocityCore.getProxy().registerServer(new ServerInfo(name, new InetSocketAddress("127.0.0.1", value))));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public class FightCommand extends SWCommand {
|
||||
private static void getModes(Chatter sender, String precommand, boolean historic){
|
||||
Component start = Component.empty();
|
||||
for(ArenaMode mode : ArenaMode.getAllModes()){
|
||||
if(mode.withoutChatName() || mode.isHistoric() != historic)
|
||||
if (!mode.isActive() || mode.isHistoric() != historic)
|
||||
continue;
|
||||
|
||||
String command = precommand + mode.getChatName();
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
package de.steamwar.velocitycore.commands;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.proxy.Velocity;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.velocitycore.listeners.ChatListener;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
@@ -41,7 +43,7 @@ public class MsgCommand extends SWCommand {
|
||||
}
|
||||
|
||||
public static void msg(PlayerChatter sender, Player target, String[] args) {
|
||||
if(target == null || target.getCurrentServer().isEmpty()) {
|
||||
if(target == null || VelocityCore.getProxy().getPlayer(target.getUniqueId()).orElse(null) == null) {
|
||||
sender.system("MSG_OFFLINE");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ public class PunishmentCommand {
|
||||
target.punish(punishmentType, banTime, msg, punisher.getId(), isPerma);
|
||||
if(punishmentType == Punishment.PunishmentType.Ban)
|
||||
ban(target, banTime, msg, punisher, isPerma);
|
||||
Chatter.serverteam().system(punishmentType.getTeamMessage(), new Message("PREFIX"), target, sender, new Message((isPerma ? "PUNISHMENT_PERMA" : "PUNISHMENT_UNTIL"), banTime), msg);
|
||||
Chatter.serverteam().system(punishmentType.getTeamMessage(), target, sender, new Message((isPerma ? "PUNISHMENT_PERMA" : "PUNISHMENT_UNTIL"), banTime), msg);
|
||||
}
|
||||
|
||||
@Register
|
||||
|
||||
@@ -49,7 +49,11 @@ public class TypeMappers {
|
||||
return new TypeMapper<>() {
|
||||
@Override
|
||||
public ArenaMode map(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return ArenaMode.getByChat(s);
|
||||
ArenaMode arenaMode = ArenaMode.getByChat(s);
|
||||
if (arenaMode == null) return null;
|
||||
if (arenaMode.isHistoric() != historic) return null;
|
||||
if (!arenaMode.isActive()) return null;
|
||||
return arenaMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -167,14 +167,19 @@ public class DiscordBot {
|
||||
checklistChannel = new ChecklistChannel(config.channel("checklist"));
|
||||
config.getCouncilThread().forEach((roleId, threadId) -> new CouncilChannel(DiscordBot.getGuild().getRoleById(roleId), DiscordBot.getGuild().getThreadChannelById(threadId)));
|
||||
|
||||
announcementChannel = new DiscordChannel(config.channel("announcement")) {
|
||||
announcementChannel = new DiscordChannel(config.channel("announcement"), 0) {
|
||||
@Override
|
||||
public void received(MessageReceivedEvent event) {
|
||||
Chatter.broadcast().system("ALERT", event.getMessage().getContentDisplay());
|
||||
}
|
||||
};
|
||||
ingameChat = new DiscordChatRoom(config.channel("ingame"), "CHAT_DISCORD_GLOBAL", Chatter::broadcast);
|
||||
serverTeamChat = new DiscordChatRoom(config.channel("serverteam"), "CHAT_SERVERTEAM", Chatter::serverteam);
|
||||
|
||||
// There is a hard limit of 30 messages per minute to send as a webhook, thus with 8 webhooks we can send
|
||||
// 240 messages per minute. Which means 4 every second. I looked at the WGS fights and there were around
|
||||
// ~70 in a short burst and then rather long no new message.
|
||||
ingameChat = new DiscordChatRoom(config.channel("ingame"), "CHAT_DISCORD_GLOBAL", Chatter::globalChat, 8);
|
||||
// 60 messages per minute should be enough for the server team!
|
||||
serverTeamChat = new DiscordChatRoom(config.channel("serverteam"), "CHAT_DISCORD_SERVERTEAM", Chatter::serverteam, 2);
|
||||
|
||||
VelocityCore.schedule(() -> {
|
||||
try {
|
||||
|
||||
@@ -32,7 +32,7 @@ public class ChecklistChannel extends DiscordChannel {
|
||||
private final List<Integer> lastSchematics = new ArrayList<>();
|
||||
|
||||
public ChecklistChannel(String channel) {
|
||||
super(channel);
|
||||
super(channel, 0);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
|
||||
@@ -26,17 +26,21 @@ import de.steamwar.velocitycore.discord.DiscordBot;
|
||||
import de.steamwar.velocitycore.discord.listeners.ChannelListener;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.dv8tion.jda.api.entities.Icon;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.entities.Webhook;
|
||||
import net.dv8tion.jda.api.entities.WebhookClient;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.events.interaction.component.GenericComponentInteractionCreateEvent;
|
||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||
import net.dv8tion.jda.api.utils.ImageProxy;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
|
||||
import net.dv8tion.jda.internal.requests.IncomingWebhookClientImpl;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Queue;
|
||||
|
||||
|
||||
@AllArgsConstructor
|
||||
public class DiscordChannel extends Chatter.PlayerlessChatter {
|
||||
@@ -46,21 +50,36 @@ public class DiscordChannel extends Chatter.PlayerlessChatter {
|
||||
return user != null ? user : SteamwarUser.get(0);
|
||||
}
|
||||
|
||||
private final Queue<Webhook> webhooks = new ArrayDeque<>();
|
||||
|
||||
private final SteamwarUser user;
|
||||
@Getter
|
||||
private final MessageChannel channel;
|
||||
|
||||
private final int maxNumberOfWebhooks;
|
||||
|
||||
public DiscordChannel(User user) {
|
||||
this(userOrPublic(user), user.openPrivateChannel().complete());
|
||||
this(userOrPublic(user), user.openPrivateChannel().complete(), 0);
|
||||
}
|
||||
|
||||
public DiscordChannel(String channel) {
|
||||
this(DiscordBot.getGuild().getTextChannelById(channel));
|
||||
public DiscordChannel(String channel, int maxNumberOfWebhooks) {
|
||||
this(DiscordBot.getGuild().getTextChannelById(channel), maxNumberOfWebhooks);
|
||||
}
|
||||
|
||||
public DiscordChannel(MessageChannel channel) {
|
||||
this(SteamwarUser.get(-1), channel);
|
||||
public DiscordChannel(MessageChannel channel, int maxNumberOfWebhooks) {
|
||||
this(SteamwarUser.get(-1), channel, maxNumberOfWebhooks);
|
||||
ChannelListener.getChannels().put(this.channel, this);
|
||||
|
||||
if (channel instanceof TextChannel) {
|
||||
TextChannel textChannel = (TextChannel) channel;
|
||||
webhooks.addAll(textChannel.retrieveWebhooks().complete());
|
||||
while (webhooks.size() > maxNumberOfWebhooks) {
|
||||
webhooks.remove().delete().queue();
|
||||
}
|
||||
while (webhooks.size() < maxNumberOfWebhooks) {
|
||||
webhooks.add(textChannel.createWebhook(DiscordBot.getInstance().getJda().getSelfUser().getName()).complete());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void send(String message) {
|
||||
@@ -70,7 +89,7 @@ public class DiscordChannel extends Chatter.PlayerlessChatter {
|
||||
.replace("@here", "`@here`")
|
||||
.replaceAll("<[@#]!?\\d+>", "`$0`");
|
||||
|
||||
if (getChannel() instanceof TextChannel && message.contains("»")) {
|
||||
if (maxNumberOfWebhooks > 0 && getChannel() instanceof TextChannel && message.contains("»")) {
|
||||
String[] strings = message.split("»", 2);
|
||||
String userName = strings[0];
|
||||
String sendMessage = strings[1];
|
||||
@@ -85,29 +104,24 @@ public class DiscordChannel extends Chatter.PlayerlessChatter {
|
||||
return;
|
||||
}
|
||||
|
||||
ImageProxy avatarUrl;
|
||||
String avatarUrl;
|
||||
if (user.getDiscordId() != null) {
|
||||
avatarUrl = DiscordBot.getGuild().retrieveMemberById(user.getDiscordId()).complete().getEffectiveAvatar();
|
||||
avatarUrl = DiscordBot.getGuild().retrieveMemberById(user.getDiscordId()).complete().getEffectiveAvatarUrl();
|
||||
} else {
|
||||
avatarUrl = DiscordBot.getInstance().getJda().getSelfUser().getAvatar();
|
||||
avatarUrl = DiscordBot.getInstance().getJda().getSelfUser().getAvatarUrl();
|
||||
}
|
||||
|
||||
TextChannel textChannel = (TextChannel) getChannel();
|
||||
try {
|
||||
textChannel.createWebhook(userName)
|
||||
.setAvatar(Icon.from(avatarUrl.download(128).get()))
|
||||
.onSuccess(webhook -> {
|
||||
webhook.sendMessage(sendMessage)
|
||||
.onSuccess(__ -> {
|
||||
webhook.delete().queue();
|
||||
})
|
||||
.queue();
|
||||
})
|
||||
.queue();
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
// Ignore and send message as normal!
|
||||
}
|
||||
Webhook webhook = webhooks.poll();
|
||||
webhooks.add(webhook);
|
||||
|
||||
// This works as per this documentation: https://discord.com/developers/docs/resources/webhook#execute-webhook
|
||||
IncomingWebhookClientImpl webhookClient = (IncomingWebhookClientImpl) WebhookClient.createClient(DiscordBot.getInstance().getJda(), webhook.getUrl());
|
||||
webhookClient.sendRequest()
|
||||
.setUsername(userName)
|
||||
.setAvatarUrl(avatarUrl)
|
||||
.setContent(sendMessage)
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
send(new MessageCreateBuilder()
|
||||
|
||||
@@ -33,8 +33,8 @@ public class DiscordChatRoom extends DiscordChannel {
|
||||
private final String format;
|
||||
private final Supplier<ChatterGroup> target;
|
||||
|
||||
public DiscordChatRoom(String channel, String format, Supplier<ChatterGroup> target) {
|
||||
super(channel);
|
||||
public DiscordChatRoom(String channel, String format, Supplier<ChatterGroup> target, int maxNumberOfWebhooks) {
|
||||
super(channel, maxNumberOfWebhooks);
|
||||
this.format = format;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@@ -46,14 +46,14 @@ public class StaticMessageChannel extends DiscordChannel {
|
||||
}
|
||||
|
||||
public StaticMessageChannel(String channel, Supplier<MessageCreateBuilder> supplier, Consumer<GenericComponentInteractionCreateEvent> interaction) {
|
||||
super(channel);
|
||||
super(channel, 0);
|
||||
this.supplier = supplier;
|
||||
this.interaction = interaction;
|
||||
init();
|
||||
}
|
||||
|
||||
public StaticMessageChannel(MessageChannel channel, Supplier<MessageCreateBuilder> supplier, Consumer<GenericComponentInteractionCreateEvent> interaction) {
|
||||
super(channel);
|
||||
super(channel, 0);
|
||||
this.supplier = supplier;
|
||||
this.interaction = interaction;
|
||||
init();
|
||||
|
||||
@@ -70,7 +70,7 @@ public class DiscordTicketHandler extends ListenerAdapter {
|
||||
Permission.MESSAGE_HISTORY).complete();
|
||||
ticketChannel.getManager().setTopic(event.getUser().getId()).complete();
|
||||
|
||||
DiscordChannel channel = new DiscordChannel(DiscordChannel.userOrPublic(event.getUser()), ticketChannel);
|
||||
DiscordChannel channel = new DiscordChannel(DiscordChannel.userOrPublic(event.getUser()), ticketChannel, 0);
|
||||
channel.send(new MessageCreateBuilder()
|
||||
.setEmbeds(new EmbedBuilder()
|
||||
.setTitle(channel.parseToPlain("DC_TICKET_TITLE"))
|
||||
|
||||
@@ -377,7 +377,8 @@ public class PluginMessage extends BasicListener {
|
||||
"axiom:hello", "axiom:set_gamemode", "axiom:set_fly_speed", "axiom:set_world_time",
|
||||
"axiom:set_world_property", "axiom:set_block", "axiom:set_hotbar_slot", "axiom:switch_active_hotbar",
|
||||
"axiom:teleport", "axiom:request_chunk_data", "axiom:spawn_entity", "axiom:response_entity_data",
|
||||
"axiom:manipulate_entity", "axiom:delete_entity", "axiom:marker_nbt_request", "axiom:set_buffer"
|
||||
"axiom:manipulate_entity", "axiom:delete_entity", "axiom:marker_nbt_request", "axiom:set_buffer",
|
||||
"axiom:allowed_gamemodes", "axiom:ignore_display_entities", "axiom:add_server_heightmap"
|
||||
)) {
|
||||
channelRegisterHandlers.put(channel, player -> {});
|
||||
registerPassthroughToServer(channel);
|
||||
|
||||
@@ -27,7 +27,6 @@ private val isInCi by lazy { Os.isFamily(Os.FAMILY_UNIX) && ProcessBuilder("host
|
||||
|
||||
dependencyResolutionManagement {
|
||||
repositories {
|
||||
|
||||
maven {
|
||||
url = URI("https://m2.dv8tion.net/releases")
|
||||
content {
|
||||
|
||||
Reference in New Issue
Block a user