PlotSquared/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java

577 lines
24 KiB
Java
Raw Normal View History

/*
* PlotSquared, a land and world management plugin for Minecraft.
* Copyright (C) IntellectualSites <https://intellectualsites.com>
* Copyright (C) IntellectualSites team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
2020-04-11 02:19:18 +02:00
package com.plotsquared.bukkit.util;
2015-02-19 07:08:15 +01:00
2020-07-10 22:12:37 +02:00
import com.google.inject.Singleton;
import com.plotsquared.bukkit.BukkitPlatform;
2020-04-11 02:19:18 +02:00
import com.plotsquared.bukkit.player.BukkitPlayer;
import com.plotsquared.bukkit.player.BukkitPlayerManager;
2020-04-15 21:26:54 +02:00
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.caption.Caption;
2020-07-09 12:58:28 +02:00
import com.plotsquared.core.configuration.caption.LocaleHolder;
2020-04-15 21:26:54 +02:00
import com.plotsquared.core.location.Location;
import com.plotsquared.core.player.PlotPlayer;
2021-05-21 19:14:13 +02:00
import com.plotsquared.core.plot.PlotArea;
2020-04-20 23:40:04 +02:00
import com.plotsquared.core.util.BlockUtil;
2020-04-15 21:26:54 +02:00
import com.plotsquared.core.util.MathMan;
import com.plotsquared.core.util.PlayerManager;
2020-04-15 21:26:54 +02:00
import com.plotsquared.core.util.StringComparison;
2020-04-20 23:40:04 +02:00
import com.plotsquared.core.util.WorldUtil;
2020-04-15 21:26:54 +02:00
import com.plotsquared.core.util.task.TaskManager;
2019-11-04 20:58:24 +01:00
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockCategories;
2019-11-04 20:58:24 +01:00
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import io.papermc.lib.PaperLib;
2020-07-05 18:14:29 +02:00
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
2020-07-09 12:58:28 +02:00
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.Template;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
2021-08-18 11:58:18 +02:00
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
2016-03-14 03:44:59 +01:00
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
2016-03-14 03:44:59 +01:00
import org.bukkit.Material;
import org.bukkit.World;
2019-08-06 22:08:56 +02:00
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Sign;
2019-04-23 23:30:31 +02:00
import org.bukkit.block.data.Directional;
2019-09-09 00:43:47 +02:00
import org.bukkit.block.data.type.WallSign;
2020-04-12 00:57:50 +02:00
import org.bukkit.entity.Ambient;
import org.bukkit.entity.Animals;
2020-04-12 01:23:13 +02:00
import org.bukkit.entity.AreaEffectCloud;
2020-04-12 00:57:50 +02:00
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Boss;
2020-04-12 00:57:50 +02:00
import org.bukkit.entity.EnderCrystal;
2020-04-12 01:23:13 +02:00
import org.bukkit.entity.EnderSignal;
2015-02-19 11:12:26 +01:00
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
2020-04-12 01:23:13 +02:00
import org.bukkit.entity.EvokerFangs;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.entity.Explosive;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Firework;
2020-04-12 00:57:50 +02:00
import org.bukkit.entity.Ghast;
import org.bukkit.entity.Hanging;
2020-04-12 04:46:51 +02:00
import org.bukkit.entity.IronGolem;
2020-04-12 01:23:13 +02:00
import org.bukkit.entity.Item;
import org.bukkit.entity.LightningStrike;
import org.bukkit.entity.Monster;
2020-04-12 00:57:50 +02:00
import org.bukkit.entity.NPC;
import org.bukkit.entity.Phantom;
2015-02-19 11:12:26 +01:00
import org.bukkit.entity.Player;
2020-04-12 00:57:50 +02:00
import org.bukkit.entity.Projectile;
2020-04-12 04:46:51 +02:00
import org.bukkit.entity.Shulker;
import org.bukkit.entity.Slime;
2020-04-12 04:46:51 +02:00
import org.bukkit.entity.Snowman;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.Vehicle;
2020-04-12 00:57:50 +02:00
import org.bukkit.entity.WaterMob;
import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
2018-12-20 00:26:20 +01:00
import java.util.Collection;
2019-08-06 22:08:56 +02:00
import java.util.HashSet;
import java.util.Objects;
2019-08-06 22:08:56 +02:00
import java.util.Set;
2020-07-24 13:18:36 +02:00
import java.util.concurrent.Semaphore;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
import java.util.stream.Stream;
2016-03-23 02:41:37 +01:00
@SuppressWarnings({"unused", "WeakerAccess"})
@Singleton
public class BukkitUtil extends WorldUtil {
2020-07-17 23:06:40 +02:00
public static final BukkitAudiences BUKKIT_AUDIENCES = BukkitAudiences.create(BukkitPlatform.getPlugin(BukkitPlatform.class));
2020-08-17 15:08:21 +02:00
public static final LegacyComponentSerializer LEGACY_COMPONENT_SERIALIZER = LegacyComponentSerializer.legacySection();
2020-07-09 12:58:28 +02:00
public static final MiniMessage MINI_MESSAGE = MiniMessage.builder().build();
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + BukkitUtil.class.getSimpleName());
private final Collection<BlockType> tileEntityTypes = new HashSet<>();
/**
* Turn a Bukkit {@link Player} into a PlotSquared {@link PlotPlayer}
*
* @param player Bukkit player
* @return PlotSquared player
*/
2021-01-10 00:01:48 +01:00
public static @NonNull BukkitPlayer adapt(final @NonNull Player player) {
final PlayerManager<?, ?> playerManager = PlotSquared.platform().playerManager();
return ((BukkitPlayerManager) playerManager).getPlayer(player);
}
/**
* Turn a Bukkit {@link org.bukkit.Location} into a PlotSquared {@link Location}.
* This only copies the 4-tuple (world,x,y,z) and does not include the yaw and the pitch
*
* @param location Bukkit location
* @return PlotSquared location
*/
2021-01-10 00:01:48 +01:00
public static @NonNull Location adapt(final org.bukkit.@NonNull Location location) {
2020-07-24 17:24:53 +02:00
return Location
2021-08-18 11:58:18 +02:00
.at(
com.plotsquared.bukkit.util.BukkitWorld.of(location.getWorld()),
MathMan.roundInt(location.getX()),
MathMan.roundInt(location.getY()),
MathMan.roundInt(location.getZ())
);
}
/**
* Turn a Bukkit {@link org.bukkit.Location} into a PlotSquared {@link Location}.
* This copies the entire 6-tuple (world,x,y,z,yaw,pitch).
Merge branch 'master' into breaking # Conflicts: # Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/events/PlotRateEvent.java # Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitEventUtil.java # Core/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotSquared.java # Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Add.java # Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Auto.java # Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Delete.java # Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Kick.java # Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Load.java # Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Music.java # Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Owner.java # Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Rate.java # Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Reload.java # Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SchematicCmd.java # Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Trust.java # Core/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/GameModeFlag.java # Core/src/main/java/com/intellectualcrafters/plot/commands/Clear.java # Core/src/main/java/com/intellectualcrafters/plot/commands/PluginCmd.java # Core/src/main/java/com/intellectualcrafters/plot/commands/Relight.java # Core/src/main/java/com/intellectualcrafters/plot/commands/SetHome.java # Core/src/main/java/com/intellectualcrafters/plot/config/C.java # Core/src/main/java/com/intellectualcrafters/plot/config/Configuration.java # Core/src/main/java/com/intellectualcrafters/plot/config/Settings.java # Core/src/test/java/com/github/intellectualsites/plotsquared/plot/util/EventUtilTest.java # Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitEventUtil.java # README.md # Sponge/src/main/java/com/github/intellectualsites/plotsquared/sponge/events/PlotRateEvent.java # Sponge/src/main/java/com/github/intellectualsites/plotsquared/sponge/util/SpongeSchematicHandler.java # Sponge/src/main/java/com/github/intellectualsites/plotsquared/sponge/util/block/SpongeLocalQueue.java # Sponge/src/main/java/com/plotsquared/sponge/util/SpongeEventUtil.java
2018-11-14 15:44:07 +01:00
*
* @param location Bukkit location
* @return PlotSquared location
*/
2021-01-10 00:01:48 +01:00
public static @NonNull Location adaptComplete(final org.bukkit.@NonNull Location location) {
2020-07-24 17:24:53 +02:00
return Location
2021-08-18 11:58:18 +02:00
.at(
com.plotsquared.bukkit.util.BukkitWorld.of(location.getWorld()),
MathMan.roundInt(location.getX()),
MathMan.roundInt(location.getY()),
MathMan.roundInt(location.getZ()),
location.getYaw(),
location.getPitch()
);
}
/**
* Turn a PlotSquared {@link Location} into a Bukkit {@link org.bukkit.Location}.
* This only copies the 4-tuple (world,x,y,z) and does not include the yaw and the pitch
*
* @param location PlotSquared location
* @return Bukkit location
*/
public static org.bukkit.@NonNull Location adapt(final @NonNull Location location) {
return new org.bukkit.Location(
(World) location.getWorld().getPlatformWorld(),
location.getX(),
location.getY(),
location.getZ()
);
}
/**
* Get a Bukkit {@link World} from its name
*
* @param string World name
* @return World if it exists, or {@code null}
*/
2021-01-10 00:01:48 +01:00
public static @Nullable World getWorld(final @NonNull String string) {
return Bukkit.getWorld(string);
}
private static void ensureLoaded(
final @NonNull String world,
final int x,
final int z,
final @NonNull Consumer<Chunk> chunkConsumer
) {
2020-07-24 13:18:36 +02:00
PaperLib.getChunkAtAsync(Objects.requireNonNull(getWorld(world)), x >> 4, z >> 4, true)
.thenAccept(chunk -> ensureMainThread(chunkConsumer, chunk));
}
private static void ensureLoaded(final @NonNull Location location, final @NonNull Consumer<Chunk> chunkConsumer) {
2020-07-24 17:24:53 +02:00
PaperLib.getChunkAtAsync(adapt(location), true).thenAccept(chunk -> ensureMainThread(chunkConsumer, chunk));
}
private static <T> void ensureMainThread(final @NonNull Consumer<T> consumer, final @NonNull T value) {
if (Bukkit.isPrimaryThread()) {
consumer.accept(value);
} else {
2020-07-24 17:24:53 +02:00
Bukkit.getScheduler().runTask(BukkitPlatform.getPlugin(BukkitPlatform.class), () -> consumer.accept(value));
}
}
@Override
public boolean isBlockSame(final @NonNull BlockState block1, final @NonNull BlockState block2) {
2018-12-20 00:26:20 +01:00
if (block1.equals(block2)) {
return true;
}
final Material mat1 = BukkitAdapter.adapt(block1.getBlockType());
final Material mat2 = BukkitAdapter.adapt(block2.getBlockType());
2018-12-20 00:26:20 +01:00
return mat1 == mat2;
}
@Override
public boolean isWorld(final @NonNull String worldName) {
2016-03-29 21:47:59 +02:00
return getWorld(worldName) != null;
2015-07-20 07:14:46 +02:00
}
@Override
public void getBiome(final @NonNull String world, final int x, final int z, final @NonNull Consumer<BiomeType> result) {
2020-07-24 17:24:53 +02:00
ensureLoaded(world, x, z, chunk -> result.accept(BukkitAdapter.adapt(getWorld(world).getBiome(x, z))));
}
@Override
public @NonNull BiomeType getBiomeSynchronous(final @NonNull String world, final int x, final int z) {
return BukkitAdapter.adapt(Objects.requireNonNull(getWorld(world)).getBiome(x, z));
2015-02-23 12:37:36 +01:00
}
@Override
public void getHighestBlock(final @NonNull String world, final int x, final int z, final @NonNull IntConsumer result) {
ensureLoaded(world, x, z, chunk -> {
final World bukkitWorld = Objects.requireNonNull(getWorld(world));
// Skip top and bottom block
int air = 1;
Implement extended world heights from Y-64 to Y319 #3473 (#3473) * Begin to implement extended world heights: - Implemented in Bukkit module (and where required in Core module) * Implement extended world heights into core module * Add min gen height to setup, * Default gen/build heights based on minecraft version * Few fixes * Fix up queues * Address comments * Make road schematic stuff slightly more efficient by sharing queues * Minor fixes, don't overlay error many times for the same y * Fix incorrect schematic paste height, undo changes to HybridUtils * Overhall regenallroads method to make it work, make sure BukkitChunkCoordinator can/will finish * Process chunks in order when regenerating all roads * Address comments * Address comments * Ground level//bedrock is at min gen height - Add comment on == rather than <= being used - It's because it's only checking for the bedrock layer being broken if that's disabled * Fix offset for min build height in SchematicHandler * Better javadoc Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com> * Address inclusivity issues for max world height * Javadocs/comments/deprecation * Use world min/max heights if present in QueueCoordinator * Address some deprecations for regions and biome setting * Add a count for chunks we're currently trying to load to not skip chunks at the end of a queue's edit * Use minGenHeight + 1 rather than build height in AugmentedUtils * Create utility method for layer index in GenChunk * Correct height in HybridUtils, also use minGenHeight + 1 * Don't magically split to 128 height in regeneration * Add utility methods for world height in QueueCoordinator * Clean up ClassicPlotManager road creation/removal * Start generation at min gen height if bedrock is disabled * min gen height is set in PlotArea * Add note on schem y normalisation * Improve plot getVolume method readability * Don't overly extend height when regenerating road region * y index utility method in ChunknQueueCoordinator * Layer index utility method in LocalChunk * Use version min/max heights if world not present in QueueCoordinator * Fix min -> max * Don't allow players to modify outside build height when using plot set / schematics. - Also fixes schematic height issues * Remove debug * Address comments * Switch loadingChunks to AtomicInteger to be safe (in case of multi-threaded) * Fix "security" issue that was already present * Ensure sign isn't physicsed Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com>
2022-03-05 19:03:39 +01:00
int maxY = com.plotsquared.bukkit.util.BukkitWorld.getMaxWorldHeight(bukkitWorld);
int minY = com.plotsquared.bukkit.util.BukkitWorld.getMinWorldHeight(bukkitWorld);
for (int y = maxY - 1; y >= minY; y--) {
Block block = bukkitWorld.getBlockAt(x, y, z);
Material type = block.getType();
if (type.isSolid()) {
if (air > 1) {
result.accept(y);
return;
}
air = 0;
} else {
if (block.isLiquid()) {
result.accept(y);
return;
}
air++;
}
}
result.accept(bukkitWorld.getMaxHeight() - 1);
});
}
@Override
@NonNegative
public int getHighestBlockSynchronous(final @NonNull String world, final int x, final int z) {
final World bukkitWorld = Objects.requireNonNull(getWorld(world));
// Skip top and bottom block
int air = 1;
Implement extended world heights from Y-64 to Y319 #3473 (#3473) * Begin to implement extended world heights: - Implemented in Bukkit module (and where required in Core module) * Implement extended world heights into core module * Add min gen height to setup, * Default gen/build heights based on minecraft version * Few fixes * Fix up queues * Address comments * Make road schematic stuff slightly more efficient by sharing queues * Minor fixes, don't overlay error many times for the same y * Fix incorrect schematic paste height, undo changes to HybridUtils * Overhall regenallroads method to make it work, make sure BukkitChunkCoordinator can/will finish * Process chunks in order when regenerating all roads * Address comments * Address comments * Ground level//bedrock is at min gen height - Add comment on == rather than <= being used - It's because it's only checking for the bedrock layer being broken if that's disabled * Fix offset for min build height in SchematicHandler * Better javadoc Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com> * Address inclusivity issues for max world height * Javadocs/comments/deprecation * Use world min/max heights if present in QueueCoordinator * Address some deprecations for regions and biome setting * Add a count for chunks we're currently trying to load to not skip chunks at the end of a queue's edit * Use minGenHeight + 1 rather than build height in AugmentedUtils * Create utility method for layer index in GenChunk * Correct height in HybridUtils, also use minGenHeight + 1 * Don't magically split to 128 height in regeneration * Add utility methods for world height in QueueCoordinator * Clean up ClassicPlotManager road creation/removal * Start generation at min gen height if bedrock is disabled * min gen height is set in PlotArea * Add note on schem y normalisation * Improve plot getVolume method readability * Don't overly extend height when regenerating road region * y index utility method in ChunknQueueCoordinator * Layer index utility method in LocalChunk * Use version min/max heights if world not present in QueueCoordinator * Fix min -> max * Don't allow players to modify outside build height when using plot set / schematics. - Also fixes schematic height issues * Remove debug * Address comments * Switch loadingChunks to AtomicInteger to be safe (in case of multi-threaded) * Fix "security" issue that was already present * Ensure sign isn't physicsed Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com>
2022-03-05 19:03:39 +01:00
int maxY = com.plotsquared.bukkit.util.BukkitWorld.getMaxWorldHeight(bukkitWorld);
int minY = com.plotsquared.bukkit.util.BukkitWorld.getMinWorldHeight(bukkitWorld);
for (int y = maxY - 1; y >= minY; y--) {
Block block = bukkitWorld.getBlockAt(x, y, z);
2019-08-06 22:08:56 +02:00
Material type = block.getType();
if (type.isSolid()) {
if (air > 1) {
return y;
}
2019-08-06 22:08:56 +02:00
air = 0;
} else {
if (block.isLiquid()) {
return y;
}
air++;
}
2015-02-19 07:08:15 +01:00
}
return bukkitWorld.getMaxHeight() - 1;
2015-02-19 07:08:15 +01:00
}
@Override
public @NonNull String[] getSignSynchronous(final @NonNull Location location) {
Block block = Objects.requireNonNull(getWorld(location.getWorldName())).getBlockAt(
location.getX(),
location.getY(),
location.getZ()
);
2020-07-17 16:25:57 +02:00
try {
2020-07-17 16:38:07 +02:00
return TaskManager.getPlatformImplementation().sync(() -> {
if (block.getState() instanceof Sign sign) {
2020-07-17 16:25:57 +02:00
return sign.getLines();
2019-11-05 16:23:48 +01:00
}
2020-07-17 16:25:57 +02:00
return new String[0];
});
} catch (final Exception e) {
e.printStackTrace();
}
return new String[0];
2015-02-22 07:30:58 +01:00
}
@Override
public @NonNull Location getSpawn(final @NonNull String world) {
2018-08-10 20:54:17 +02:00
final org.bukkit.Location temp = getWorld(world).getSpawnLocation();
2020-07-24 17:24:53 +02:00
return Location.at(world, temp.getBlockX(), temp.getBlockY(), temp.getBlockZ(), temp.getYaw(), temp.getPitch());
2015-02-22 07:56:46 +01:00
}
@Override
public void setSpawn(final @NonNull Location location) {
final World world = getWorld(location.getWorldName());
if (world != null) {
2016-03-23 02:41:37 +01:00
world.setSpawnLocation(location.getX(), location.getY(), location.getZ());
}
}
@Override
public void saveWorld(final @NonNull String worldName) {
2018-08-10 20:54:17 +02:00
final World world = getWorld(worldName);
if (world != null) {
world.save();
}
}
@Override
@SuppressWarnings("deprecation")
public void setSign(
final @NonNull Location location, final @NonNull Caption[] lines,
final @NonNull Template... replacements
) {
ensureLoaded(location.getWorldName(), location.getX(), location.getZ(), chunk -> {
2021-05-21 19:14:13 +02:00
PlotArea area = location.getPlotArea();
final World world = getWorld(location.getWorldName());
2020-07-09 12:58:28 +02:00
final Block block = world.getBlockAt(location.getX(), location.getY(), location.getZ());
final Material type = block.getType();
if (type != Material.LEGACY_SIGN && type != Material.LEGACY_WALL_SIGN) {
BlockFace facing = BlockFace.NORTH;
if (!world.getBlockAt(location.getX(), location.getY(), location.getZ() + 1).getType().isSolid()) {
if (world.getBlockAt(location.getX() - 1, location.getY(), location.getZ()).getType().isSolid()) {
facing = BlockFace.EAST;
} else if (world.getBlockAt(location.getX() + 1, location.getY(), location.getZ()).getType().isSolid()) {
facing = BlockFace.WEST;
} else if (world.getBlockAt(location.getX(), location.getY(), location.getZ() - 1).getType().isSolid()) {
facing = BlockFace.SOUTH;
}
}
if (PlotSquared.platform().serverVersion()[1] == 13) {
block.setType(Material.valueOf(area.legacySignMaterial()), false);
} else {
2021-05-21 19:14:13 +02:00
block.setType(Material.valueOf(area.signMaterial()), false);
}
if (!(block.getBlockData() instanceof WallSign)) {
throw new RuntimeException("Something went wrong generating a sign");
}
final Directional sign = (Directional) block.getBlockData();
sign.setFacing(facing);
block.setBlockData(sign, false);
}
final org.bukkit.block.BlockState blockstate = block.getState();
if (blockstate instanceof final Sign sign) {
for (int i = 0; i < lines.length; i++) {
2020-07-09 12:58:28 +02:00
sign.setLine(i, LEGACY_COMPONENT_SERIALIZER
.serialize(MINI_MESSAGE.parse(lines[i].getComponent(LocaleHolder.console()), replacements)));
}
Implement extended world heights from Y-64 to Y319 #3473 (#3473) * Begin to implement extended world heights: - Implemented in Bukkit module (and where required in Core module) * Implement extended world heights into core module * Add min gen height to setup, * Default gen/build heights based on minecraft version * Few fixes * Fix up queues * Address comments * Make road schematic stuff slightly more efficient by sharing queues * Minor fixes, don't overlay error many times for the same y * Fix incorrect schematic paste height, undo changes to HybridUtils * Overhall regenallroads method to make it work, make sure BukkitChunkCoordinator can/will finish * Process chunks in order when regenerating all roads * Address comments * Address comments * Ground level//bedrock is at min gen height - Add comment on == rather than <= being used - It's because it's only checking for the bedrock layer being broken if that's disabled * Fix offset for min build height in SchematicHandler * Better javadoc Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com> * Address inclusivity issues for max world height * Javadocs/comments/deprecation * Use world min/max heights if present in QueueCoordinator * Address some deprecations for regions and biome setting * Add a count for chunks we're currently trying to load to not skip chunks at the end of a queue's edit * Use minGenHeight + 1 rather than build height in AugmentedUtils * Create utility method for layer index in GenChunk * Correct height in HybridUtils, also use minGenHeight + 1 * Don't magically split to 128 height in regeneration * Add utility methods for world height in QueueCoordinator * Clean up ClassicPlotManager road creation/removal * Start generation at min gen height if bedrock is disabled * min gen height is set in PlotArea * Add note on schem y normalisation * Improve plot getVolume method readability * Don't overly extend height when regenerating road region * y index utility method in ChunknQueueCoordinator * Layer index utility method in LocalChunk * Use version min/max heights if world not present in QueueCoordinator * Fix min -> max * Don't allow players to modify outside build height when using plot set / schematics. - Also fixes schematic height issues * Remove debug * Address comments * Switch loadingChunks to AtomicInteger to be safe (in case of multi-threaded) * Fix "security" issue that was already present * Ensure sign isn't physicsed Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com>
2022-03-05 19:03:39 +01:00
sign.update(true, false);
}
});
}
@Override
public @NonNull StringComparison<BlockState>.ComparisonResult getClosestBlock(@NonNull String name) {
2019-11-04 20:55:55 +01:00
BlockState state = BlockUtil.get(name);
return new StringComparison<BlockState>().new ComparisonResult(1, state);
}
@Override
public com.sk89q.worldedit.world.@NonNull World getWeWorld(final @NonNull String world) {
return new BukkitWorld(Bukkit.getWorld(world));
}
@Override
public void refreshChunk(int x, int z, String world) {
Bukkit.getWorld(world).refreshChunk(x, z);
}
@Override
public void getBlock(final @NonNull Location location, final @NonNull Consumer<BlockState> result) {
ensureLoaded(location, chunk -> {
final World world = getWorld(location.getWorldName());
2020-07-24 17:24:53 +02:00
final Block block = Objects.requireNonNull(world).getBlockAt(location.getX(), location.getY(), location.getZ());
result.accept(Objects.requireNonNull(BukkitAdapter.asBlockType(block.getType())).getDefaultState());
});
}
@Override
public @NonNull BlockState getBlockSynchronous(final @NonNull Location location) {
final World world = getWorld(location.getWorldName());
2020-07-24 17:24:53 +02:00
final Block block = Objects.requireNonNull(world).getBlockAt(location.getX(), location.getY(), location.getZ());
2020-07-24 13:18:36 +02:00
return Objects.requireNonNull(BukkitAdapter.asBlockType(block.getType())).getDefaultState();
2016-02-10 19:59:51 +01:00
}
@Override
@NonNegative
2021-05-01 18:33:02 +02:00
public double getHealth(final @NonNull PlotPlayer<?> player) {
2020-07-24 13:18:36 +02:00
return Objects.requireNonNull(Bukkit.getPlayer(player.getUUID())).getHealth();
}
@Override
@NonNegative
public int getFoodLevel(final @NonNull PlotPlayer<?> player) {
2020-07-24 13:18:36 +02:00
return Objects.requireNonNull(Bukkit.getPlayer(player.getUUID())).getFoodLevel();
}
@Override
public void setHealth(final @NonNull PlotPlayer<?> player, @NonNegative final double health) {
2020-07-24 13:18:36 +02:00
Objects.requireNonNull(Bukkit.getPlayer(player.getUUID())).setHealth(health);
}
@Override
public void setFoodLevel(final @NonNull PlotPlayer<?> player, @NonNegative final int foodLevel) {
Bukkit.getPlayer(player.getUUID()).setFoodLevel(foodLevel);
}
@Override
public @NonNull Set<com.sk89q.worldedit.world.entity.EntityType> getTypesInCategory(final @NonNull String category) {
final Collection<Class<?>> allowedInterfaces = new HashSet<>();
switch (category) {
case "animal" -> {
2020-04-12 04:46:51 +02:00
allowedInterfaces.add(IronGolem.class);
allowedInterfaces.add(Snowman.class);
allowedInterfaces.add(Animals.class);
2020-04-12 00:57:50 +02:00
allowedInterfaces.add(WaterMob.class);
allowedInterfaces.add(Ambient.class);
2020-04-30 12:01:52 +02:00
}
2021-05-21 19:14:13 +02:00
case "tameable" -> allowedInterfaces.add(Tameable.class);
case "vehicle" -> allowedInterfaces.add(Vehicle.class);
case "hostile" -> {
2020-04-12 04:46:51 +02:00
allowedInterfaces.add(Shulker.class);
allowedInterfaces.add(Monster.class);
allowedInterfaces.add(Boss.class);
allowedInterfaces.add(Slime.class);
2020-04-12 00:57:50 +02:00
allowedInterfaces.add(Ghast.class);
allowedInterfaces.add(Phantom.class);
allowedInterfaces.add(EnderCrystal.class);
2020-04-30 12:01:52 +02:00
}
2021-05-21 19:14:13 +02:00
case "hanging" -> allowedInterfaces.add(Hanging.class);
case "villager" -> allowedInterfaces.add(NPC.class);
case "projectile" -> allowedInterfaces.add(Projectile.class);
case "other" -> {
2020-04-12 00:57:50 +02:00
allowedInterfaces.add(ArmorStand.class);
2020-04-12 01:23:13 +02:00
allowedInterfaces.add(FallingBlock.class);
allowedInterfaces.add(Item.class);
allowedInterfaces.add(Explosive.class);
allowedInterfaces.add(AreaEffectCloud.class);
allowedInterfaces.add(EvokerFangs.class);
allowedInterfaces.add(LightningStrike.class);
allowedInterfaces.add(ExperienceOrb.class);
allowedInterfaces.add(EnderSignal.class);
allowedInterfaces.add(Firework.class);
2020-04-30 12:01:52 +02:00
}
2021-05-21 19:14:13 +02:00
case "player" -> allowedInterfaces.add(Player.class);
default -> LOGGER.error("Unknown entity category requested: {}", category);
}
final Set<com.sk89q.worldedit.world.entity.EntityType> types = new HashSet<>();
2020-04-30 12:01:52 +02:00
outer:
for (final EntityType bukkitType : EntityType.values()) {
final Class<? extends Entity> entityClass = bukkitType.getEntityClass();
if (entityClass == null) {
continue;
}
for (final Class<?> allowedInterface : allowedInterfaces) {
if (allowedInterface.isAssignableFrom(entityClass)) {
types.add(BukkitAdapter.adapt(bukkitType));
continue outer;
}
}
}
return types;
}
@Override
public @NonNull Collection<BlockType> getTileEntityTypes() {
if (this.tileEntityTypes.isEmpty()) {
// Categories
tileEntityTypes.addAll(BlockCategories.BANNERS.getAll());
tileEntityTypes.addAll(BlockCategories.SIGNS.getAll());
tileEntityTypes.addAll(BlockCategories.BEDS.getAll());
tileEntityTypes.addAll(BlockCategories.FLOWER_POTS.getAll());
// Individual Types
// Add these from strings
2021-08-18 11:58:18 +02:00
Stream.of(
"barrel",
"beacon",
"beehive",
"bee_nest",
"bell",
"blast_furnace",
"brewing_stand",
"campfire",
"chest",
"ender_chest",
"trapped_chest",
"command_block",
"end_gateway",
"hopper",
"jigsaw",
"jubekox",
"lectern",
"note_block",
"black_shulker_box",
"blue_shulker_box",
"brown_shulker_box",
"cyan_shulker_box",
"gray_shulker_box",
"green_shulker_box",
"light_blue_shulker_box",
"light_gray_shulker_box",
"lime_shulker_box",
"magenta_shulker_box",
"orange_shulker_box",
"pink_shulker_box",
"purple_shulker_box",
"red_shulker_box",
"shulker_box",
"white_shulker_box",
"yellow_shulker_box",
"smoker",
"structure_block",
"structure_void"
)
.map(BlockTypes::get).filter(Objects::nonNull).forEach(tileEntityTypes::add);
}
return this.tileEntityTypes;
}
@Override
@NonNegative
public int getTileEntityCount(final @NonNull String world, final @NonNull BlockVector2 chunk) {
return Objects.requireNonNull(getWorld(world)).
getChunkAt(chunk.getBlockX(), chunk.getBlockZ()).getTileEntities().length;
2020-07-24 13:18:36 +02:00
}
@Override
public Set<BlockVector2> getChunkChunks(String world) {
2020-07-24 13:18:36 +02:00
Set<BlockVector2> chunks = super.getChunkChunks(world);
if (Bukkit.isPrimaryThread()) {
for (Chunk chunk : Objects.requireNonNull(Bukkit.getWorld(world)).getLoadedChunks()) {
BlockVector2 loc = BlockVector2.at(chunk.getX() >> 5, chunk.getZ() >> 5);
chunks.add(loc);
}
} else {
final Semaphore semaphore = new Semaphore(1);
try {
semaphore.acquire();
2020-07-24 17:24:53 +02:00
Bukkit.getScheduler().runTask(BukkitPlatform.getPlugin(BukkitPlatform.class), () -> {
for (Chunk chunk : Objects.requireNonNull(Bukkit.getWorld(world)).getLoadedChunks()) {
BlockVector2 loc = BlockVector2.at(chunk.getX() >> 5, chunk.getZ() >> 5);
chunks.add(loc);
}
semaphore.release();
});
2020-07-24 13:18:36 +02:00
semaphore.acquireUninterruptibly();
} catch (final Exception e) {
e.printStackTrace();
}
}
return chunks;
}
2015-02-19 07:08:15 +01:00
}