forked from SteamWar/SteamWar
Add BauSystem module
Fix ci java version Fix LinkageProcessor
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class BauMemberUpdateEvent extends Event {
|
||||
|
||||
@Getter
|
||||
private final Set<Player> changed;
|
||||
|
||||
@Getter
|
||||
private final Set<Player> newSpectator;
|
||||
|
||||
@Getter
|
||||
private final Set<Player> newBuilder;
|
||||
|
||||
public BauMemberUpdateEvent(Set<Player> newSpectator, Set<Player> newBuilder) {
|
||||
this.newSpectator = Collections.unmodifiableSet(newSpectator);
|
||||
this.newBuilder = Collections.unmodifiableSet(newBuilder);
|
||||
Set<Player> changed = new HashSet<>();
|
||||
changed.addAll(newSpectator);
|
||||
changed.addAll(newBuilder);
|
||||
this.changed = Collections.unmodifiableSet(changed);
|
||||
}
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.region.Point;
|
||||
import de.steamwar.core.VersionDependent;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public interface FlatteningWrapper {
|
||||
FlatteningWrapper impl = VersionDependent.getVersionImpl(BauSystem.getInstance());
|
||||
|
||||
boolean isNoBook(ItemStack item);
|
||||
|
||||
boolean isUnpusheable(Material material);
|
||||
boolean isBreakingOnPush(Material material);
|
||||
|
||||
boolean isWorldEditCommand(String command);
|
||||
void setSelection(Player p, Point minPoint, Point maxPoint);
|
||||
|
||||
Clipboard loadSchematic(File file);
|
||||
EditSession paste(PasteBuilder pasteBuilder);
|
||||
|
||||
Clipboard copy(Point minPoint, Point maxPoint, Point copyPoint);
|
||||
boolean backup(Point minPoint, Point maxPoint, File file);
|
||||
|
||||
boolean inWater(World world, Vector tntPosition);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import de.steamwar.bausystem.SWUtils;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
@UtilityClass
|
||||
public class ItemUtils {
|
||||
|
||||
private final NamespacedKey ITEM_KEY = SWUtils.getNamespaceKey("bau_item");
|
||||
|
||||
public boolean isItem(ItemStack itemStack, String tag) {
|
||||
String value = getTag(itemStack, ITEM_KEY);
|
||||
return value != null && value.equals(tag);
|
||||
}
|
||||
|
||||
public void setItem(ItemStack itemStack, String tag) {
|
||||
setTag(itemStack, ITEM_KEY, tag);
|
||||
}
|
||||
|
||||
public String getTag(ItemStack itemStack, NamespacedKey key) {
|
||||
if (itemStack == null) {
|
||||
return null;
|
||||
}
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
if (meta == null) {
|
||||
return null;
|
||||
}
|
||||
PersistentDataContainer container = meta.getPersistentDataContainer();
|
||||
if (!container.has(key, PersistentDataType.STRING)) {
|
||||
return null;
|
||||
}
|
||||
return container.get(key, PersistentDataType.STRING);
|
||||
}
|
||||
|
||||
public void setTag(ItemStack itemStack, NamespacedKey key, String value) {
|
||||
if (itemStack == null) {
|
||||
return;
|
||||
}
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
if (meta == null) {
|
||||
return;
|
||||
}
|
||||
if (value == null) {
|
||||
meta.getPersistentDataContainer().remove(key);
|
||||
} else {
|
||||
meta.getPersistentDataContainer().set(key, PersistentDataType.STRING, value);
|
||||
}
|
||||
itemStack.setItemMeta(meta);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
@UtilityClass
|
||||
public class ListChatView {
|
||||
|
||||
public static <T> void chatView(Player player, List<T> elements, int page, Function<T, TextComponent> elementConverter, BiConsumer<TextComponent, Integer> beforePageConsumer, BiConsumer<TextComponent, Integer> afterPageConsumer) {
|
||||
int pageCount = (int) Math.ceil(elements.size() / 18d);
|
||||
for (int i = page * 18; i < elements.size() && i < (page + 1) * 18; i++) {
|
||||
T element = elements.get(i);
|
||||
player.spigot().sendMessage(elementConverter.apply(element));
|
||||
}
|
||||
|
||||
TextComponent beforePage = new TextComponent("««");
|
||||
if (page > 0) {
|
||||
beforePage.setColor(ChatColor.YELLOW);
|
||||
beforePageConsumer.accept(beforePage, page - 1);
|
||||
} else {
|
||||
beforePage.setColor(ChatColor.RED);
|
||||
}
|
||||
|
||||
TextComponent nextPage = new TextComponent(BauSystem.MESSAGE.parse("PAGE_LIST", player, page + 1, Math.max(pageCount, 1)));
|
||||
if (page < pageCount - 1) {
|
||||
nextPage.setColor(ChatColor.YELLOW);
|
||||
afterPageConsumer.accept(nextPage, page + 1);
|
||||
} else {
|
||||
nextPage.setColor(ChatColor.RED);
|
||||
}
|
||||
|
||||
beforePage.addExtra(nextPage);
|
||||
player.spigot().sendMessage(beforePage);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.core.VersionDependent;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public interface NMSWrapper {
|
||||
NMSWrapper impl = VersionDependent.getVersionImpl(BauSystem.getInstance());
|
||||
|
||||
void setInternalGameMode(Player player, GameMode gameMode);
|
||||
void setSlotToItemStack(Player player, Object o);
|
||||
|
||||
void setGameStateChangeReason(Object packet);
|
||||
void setPlayerBuildAbilities(Player player);
|
||||
|
||||
Material pathMaterial();
|
||||
|
||||
boolean checkItemStack(ItemStack item);
|
||||
|
||||
Object resetExplosionKnockback(Object packet);
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.function.pattern.WaterloggedRemover;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import de.steamwar.bausystem.region.Color;
|
||||
import de.steamwar.bausystem.region.Point;
|
||||
import de.steamwar.sql.SchematicData;
|
||||
import de.steamwar.sql.SchematicNode;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
@Getter
|
||||
public class PasteBuilder {
|
||||
|
||||
private final ClipboardProvider clipboardProvider;
|
||||
private Point pastPoint;
|
||||
private boolean rotate;
|
||||
private boolean ignoreAir;
|
||||
private boolean reset;
|
||||
private Point minPoint;
|
||||
private Point maxPoint;
|
||||
private int waterLevel;
|
||||
private List<BiPredicate<BaseBlock, String>> predicates = new ArrayList<>();
|
||||
private List<BiConsumer<Clipboard, BlockVector3>> mappers = new ArrayList<>();
|
||||
|
||||
public PasteBuilder(@NonNull ClipboardProvider clipboardProvider) {
|
||||
this.clipboardProvider = clipboardProvider;
|
||||
}
|
||||
|
||||
public PasteBuilder pastePoint(Point point) {
|
||||
this.pastPoint = point;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PasteBuilder rotate(boolean rotate) {
|
||||
this.rotate = rotate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PasteBuilder ignoreAir(boolean ignoreAir) {
|
||||
this.ignoreAir = ignoreAir;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PasteBuilder reset(boolean reset) {
|
||||
this.reset = reset;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PasteBuilder minPoint(Point point) {
|
||||
this.minPoint = point;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PasteBuilder maxPoint(Point point) {
|
||||
this.maxPoint = point;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PasteBuilder waterLevel(int waterLevel) {
|
||||
this.waterLevel = waterLevel;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PasteBuilder only(BiPredicate<BaseBlock, String> predicate) {
|
||||
predicates.add(predicate);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PasteBuilder map(BiConsumer<Clipboard, BlockVector3> mapper) {
|
||||
mappers.add(mapper);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PasteBuilder color(Color color) {
|
||||
if (color == Color.PINK) return this;
|
||||
|
||||
BaseBlock WOOL = Objects.requireNonNull(BlockTypes.PINK_WOOL).getDefaultState().toBaseBlock();
|
||||
BaseBlock CLAY = Objects.requireNonNull(BlockTypes.PINK_TERRACOTTA).getDefaultState().toBaseBlock();
|
||||
BaseBlock GLAZED = Objects.requireNonNull(BlockTypes.PINK_GLAZED_TERRACOTTA).getDefaultState().toBaseBlock();
|
||||
BaseBlock GLASS = Objects.requireNonNull(BlockTypes.PINK_STAINED_GLASS).getDefaultState().toBaseBlock();
|
||||
BaseBlock GLASS_PANE = Objects.requireNonNull(BlockTypes.PINK_STAINED_GLASS_PANE).getDefaultState().toBaseBlock();
|
||||
BaseBlock CONCRETE = Objects.requireNonNull(BlockTypes.PINK_CONCRETE).getDefaultState().toBaseBlock();
|
||||
BaseBlock CONCRETE_POWDER = Objects.requireNonNull(BlockTypes.PINK_CONCRETE_POWDER).getDefaultState().toBaseBlock();
|
||||
BaseBlock CARPET = Objects.requireNonNull(BlockTypes.PINK_CARPET).getDefaultState().toBaseBlock();
|
||||
|
||||
BaseBlock wool = Objects.requireNonNull(BlockTypes.get(color.name().toLowerCase() + "_wool")).getDefaultState().toBaseBlock();
|
||||
BaseBlock clay = Objects.requireNonNull(BlockTypes.get(color.name().toLowerCase() + "_terracotta")).getDefaultState().toBaseBlock();
|
||||
BaseBlock glazed = Objects.requireNonNull(BlockTypes.get(color.name().toLowerCase() + "_glazed_terracotta")).getDefaultState().toBaseBlock();
|
||||
BaseBlock glass = Objects.requireNonNull(BlockTypes.get(color.name().toLowerCase() + "_stained_glass")).getDefaultState().toBaseBlock();
|
||||
BaseBlock glassPane = Objects.requireNonNull(BlockTypes.get(color.name().toLowerCase() + "_stained_glass_pane")).getDefaultState().toBaseBlock();
|
||||
BaseBlock carpet = Objects.requireNonNull(BlockTypes.get(color.name().toLowerCase() + "_carpet")).getDefaultState().toBaseBlock();
|
||||
BaseBlock concrete = Objects.requireNonNull(BlockTypes.get(color.name().toLowerCase() + "_concrete")).getDefaultState().toBaseBlock();
|
||||
BaseBlock concretePowder = Objects.requireNonNull(BlockTypes.get(color.name().toLowerCase() + "_concrete_powder")).getDefaultState().toBaseBlock();
|
||||
|
||||
return map((clipboard, blockVector3) -> {
|
||||
BaseBlock block = clipboard.getFullBlock(blockVector3);
|
||||
if (block.equals(WOOL)) {
|
||||
clipboard.setBlock(blockVector3, wool);
|
||||
} else if (block.equals(CLAY)) {
|
||||
clipboard.setBlock(blockVector3, clay);
|
||||
} else if (block.equals(GLAZED)) {
|
||||
clipboard.setBlock(blockVector3, glazed);
|
||||
} else if (block.equals(GLASS)) {
|
||||
clipboard.setBlock(blockVector3, glass);
|
||||
} else if (block.equals(GLASS_PANE)) {
|
||||
clipboard.setBlock(blockVector3, glassPane);
|
||||
} else if (block.equals(CARPET)) {
|
||||
clipboard.setBlock(blockVector3, carpet);
|
||||
} else if (block.equals(CONCRETE)) {
|
||||
clipboard.setBlock(blockVector3, concrete);
|
||||
} else if (block.equals(CONCRETE_POWDER)) {
|
||||
clipboard.setBlock(blockVector3, concretePowder);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public PasteBuilder onlyColors(boolean onlyColors) {
|
||||
if (!onlyColors) return this;
|
||||
return only((baseBlock, s) -> {
|
||||
return s.endsWith("_wool") || s.endsWith("_terracotta") || s.endsWith("_glazed_terracotta") || s.endsWith("_stained_glass") || s.endsWith("_stained_glass_pane") || s.endsWith("_carpet") || s.endsWith("_concrete") || s.endsWith("_concrete_powder");
|
||||
});
|
||||
}
|
||||
|
||||
public PasteBuilder removeTNT(boolean removeTNT) {
|
||||
if (!removeTNT) return this;
|
||||
BaseBlock tnt = Objects.requireNonNull(BlockTypes.get("tnt")).getDefaultState().toBaseBlock();
|
||||
BaseBlock air = Objects.requireNonNull(BlockTypes.get("air")).getDefaultState().toBaseBlock();
|
||||
|
||||
return map((clipboard, blockVector3) -> {
|
||||
BaseBlock baseBlock = clipboard.getFullBlock(blockVector3);
|
||||
if (baseBlock.equals(tnt)) {
|
||||
clipboard.setBlock(blockVector3, air);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public PasteBuilder removeWater(boolean removeWater) {
|
||||
if (!removeWater) return this;
|
||||
BaseBlock water = Objects.requireNonNull(BlockTypes.get("water")).getDefaultState().toBaseBlock();
|
||||
BaseBlock air = Objects.requireNonNull(BlockTypes.get("air")).getDefaultState().toBaseBlock();
|
||||
WaterloggedRemover waterloggedRemover = new WaterloggedRemover(getClipboard());
|
||||
|
||||
return map((clipboard, blockVector3) -> {
|
||||
BaseBlock baseBlock = clipboard.getFullBlock(blockVector3);
|
||||
if (baseBlock.equals(water)) {
|
||||
clipboard.setBlock(blockVector3, air);
|
||||
return;
|
||||
}
|
||||
String blockName = clipboard.getFullBlock(blockVector3).getBlockType().getName();
|
||||
if (blockName.equals("Water")) {
|
||||
clipboard.setBlock(blockVector3, air);
|
||||
return;
|
||||
}
|
||||
baseBlock = waterloggedRemover.applyBlock(blockVector3);
|
||||
if (baseBlock != air) {
|
||||
clipboard.setBlock(blockVector3, baseBlock);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Clipboard getClipboard() {
|
||||
return clipboardProvider.getClipboard();
|
||||
}
|
||||
|
||||
public EditSession run() {
|
||||
if (pastPoint == null) {
|
||||
throw new IllegalStateException("pastePoint is null");
|
||||
}
|
||||
return FlatteningWrapper.impl.paste(this);
|
||||
}
|
||||
|
||||
public interface ClipboardProvider {
|
||||
Clipboard getClipboard();
|
||||
|
||||
default <T extends ClipboardProvider> boolean is(Class<T> clazz) {
|
||||
return clazz.isInstance(this);
|
||||
}
|
||||
|
||||
default <T extends ClipboardProvider> T as(Class<T> clazz) {
|
||||
return clazz.cast(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class FileProvider implements ClipboardProvider {
|
||||
private final File file;
|
||||
private final Clipboard clipboard;
|
||||
|
||||
public FileProvider(File file) {
|
||||
this.file = file;
|
||||
this.clipboard = FlatteningWrapper.impl.loadSchematic(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clipboard getClipboard() {
|
||||
return clipboard;
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class SchematicProvider implements ClipboardProvider {
|
||||
private final SchematicNode schematic;
|
||||
private final Clipboard clipboard;
|
||||
|
||||
public SchematicProvider(SchematicNode schematic) {
|
||||
this.schematic = schematic;
|
||||
try {
|
||||
this.clipboard = new SchematicData(schematic).load();
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clipboard getClipboard() {
|
||||
return clipboard;
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class ClipboardProviderImpl implements ClipboardProvider {
|
||||
private final Clipboard clipboard;
|
||||
|
||||
public ClipboardProviderImpl(Clipboard clipboard) {
|
||||
this.clipboard = clipboard;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clipboard getClipboard() {
|
||||
return clipboard;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,544 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import com.comphenix.tinyprotocol.Reflection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.*;
|
||||
import org.bukkit.block.data.*;
|
||||
import org.bukkit.block.data.type.Hopper;
|
||||
import org.bukkit.block.data.type.Observer;
|
||||
import org.bukkit.block.data.type.*;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.block.BlockCanBuildEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.*;
|
||||
import org.bukkit.util.RayTraceResult;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@UtilityClass
|
||||
public class PlaceItemUtils {
|
||||
|
||||
// https://github.com/Articdive/ArticData/blob/1.20.1/1_20_1_tags/1_20_1_block_tags.json
|
||||
// #minecraft:replaceable
|
||||
private static final Set<String> replaceables;
|
||||
|
||||
static {
|
||||
replaceables = new HashSet<>(Arrays.asList(
|
||||
"minecraft:air",
|
||||
"minecraft:water",
|
||||
"minecraft:lava",
|
||||
"minecraft:grass",
|
||||
"minecraft:fern",
|
||||
"minecraft:dead_bush",
|
||||
"minecraft:seagrass",
|
||||
"minecraft:tall_seagrass",
|
||||
"minecraft:fire",
|
||||
"minecraft:soul_fire",
|
||||
"minecraft:snow",
|
||||
"minecraft:vine",
|
||||
"minecraft:glow_lichen",
|
||||
"minecraft:light",
|
||||
"minecraft:tall_grass",
|
||||
"minecraft:large_fern",
|
||||
"minecraft:structure_void",
|
||||
"minecraft:void_air",
|
||||
"minecraft:cave_air",
|
||||
"minecraft:bubble_column",
|
||||
"minecraft:warped_roots",
|
||||
"minecraft:nether_sprouts",
|
||||
"minecraft:crimson_roots",
|
||||
"minecraft:hanging_roots"))
|
||||
.stream()
|
||||
.map(s -> s.substring(10))
|
||||
.map(String::toUpperCase)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private static final Class<?> blockPosition = Reflection.getClass("{nms.core}.BlockPosition");
|
||||
private static final Reflection.ConstructorInvoker blockPositionConstructor = Reflection.getConstructor(blockPosition, int.class, int.class, int.class);
|
||||
private static final Class<?> craftBlock = Reflection.getClass("{obc}.block.CraftBlockState");
|
||||
private static final Class<?> craftWorld = Reflection.getClass("{obc}.CraftWorld");
|
||||
private static final Reflection.FieldAccessor<?> positionAccessor = Reflection.getField(craftBlock, blockPosition, 0);
|
||||
private static final Reflection.FieldAccessor<?> worldAccessor = Reflection.getField(craftBlock, craftWorld, 0);
|
||||
|
||||
/**
|
||||
* Attempt to place an {@link ItemStack} the {@link Player} is holding against a {@link Block} inside the World.
|
||||
* This can be easily used inside the {@link org.bukkit.event.player.PlayerInteractEvent} to mimik placing a
|
||||
* block without any minecraft related GUI's etc. executing.
|
||||
*
|
||||
* @param player the Player placing the block
|
||||
* @param itemStack the ItemStack to be placed
|
||||
* @param against the Block at which the player aims (does not need to be in range of the player)
|
||||
* @param againstSide the BlockFace the player aims
|
||||
* @param hand the Hand the player is using
|
||||
* @param force allow illegal states to be created by placing the block
|
||||
* @param applyPhysics apply physics while placing the block
|
||||
* @param rotateAway rotate everything in the opposite direction, so a block facing the Player will face away, and the other way round
|
||||
* @param playSound enables sound of placing
|
||||
*/
|
||||
public PlaceItemResult placeItem(Player player, ItemStack itemStack, Block against, BlockFace againstSide, EquipmentSlot hand, boolean force, boolean applyPhysics, boolean rotateAway, boolean playSound) {
|
||||
// If the ItemStack is null or air we cannot place it
|
||||
if (itemStack == null) return PlaceItemResult.NO_ITEM_HELD;
|
||||
if (itemStack.getType().isAir()) return PlaceItemResult.NO_ITEM_HELD;
|
||||
|
||||
// This Block should be replaced by the new Block
|
||||
Block block = against.getRelative(againstSide);
|
||||
|
||||
// We cannot place any Item that is not also a Block, this is checked by testing for the ItemMeta
|
||||
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||
if (!(itemMeta instanceof BlockDataMeta)) {
|
||||
return PlaceItemResult.NO_BLOCK_ITEM_HELD;
|
||||
}
|
||||
|
||||
BlockDataMeta blockDataMeta = (BlockDataMeta) itemMeta;
|
||||
|
||||
// Converting the Item Material to a Block Material
|
||||
// e.g. Material.REDSTONE -> Material.REDSTONE_WIRE
|
||||
Material typeToPlace = PlaceItemWrapper.ITEM_MATERIAL_TO_BLOCK_MATERIAL.getOrDefault(itemStack.getType(), itemStack.getType());
|
||||
|
||||
BlockData blockData = null;
|
||||
AtomicBoolean usedForcePlace = new AtomicBoolean();
|
||||
if (againstSide == BlockFace.NORTH || againstSide == BlockFace.SOUTH || againstSide == BlockFace.EAST || againstSide == BlockFace.WEST) {
|
||||
// Try Wall Placement first
|
||||
blockData = toBlockData(player, blockDataMeta, PlaceItemWrapper.BLOCK_MATERIAL_TO_WALL_BLOCK_MATERIAL.getOrDefault(typeToPlace, typeToPlace));
|
||||
if (blockData != null && !canPlace(block, blockData, force, usedForcePlace)) {
|
||||
// Check if default Rotation from input could be valid
|
||||
BlockFace rotation = getRotation(blockData);
|
||||
setRotation(blockData, againstSide);
|
||||
if (!canPlace(block, blockData, force, usedForcePlace)) {
|
||||
setRotation(blockData, rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try default Placement
|
||||
if (blockData == null || !canPlace(block, blockData, force, usedForcePlace)) {
|
||||
blockData = toBlockData(player, blockDataMeta, typeToPlace);
|
||||
}
|
||||
|
||||
if (blockData != null && !canPlace(block, blockData, force, usedForcePlace)) {
|
||||
if (blockData instanceof FaceAttachable) {
|
||||
// FaceAttachable Blocks should be placed on the Ceiling/Floor if possible
|
||||
// This applies mainly to Lever and Buttons
|
||||
FaceAttachable faceAttachable = (FaceAttachable) blockData;
|
||||
boolean topFirst = isHitHalfTop(player);
|
||||
faceAttachable.setAttachedFace(topFirst ? FaceAttachable.AttachedFace.CEILING : FaceAttachable.AttachedFace.FLOOR);
|
||||
if (!canPlace(block, blockData, force, usedForcePlace)) {
|
||||
faceAttachable.setAttachedFace(topFirst ? FaceAttachable.AttachedFace.FLOOR : FaceAttachable.AttachedFace.CEILING);
|
||||
}
|
||||
if (!canPlace(block, blockData, force, usedForcePlace)) {
|
||||
return PlaceItemResult.NO_VALID_PLACEMENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (blockData == null) return PlaceItemResult.NO_BLOCK_ITEM_HELD;
|
||||
|
||||
// Placing a Block inside of Water should set it to Waterlogged
|
||||
if (blockData instanceof Waterlogged && block.getType() == Material.WATER) {
|
||||
Levelled levelled = (Levelled) block.getBlockData();
|
||||
((Waterlogged) blockData).setWaterlogged(levelled.getLevel() == levelled.getMaximumLevel());
|
||||
}
|
||||
|
||||
if (blockData instanceof Slab) {
|
||||
// Slabs can be set at Top or Bottom
|
||||
((Slab) blockData).setType(isHitHalfTop(player) ? Slab.Type.TOP : Slab.Type.BOTTOM);
|
||||
if (againstSide == BlockFace.DOWN) {
|
||||
((Slab) blockData).setType(Slab.Type.TOP);
|
||||
}
|
||||
} else if (blockData instanceof Stairs) {
|
||||
// Stairs can be set at Top or Bottom
|
||||
((Stairs) blockData).setHalf(isHitHalfTop(player) ? Bisected.Half.TOP : Bisected.Half.BOTTOM);
|
||||
if (againstSide == BlockFace.DOWN) {
|
||||
((Stairs) blockData).setHalf(Bisected.Half.TOP);
|
||||
}
|
||||
} else if (blockData instanceof TrapDoor) {
|
||||
// TrapDoors can be set at Top or Bottom
|
||||
((TrapDoor) blockData).setHalf(isHitHalfTop(player) ? Bisected.Half.TOP : Bisected.Half.BOTTOM);
|
||||
if (againstSide == BlockFace.DOWN) {
|
||||
((TrapDoor) blockData).setHalf(Bisected.Half.TOP);
|
||||
}
|
||||
} else if (blockData instanceof Chain) {
|
||||
// Chains are always rotated against the block you place against
|
||||
Orientable orientable = (Orientable) blockData;
|
||||
switch (againstSide) {
|
||||
case EAST:
|
||||
case WEST:
|
||||
orientable.setAxis(Axis.X);
|
||||
break;
|
||||
case UP:
|
||||
case DOWN:
|
||||
orientable.setAxis(Axis.Y);
|
||||
break;
|
||||
case NORTH:
|
||||
case SOUTH:
|
||||
orientable.setAxis(Axis.Z);
|
||||
break;
|
||||
}
|
||||
} else if (blockData instanceof Hopper && (againstSide == BlockFace.UP || againstSide == BlockFace.DOWN)) {
|
||||
// Placing at the Top or Bottom of a Block result in a downwards facing Hopper
|
||||
((Hopper) blockData).setFacing(BlockFace.DOWN);
|
||||
} else if (blockData instanceof Directional && (blockData.getMaterial().name().endsWith("_HEAD") || blockData.getMaterial().name().endsWith("_SKULL")) && againstSide != BlockFace.DOWN && againstSide != BlockFace.UP) {
|
||||
// Skulls and Heads are always rotated towards you if not in Wall variant
|
||||
((Directional) blockData).setFacing(againstSide);
|
||||
} else if (blockData instanceof LightningRod) {
|
||||
// Lightning Rod is always rotated against the block you place against
|
||||
((Directional) blockData).setFacing(againstSide);
|
||||
}
|
||||
if (force && blockData instanceof FaceAttachable) {
|
||||
// Forcing to Place a FaceAttachable against the Block you specified. Needs the force flag to be set
|
||||
FaceAttachable faceAttachable = (FaceAttachable) blockData;
|
||||
if (blockData instanceof Switch && againstSide == BlockFace.DOWN) {
|
||||
faceAttachable.setAttachedFace(FaceAttachable.AttachedFace.CEILING);
|
||||
} else if (againstSide == BlockFace.UP) {
|
||||
faceAttachable.setAttachedFace(FaceAttachable.AttachedFace.FLOOR);
|
||||
} else if (blockData instanceof Directional) {
|
||||
((Directional) blockData).setFacing(againstSide);
|
||||
}
|
||||
if (blockData instanceof Switch) {
|
||||
// Levers and Buttons are always Rotated the other way
|
||||
Switch switchType = (Switch) blockData;
|
||||
switch (switchType.getAttachedFace()) {
|
||||
case FLOOR:
|
||||
case CEILING:
|
||||
switchType.setFacing(switchType.getFacing().getOppositeFace());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (force && blockData instanceof Directional && !(blockData instanceof FaceAttachable) && PlaceItemWrapper.BLOCK_MATERIAL_TO_WALL_BLOCK_MATERIAL.containsValue(blockData.getMaterial())) {
|
||||
Directional directional = (Directional) blockData;
|
||||
if (directional.getFaces().contains(againstSide)) {
|
||||
directional.setFacing(againstSide);
|
||||
}
|
||||
}
|
||||
if (force && blockData instanceof Rotatable && !(blockData instanceof FaceAttachable)) {
|
||||
Rotatable rotatable = (Rotatable) blockData;
|
||||
if (againstSide != BlockFace.UP && againstSide != BlockFace.DOWN) {
|
||||
rotatable.setRotation(againstSide);
|
||||
}
|
||||
}
|
||||
|
||||
if (blockData instanceof RedstoneWire) {
|
||||
// Redstone Wire is connected to every Side by default
|
||||
RedstoneWire redstoneWire = (RedstoneWire) blockData;
|
||||
redstoneWire.setFace(BlockFace.NORTH, RedstoneWire.Connection.SIDE);
|
||||
redstoneWire.setFace(BlockFace.SOUTH, RedstoneWire.Connection.SIDE);
|
||||
redstoneWire.setFace(BlockFace.EAST, RedstoneWire.Connection.SIDE);
|
||||
redstoneWire.setFace(BlockFace.WEST, RedstoneWire.Connection.SIDE);
|
||||
}
|
||||
|
||||
if (rotateAway) {
|
||||
// Rotate the other way if rotateAway is set to true
|
||||
BlockFace blockFace = getRotation(blockData);
|
||||
if (blockFace != null) {
|
||||
blockFace = blockFace.getOppositeFace();
|
||||
if (blockData instanceof Hopper && (blockFace == BlockFace.UP || blockFace == BlockFace.DOWN)) {
|
||||
((Hopper) blockData).setFacing(BlockFace.DOWN);
|
||||
} else {
|
||||
setRotation(blockData, blockFace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the Block can be build
|
||||
BlockCanBuildEvent blockCanBuildEvent = new BlockCanBuildEvent(against, player, blockData, canPlace(block, blockData, force, usedForcePlace));
|
||||
Bukkit.getPluginManager().callEvent(blockCanBuildEvent);
|
||||
if (!blockCanBuildEvent.isBuildable()) return PlaceItemResult.NO_BUILD;
|
||||
|
||||
BlockState oldState = block.getState();
|
||||
|
||||
// Retrieve the BlockState of the ItemStack if present
|
||||
BlockState blockState = null;
|
||||
if (itemMeta instanceof BlockStateMeta) {
|
||||
blockState = ((BlockStateMeta) itemMeta).getBlockState();
|
||||
}
|
||||
|
||||
if (blockState == null) {
|
||||
// If no BlockState is present use the BlockState of the Block you want to edit
|
||||
blockState = block.getState();
|
||||
} else {
|
||||
// If a BlockState is present set the Position and World to the Block you want to place
|
||||
Location blockLocation = block.getLocation();
|
||||
positionAccessor.set(blockState, blockPositionConstructor.invoke(blockLocation.getBlockX(), blockLocation.getBlockY(), blockLocation.getBlockZ()));
|
||||
worldAccessor.set(blockState, blockLocation.getWorld());
|
||||
}
|
||||
|
||||
if (blockData.getMaterial().isSolid()) {
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
Location min = p.getLocation().add(-0.3, 0, -0.3);
|
||||
Location max = p.getLocation().add(0.3, p.isSneaking() ? 1.5 : 1.8, 0.3);
|
||||
|
||||
Location blockmin = block.getLocation();
|
||||
Location blockmax = block.getLocation().add(1.0, 1.0, 1.0);
|
||||
if (
|
||||
!(max.getX() <= blockmin.getX() || min.getX() >= blockmax.getX() ||
|
||||
max.getY() <= blockmin.getY() || min.getY() >= blockmax.getY() ||
|
||||
max.getZ() <= blockmin.getZ() || min.getZ() >= blockmax.getZ())
|
||||
) {
|
||||
return PlaceItemResult.NO_PLACE_INSIDE_PLAYER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the generated BlockData to the BlockState and update the world without physics
|
||||
blockState.setBlockData(blockData);
|
||||
blockState.update(true, false);
|
||||
|
||||
// Check if the Block is allowed to be placed
|
||||
BlockPlaceEvent blockPlaceEvent = new BlockPlaceEvent(block, oldState, against, itemStack, player, true, hand);
|
||||
Bukkit.getPluginManager().callEvent(blockCanBuildEvent);
|
||||
if (blockPlaceEvent.isCancelled() || !blockPlaceEvent.canBuild()) {
|
||||
// Reset world
|
||||
oldState.update(true, false);
|
||||
return PlaceItemResult.NO_PLACE;
|
||||
}
|
||||
|
||||
if (hasSecondBlock(blockData)) {
|
||||
// Place tht second block of a Door or Tallgrass.
|
||||
Bisected bisected = (Bisected) blockData;
|
||||
Block blockAbove = block.getRelative(0, 1, 0);
|
||||
bisected.setHalf(Bisected.Half.TOP);
|
||||
if (canPlace(blockAbove, blockData, force, usedForcePlace)) {
|
||||
if (blockData instanceof Waterlogged) {
|
||||
((Waterlogged) blockData).setWaterlogged(blockAbove.getType() == Material.WATER);
|
||||
}
|
||||
blockAbove.setBlockData(blockData, applyPhysics);
|
||||
} else {
|
||||
// If the second Block couldn't be placed remove the first Block as well
|
||||
oldState.update(true, false);
|
||||
return PlaceItemResult.NO_DOUBLE_HIGH_BLOCK_SPACE;
|
||||
}
|
||||
}
|
||||
if (applyPhysics) {
|
||||
// Apply Physics by placing the old State without Physics and setting the new with physics
|
||||
oldState.update(true, false);
|
||||
blockState.update(true, true);
|
||||
}
|
||||
|
||||
if (itemMeta instanceof BannerMeta) {
|
||||
// Apply Banner Patterns to now placed Block in World
|
||||
BannerMeta bannerMeta = (BannerMeta) itemMeta;
|
||||
Banner banner = (Banner) block.getState();
|
||||
banner.setPatterns(bannerMeta.getPatterns());
|
||||
banner.update(true, false);
|
||||
} else if (itemMeta instanceof SkullMeta) {
|
||||
// Apply Skull Data to now placed Block in World
|
||||
SkullMeta skullMeta = (SkullMeta) itemMeta;
|
||||
Skull skull = (Skull) block.getState();
|
||||
skull.setOwnerProfile(skullMeta.getOwnerProfile());
|
||||
if (skullMeta.getOwningPlayer() != null) {
|
||||
skull.setOwningPlayer(skullMeta.getOwningPlayer());
|
||||
}
|
||||
skull.update(true, false);
|
||||
}
|
||||
|
||||
if (playSound) {
|
||||
// Play the corresponding sound of placing the now placed Block
|
||||
SoundGroup soundGroup = blockData.getSoundGroup();
|
||||
block.getWorld().playSound(block.getLocation(), soundGroup.getPlaceSound(), soundGroup.getVolume() * 0.8F, soundGroup.getPitch() * 0.8F);
|
||||
}
|
||||
return usedForcePlace.get() ? PlaceItemResult.SUCCESS_FORCE : PlaceItemResult.SUCCESS;
|
||||
}
|
||||
|
||||
public BlockFace[] axis = { BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST };
|
||||
public BlockFace[] radial = { BlockFace.NORTH, BlockFace.NORTH_EAST, BlockFace.EAST, BlockFace.SOUTH_EAST, BlockFace.SOUTH, BlockFace.SOUTH_WEST, BlockFace.WEST, BlockFace.NORTH_WEST };
|
||||
|
||||
public BlockFace yawToFace(float yaw) {
|
||||
return radial[Math.round(yaw / 45f) & 0x7];
|
||||
}
|
||||
|
||||
public BlockFace yawToFaceAxis(float yaw) {
|
||||
return axis[Math.round(yaw / 90f) & 0x3];
|
||||
}
|
||||
|
||||
public BlockFace toFace(Set<BlockFace> faces, float pitch, float yaw) {
|
||||
if (faces.contains(BlockFace.UP) && pitch >= 45.0) {
|
||||
return BlockFace.UP;
|
||||
}
|
||||
if (faces.contains(BlockFace.DOWN) && pitch <= -45.0) {
|
||||
return BlockFace.DOWN;
|
||||
}
|
||||
return yawToFaceAxis(yaw);
|
||||
}
|
||||
|
||||
public BlockData toBlockData(Player player, BlockDataMeta blockDataMeta, Material material) {
|
||||
BlockData blockData;
|
||||
try {
|
||||
blockData = blockDataMeta.getBlockData(material);
|
||||
} catch (NullPointerException e) {
|
||||
// Some items have a BlockDataMeta but they cannot be converted to one like ItemFrame, those will be ignored
|
||||
return null;
|
||||
}
|
||||
|
||||
if (blockData instanceof Stairs || blockData instanceof Observer || blockData instanceof Hopper || blockData instanceof Door) {
|
||||
// Stairs, Observer, Hopper and Doors are placed the opposite way
|
||||
Directional directional = (Directional) blockData;
|
||||
BlockFace face = toFace(directional.getFaces(), player.getLocation().getPitch(), player.getLocation().getYaw());
|
||||
directional.setFacing(face.getOppositeFace());
|
||||
} else if (blockData instanceof Orientable) {
|
||||
// Orientable only have 3 Axis: X, Y, Z
|
||||
Orientable orientable = (Orientable) blockData;
|
||||
Set<BlockFace> faces = new HashSet<>();
|
||||
Set<Axis> axisSet = orientable.getAxes();
|
||||
if (axisSet.contains(Axis.X)) {
|
||||
faces.add(BlockFace.EAST);
|
||||
faces.add(BlockFace.WEST);
|
||||
}
|
||||
if (axisSet.contains(Axis.Y)) {
|
||||
faces.add(BlockFace.UP);
|
||||
faces.add(BlockFace.DOWN);
|
||||
}
|
||||
if (axisSet.contains(Axis.Z)) {
|
||||
faces.add(BlockFace.NORTH);
|
||||
faces.add(BlockFace.SOUTH);
|
||||
}
|
||||
BlockFace face = toFace(faces, player.getLocation().getPitch(), player.getLocation().getYaw());
|
||||
switch (face) {
|
||||
case EAST:
|
||||
case WEST:
|
||||
orientable.setAxis(Axis.X);
|
||||
break;
|
||||
case UP:
|
||||
case DOWN:
|
||||
orientable.setAxis(Axis.Y);
|
||||
break;
|
||||
case NORTH:
|
||||
case SOUTH:
|
||||
orientable.setAxis(Axis.Z);
|
||||
break;
|
||||
}
|
||||
} else if (blockData instanceof Rotatable) {
|
||||
Rotatable rotatable = (Rotatable) blockData;
|
||||
BlockFace blockeFace = yawToFace(player.getLocation().getYaw());
|
||||
if (blockData.getMaterial().name().endsWith("_HEAD") || blockData.getMaterial().name().endsWith("_SKULL")) {
|
||||
// Wall Heads and Wall Skulls are placed the opposite way
|
||||
rotatable.setRotation(blockeFace.getOppositeFace());
|
||||
} else {
|
||||
rotatable.setRotation(blockeFace);
|
||||
}
|
||||
} else if (blockData instanceof Directional) {
|
||||
Directional directional = (Directional) blockData;
|
||||
directional.setFacing(toFace(directional.getFaces(), player.getLocation().getPitch(), player.getLocation().getYaw()));
|
||||
} else if (blockData instanceof Rail) {
|
||||
Rail rail = (Rail) blockData;
|
||||
BlockFace face = yawToFaceAxis(player.getLocation().getYaw());
|
||||
// Rails are only represented by 2 States, North_South or East_West the remaining States will be ignored here
|
||||
rail.setShape(face == BlockFace.NORTH || face == BlockFace.SOUTH ? Rail.Shape.NORTH_SOUTH : Rail.Shape.EAST_WEST);
|
||||
}
|
||||
|
||||
return blockData;
|
||||
}
|
||||
|
||||
private BlockFace getRotation(BlockData blockData) {
|
||||
if (blockData instanceof Rotatable) {
|
||||
return ((Rotatable) blockData).getRotation();
|
||||
} else if (blockData instanceof Directional) {
|
||||
return ((Directional) blockData).getFacing();
|
||||
} else if (blockData instanceof Rail) {
|
||||
Rail rail = (Rail) blockData;
|
||||
switch (rail.getShape()) {
|
||||
case NORTH_SOUTH:
|
||||
return BlockFace.NORTH;
|
||||
case EAST_WEST:
|
||||
return BlockFace.EAST;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setRotation(BlockData blockData, BlockFace rotation) {
|
||||
if (blockData instanceof Rotatable) {
|
||||
((Rotatable) blockData).setRotation(rotation);
|
||||
} else if (blockData instanceof Directional) {
|
||||
((Directional) blockData).setFacing(rotation);
|
||||
} else if (blockData instanceof Rail) {
|
||||
Rail rail = (Rail) blockData;
|
||||
switch (rotation) {
|
||||
case NORTH:
|
||||
case SOUTH:
|
||||
rail.setShape(Rail.Shape.NORTH_SOUTH);
|
||||
break;
|
||||
case EAST:
|
||||
case WEST:
|
||||
rail.setShape(Rail.Shape.EAST_WEST);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isHitHalfTop(Player player) {
|
||||
RayTraceResult rayTraceResult = player.rayTraceBlocks(6, FluidCollisionMode.NEVER);
|
||||
if (rayTraceResult != null) {
|
||||
Vector vector = rayTraceResult.getHitPosition();
|
||||
return (vector.getY() - vector.getBlockY()) > 0.5;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasSecondBlock(BlockData blockData) {
|
||||
if (!(blockData instanceof Bisected)) {
|
||||
return false;
|
||||
}
|
||||
if (blockData instanceof Door) {
|
||||
return true;
|
||||
}
|
||||
return blockData.getClass().getName().contains("Tall");
|
||||
}
|
||||
|
||||
private boolean canPlace(Block block, BlockData blockData, boolean force, AtomicBoolean usedForcePlace) {
|
||||
if (!block.canPlace(blockData)) {
|
||||
if (force) usedForcePlace.set(true);
|
||||
return force;
|
||||
}
|
||||
return replaceables.contains(block.getType().name());
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum PlaceItemResult {
|
||||
NO_ITEM_HELD(false),
|
||||
NO_BLOCK_ITEM_HELD(false),
|
||||
NO_VALID_PLACEMENT(false),
|
||||
NO_BUILD(false),
|
||||
NO_PLACE(false),
|
||||
NO_DOUBLE_HIGH_BLOCK_SPACE(false),
|
||||
NO_PLACE_INSIDE_PLAYER(false),
|
||||
SUCCESS(true),
|
||||
SUCCESS_FORCE(true),
|
||||
;
|
||||
|
||||
private final boolean success;
|
||||
|
||||
public boolean wasForced() {
|
||||
return this == SUCCESS_FORCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.core.VersionDependent;
|
||||
import org.bukkit.Material;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public interface PlaceItemWrapper {
|
||||
Map<Material, Material> ITEM_MATERIAL_TO_BLOCK_MATERIAL = new HashMap<>();
|
||||
Map<Material, Material> BLOCK_MATERIAL_TO_WALL_BLOCK_MATERIAL = new HashMap<>();
|
||||
|
||||
PlaceItemWrapper impl = VersionDependent.getVersionImpl(BauSystem.getInstance());
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import com.comphenix.tinyprotocol.Reflection;
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.core.BountifulWrapper;
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.core.VersionDependent;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public interface PlayerMovementWrapper {
|
||||
Class<?> teleportPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityTeleport");
|
||||
Reflection.FieldAccessor<Integer> teleportEntity = Reflection.getField(teleportPacket, Integer.TYPE, 0);
|
||||
BountifulWrapper.PositionSetter teleportPosition = BountifulWrapper.impl.getPositionSetter(teleportPacket, Core.getVersion() == 8 ? 1 : 0);
|
||||
Reflection.FieldAccessor<Byte> teleportYaw = Reflection.getField(teleportPacket, Byte.TYPE, 0);
|
||||
Reflection.FieldAccessor<Byte> teleportPitch = Reflection.getField(teleportPacket, Byte.TYPE, 1);
|
||||
|
||||
PlayerMovementWrapper impl = VersionDependent.getVersionImpl(BauSystem.getInstance());
|
||||
|
||||
void setPosition(Player player, Object object);
|
||||
Object convertToOut(Player player, Object object);
|
||||
|
||||
default byte rotToByte(float rot) {
|
||||
return (byte)((int)(rot * 256.0F / 360.0F));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import de.steamwar.entity.REntity;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.bukkit.FluidCollisionMode;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.RayTraceResult;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@UtilityClass
|
||||
public class RayTraceUtils {
|
||||
|
||||
public static RRayTraceResult traceREntity(Player player, Location to, List<REntity> entityList) {
|
||||
if (player.getGameMode() == GameMode.SPECTATOR) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Location startPos = to.clone().add(0.0, player.getEyeHeight(), 0.0);
|
||||
Vector direction = to.getDirection();
|
||||
RayTraceResult blocks = player.getWorld().rayTraceBlocks(startPos, direction, 10.0, FluidCollisionMode.NEVER, true);
|
||||
|
||||
REntity nearestHitEntity = null;
|
||||
RRayTraceResult nearestHitResult = null;
|
||||
double nearestDistanceSq = Double.MAX_VALUE;
|
||||
for (REntity entity: entityList) {
|
||||
if (!isOccluded(startPos.toVector(), direction, new Vector(entity.getX(), entity.getY() + 0.5, entity.getZ()))) continue;
|
||||
double distanceSq = new Vector(entity.getX(), entity.getY() + 0.5, entity.getZ()).distanceSquared(startPos.toVector());
|
||||
if (distanceSq > 100.0) continue;
|
||||
if (distanceSq < nearestDistanceSq) {
|
||||
nearestHitEntity = entity;
|
||||
nearestHitResult = new RRayTraceResult(new Vector(entity.getX(), entity.getY() + 0.5, entity.getZ()), null, null, entity);
|
||||
nearestDistanceSq = distanceSq;
|
||||
}
|
||||
}
|
||||
RRayTraceResult entities = nearestHitEntity == null ? null : new RRayTraceResult(nearestHitResult.getHitPosition(), nearestHitResult.getHitBlock(), nearestHitResult.getHitBlockFace(), nearestHitEntity);
|
||||
|
||||
if (blocks == null) {
|
||||
return entities;
|
||||
} else if (entities == null) {
|
||||
return RRayTraceResult.fromRayTraceResult(blocks);
|
||||
} else {
|
||||
Vector startVec = startPos.toVector();
|
||||
double blockHitDistance = startVec.distance(blocks.getHitPosition());
|
||||
double entityHitDistanceSquared = startVec.distanceSquared(entities.getHitPosition());
|
||||
return entityHitDistanceSquared < blockHitDistance * blockHitDistance ? entities : RRayTraceResult.fromRayTraceResult(blocks);
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class RRayTraceResult {
|
||||
private final Vector hitPosition;
|
||||
private final Block hitBlock;
|
||||
private final BlockFace hitBlockFace;
|
||||
private final REntity hitEntity;
|
||||
|
||||
public static RRayTraceResult fromRayTraceResult(RayTraceResult rayTraceResult) {
|
||||
return new RRayTraceResult(rayTraceResult.getHitPosition(), rayTraceResult.getHitBlock(), rayTraceResult.getHitBlockFace(), null);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isOccluded(Vector a, Vector n, Vector b) {
|
||||
// a = Head pos, n = View direction (normalized), b = entity center
|
||||
// https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Vector_formulation
|
||||
|
||||
double abX = b.getX() - a.getX();
|
||||
double abY = b.getY() - a.getY();
|
||||
double abZ = b.getZ() - a.getZ();
|
||||
double lambda = abX * n.getX() + abY * n.getY() + abZ * n.getZ();
|
||||
double distX = abX - n.getX() * lambda;
|
||||
double distY = abY - n.getY() * lambda;
|
||||
double distZ = abZ - n.getZ() * lambda;
|
||||
return Math.abs(distX) < 0.5 && Math.abs(distY) < 0.5 && Math.abs(distZ) < 0.5;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import de.steamwar.bausystem.region.Region;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public interface ScoreboardElement {
|
||||
ScoreboardGroup getGroup();
|
||||
int order();
|
||||
|
||||
String get(Region region, Player p);
|
||||
|
||||
enum ScoreboardGroup {
|
||||
HEADER,
|
||||
REGION,
|
||||
OTHER,
|
||||
FOOTER
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
public class TickEndEvent extends Event {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.core.VersionDependent;
|
||||
|
||||
public interface TickListener {
|
||||
|
||||
TickListener impl = VersionDependent.getVersionImpl(BauSystem.getInstance());
|
||||
|
||||
default void init() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
public class TickStartEvent extends Event {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.region.Region;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
||||
@Linked
|
||||
public class TimeScoreboardElement implements ScoreboardElement {
|
||||
|
||||
@Override
|
||||
public ScoreboardGroup getGroup() {
|
||||
return ScoreboardGroup.HEADER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int order() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(Region region, Player p) {
|
||||
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TIME", p) + "§8: §7" + new SimpleDateFormat(BauSystem.MESSAGE.parse("TIME", p)).format(Calendar.getInstance().getTime());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.IncompleteRegionException;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.extension.factory.PatternFactory;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.internal.registry.InputParser;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.regions.RegionSelector;
|
||||
import de.steamwar.bausystem.shared.Pair;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@UtilityClass
|
||||
public class WorldEditUtils {
|
||||
|
||||
public EditSession getEditSession(Player player) {
|
||||
return WorldEdit.getInstance().getEditSessionFactory().getEditSession(BukkitAdapter.adapt(player.getWorld()), -1, BukkitAdapter.adapt(player));
|
||||
}
|
||||
|
||||
public void addToPlayer(Player player, EditSession editSession) {
|
||||
WorldEdit.getInstance().getSessionManager().get(BukkitAdapter.adapt(player)).remember(editSession);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public Region getRegion(Player player) {
|
||||
RegionSelector regionSelector = WorldEdit.getInstance()
|
||||
.getSessionManager()
|
||||
.get(BukkitAdapter.adapt(player))
|
||||
.getRegionSelector(BukkitAdapter.adapt(player.getWorld()));
|
||||
return regionSelector.getRegion();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public Mask getMask(Player player) {
|
||||
return WorldEdit.getInstance()
|
||||
.getSessionManager()
|
||||
.get(BukkitAdapter.adapt(player))
|
||||
.getMask();
|
||||
}
|
||||
|
||||
public void addMaskParser(InputParser<Mask> maskInputParser) {
|
||||
WorldEdit.getInstance().getMaskFactory().register(maskInputParser);
|
||||
}
|
||||
|
||||
public void addPatternParser(InputParser<Pattern> patternInputParser) {
|
||||
WorldEdit.getInstance().getPatternFactory().register(patternInputParser);
|
||||
}
|
||||
|
||||
public PatternFactory getPatternFactory() {
|
||||
return WorldEdit.getInstance().getPatternFactory();
|
||||
}
|
||||
|
||||
public Pair<Location, Location> getSelection(Player player) {
|
||||
RegionSelector regionSelector = WorldEdit.getInstance()
|
||||
.getSessionManager()
|
||||
.get(BukkitAdapter.adapt(player))
|
||||
.getRegionSelector(BukkitAdapter.adapt(player.getWorld()));
|
||||
|
||||
try {
|
||||
BlockVector3 min = regionSelector.getRegion().getMinimumPoint();
|
||||
BlockVector3 max = regionSelector.getRegion().getMaximumPoint();
|
||||
return new Pair<>(adapt(player.getWorld(), min), adapt(player.getWorld(), max));
|
||||
} catch (IncompleteRegionException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Location adapt(World world, BlockVector3 blockVector3) {
|
||||
return new Location(world, blockVector3.getBlockX(), blockVector3.getBlockY(), blockVector3.getBlockZ());
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils.bossbar;
|
||||
|
||||
import de.steamwar.bausystem.region.Region;
|
||||
import org.bukkit.boss.BarColor;
|
||||
import org.bukkit.boss.BarFlag;
|
||||
import org.bukkit.boss.BarStyle;
|
||||
|
||||
public interface BauSystemBossbar {
|
||||
|
||||
String getTitle();
|
||||
void setTitle(String title);
|
||||
|
||||
double getProgress();
|
||||
void setProgress(double progress);
|
||||
|
||||
BarColor getColor();
|
||||
void setColor(BarColor color);
|
||||
|
||||
BarStyle getStyle();
|
||||
void setStyle(BarStyle style);
|
||||
|
||||
boolean hasFlag(BarFlag flag);
|
||||
void addFlag(BarFlag flag);
|
||||
void removeFlag(BarFlag flag);
|
||||
|
||||
boolean isVisible();
|
||||
void setVisible(boolean visible);
|
||||
|
||||
Region getRegion();
|
||||
|
||||
void cleanup();
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils.bossbar;
|
||||
|
||||
import de.steamwar.bausystem.region.Region;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.boss.BarColor;
|
||||
import org.bukkit.boss.BarStyle;
|
||||
import org.bukkit.boss.BossBar;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Linked
|
||||
public class BossBarService implements Listener {
|
||||
|
||||
public static BossBarService instance;
|
||||
|
||||
public BossBarService() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
private final Map<Player, Map<Region, Map<String, BauSystemBossbar>>> playerBossBars = new HashMap<>();
|
||||
|
||||
public synchronized BauSystemBossbar get(Player player, Region region, String key) {
|
||||
return playerBossBars.computeIfAbsent(player, p -> new HashMap<>())
|
||||
.computeIfAbsent(region, r -> new HashMap<>())
|
||||
.computeIfAbsent(key, k -> {
|
||||
BossBar bossBar = Bukkit.createBossBar("", BarColor.WHITE, BarStyle.SOLID);
|
||||
bossBar.addPlayer(player);
|
||||
if (region.isGlobal()) {
|
||||
return new GlobalBossbar(bossBar);
|
||||
} else {
|
||||
return new RegionedBossbar(bossBar, region, player);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public synchronized void removeAll(Player player, String key) {
|
||||
Map<Region, Map<String, BauSystemBossbar>> regionMap = playerBossBars.get(player);
|
||||
if (regionMap == null) return;
|
||||
for (Map<String, BauSystemBossbar> bossBarMap : regionMap.values()) {
|
||||
BauSystemBossbar bossBar = bossBarMap.remove(key);
|
||||
if (bossBar == null) continue;
|
||||
bossBar.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void removeAll(Player player) {
|
||||
Map<Region, Map<String, BauSystemBossbar>> regionMap = playerBossBars.remove(player);
|
||||
if (regionMap == null) return;
|
||||
for (Map<String, BauSystemBossbar> bossBarMap : regionMap.values()) {
|
||||
for (BauSystemBossbar bossBar : bossBarMap.values()) {
|
||||
bossBar.cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void remove(Player player, Region region, String key) {
|
||||
Map<Region, Map<String, BauSystemBossbar>> regionMap = playerBossBars.get(player);
|
||||
if (regionMap == null) return;
|
||||
Map<String, BauSystemBossbar> bossBarMap = regionMap.get(region);
|
||||
if (bossBarMap == null) return;
|
||||
BauSystemBossbar bossBar = bossBarMap.remove(key);
|
||||
if (bossBar == null) return;
|
||||
bossBar.cleanup();
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
removeAll(event.getPlayer());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils.bossbar;
|
||||
|
||||
import de.steamwar.bausystem.region.GlobalRegion;
|
||||
import de.steamwar.bausystem.region.Region;
|
||||
import org.bukkit.boss.BarColor;
|
||||
import org.bukkit.boss.BarFlag;
|
||||
import org.bukkit.boss.BarStyle;
|
||||
import org.bukkit.boss.BossBar;
|
||||
|
||||
public class GlobalBossbar implements BauSystemBossbar {
|
||||
|
||||
private BossBar bossBar;
|
||||
|
||||
public GlobalBossbar(BossBar bossBar) {
|
||||
this.bossBar = bossBar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return bossBar.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(String title) {
|
||||
bossBar.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getProgress() {
|
||||
return bossBar.getProgress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgress(double progress) {
|
||||
bossBar.setProgress(progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BarColor getColor() {
|
||||
return bossBar.getColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColor(BarColor color) {
|
||||
bossBar.setColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BarStyle getStyle() {
|
||||
return bossBar.getStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyle(BarStyle style) {
|
||||
bossBar.setStyle(style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFlag(BarFlag flag) {
|
||||
return bossBar.hasFlag(flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFlag(BarFlag flag) {
|
||||
bossBar.addFlag(flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFlag(BarFlag flag) {
|
||||
bossBar.removeFlag(flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
return bossBar.isVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
bossBar.setVisible(visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region getRegion() {
|
||||
return GlobalRegion.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
bossBar.removeAll();
|
||||
bossBar = null;
|
||||
}
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils.bossbar;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.region.Region;
|
||||
import de.steamwar.bausystem.region.utils.RegionExtensionType;
|
||||
import de.steamwar.bausystem.region.utils.RegionType;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.boss.BarColor;
|
||||
import org.bukkit.boss.BarFlag;
|
||||
import org.bukkit.boss.BarStyle;
|
||||
import org.bukkit.boss.BossBar;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
public class RegionedBossbar implements BauSystemBossbar, Listener {
|
||||
|
||||
private BossBar bossBar;
|
||||
private Region region;
|
||||
private Player player;
|
||||
|
||||
public RegionedBossbar(BossBar bossBar, Region region, Player player) {
|
||||
this.bossBar = bossBar;
|
||||
this.region = region;
|
||||
this.player = player;
|
||||
Bukkit.getPluginManager().registerEvents(this, BauSystem.getInstance());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return bossBar.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(String title) {
|
||||
bossBar.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getProgress() {
|
||||
return bossBar.getProgress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgress(double progress) {
|
||||
bossBar.setProgress(progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BarColor getColor() {
|
||||
return bossBar.getColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColor(BarColor color) {
|
||||
bossBar.setColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BarStyle getStyle() {
|
||||
return bossBar.getStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyle(BarStyle style) {
|
||||
bossBar.setStyle(style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFlag(BarFlag flag) {
|
||||
return bossBar.hasFlag(flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFlag(BarFlag flag) {
|
||||
bossBar.addFlag(flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFlag(BarFlag flag) {
|
||||
bossBar.removeFlag(flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
return bossBar.isVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
bossBar.setVisible(visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region getRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
if (event.getPlayer() != player) return;
|
||||
if (region.inRegion(event.getTo(), RegionType.NORMAL, RegionExtensionType.NORMAL)) {
|
||||
bossBar.addPlayer(player);
|
||||
} else {
|
||||
bossBar.removePlayer(player);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
if (event.getPlayer() != player) return;
|
||||
cleanup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
if (bossBar != null) {
|
||||
bossBar.removeAll();
|
||||
bossBar = null;
|
||||
}
|
||||
region = null;
|
||||
player = null;
|
||||
|
||||
PlayerMoveEvent.getHandlerList().unregister(this);
|
||||
PlayerQuitEvent.getHandlerList().unregister(this);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user