mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2024-11-26 20:55:41 +01:00
Uses seed worlds for deletion purposes (#2084)
* Uses seed worlds for deletion purposes * Use Flat type * Implement the superflat saver * Fix nullable issue * Fix tests. * Fix code smells
This commit is contained in:
parent
7040047fcb
commit
0c29d0b5dd
@ -1,6 +1,5 @@
|
||||
package world.bentobox.bentobox.listeners.flags.worldsettings;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
@ -13,7 +12,6 @@ import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
@ -22,8 +20,8 @@ import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.events.BentoBoxReadyEvent;
|
||||
import world.bentobox.bentobox.api.flags.FlagListener;
|
||||
import world.bentobox.bentobox.lists.Flags;
|
||||
import world.bentobox.bentobox.util.MyBiomeGrid;
|
||||
import world.bentobox.bentobox.util.Pair;
|
||||
import world.bentobox.bentobox.nms.WorldRegenerator;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
/**
|
||||
* Cleans super-flat world chunks or normal nether chunks if they generate accidentally
|
||||
@ -35,11 +33,10 @@ public class CleanSuperFlatListener extends FlagListener {
|
||||
private final BentoBox plugin = BentoBox.getInstance();
|
||||
|
||||
/**
|
||||
* Stores pairs of X,Z coordinates of chunks that need to be regenerated.
|
||||
* @since 1.1
|
||||
* Stores chunks that need to be regenerated.
|
||||
*/
|
||||
@NonNull
|
||||
private final Queue<@NonNull Pair<@NonNull Integer, @NonNull Integer>> chunkQueue = new LinkedList<>();
|
||||
private final Queue<Chunk> chunkQueue = new LinkedList<>();
|
||||
|
||||
/**
|
||||
* Task that runs each tick to regenerate chunks that are in the {@link #chunkQueue}.
|
||||
@ -56,8 +53,15 @@ public class CleanSuperFlatListener extends FlagListener {
|
||||
*/
|
||||
private boolean ready;
|
||||
|
||||
private WorldRegenerator regenerator;
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onBentoBoxReady(BentoBoxReadyEvent e) {
|
||||
this.regenerator = Util.getRegenerator();
|
||||
if (regenerator == null) {
|
||||
plugin.logError("Could not start CleanSuperFlat because of NMS error");
|
||||
return;
|
||||
}
|
||||
ready = true;
|
||||
}
|
||||
|
||||
@ -71,7 +75,6 @@ public class CleanSuperFlatListener extends FlagListener {
|
||||
return;
|
||||
}
|
||||
|
||||
MyBiomeGrid grid = new MyBiomeGrid(world.getEnvironment());
|
||||
ChunkGenerator cg = plugin.getAddonsManager().getDefaultWorldGenerator(world.getName(), "");
|
||||
|
||||
if (cg == null)
|
||||
@ -88,11 +91,11 @@ public class CleanSuperFlatListener extends FlagListener {
|
||||
}
|
||||
|
||||
// Add to queue
|
||||
this.chunkQueue.add(new Pair<>(e.getChunk().getX(), e.getChunk().getZ()));
|
||||
this.chunkQueue.add(e.getChunk());
|
||||
|
||||
if (this.task == null || this.task.isCancelled())
|
||||
{
|
||||
this.task = Bukkit.getScheduler().runTaskTimer(this.plugin, () -> this.cleanChunk(world, cg, grid), 0L, 1L);
|
||||
this.task = Bukkit.getScheduler().runTaskTimer(this.plugin, () -> this.cleanChunk(world), 0L, 1L);
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,37 +104,19 @@ public class CleanSuperFlatListener extends FlagListener {
|
||||
* This method clears the chunk from queue in the given world
|
||||
* @param world The world that must be cleared.
|
||||
* @param cg Chunk generator.
|
||||
* @param grid Biome Grid.
|
||||
*/
|
||||
private void cleanChunk(World world, ChunkGenerator cg, MyBiomeGrid grid)
|
||||
private void cleanChunk(World world)
|
||||
{
|
||||
SecureRandom random = new SecureRandom();
|
||||
|
||||
if (!this.chunkQueue.isEmpty())
|
||||
{
|
||||
Pair<Integer, Integer> chunkXZ = this.chunkQueue.poll();
|
||||
Chunk chunk = this.chunkQueue.poll();
|
||||
|
||||
ChunkData cd = cg.generateChunkData(world, random, chunkXZ.getKey(), chunkXZ.getValue(), grid);
|
||||
Chunk chunk = world.getChunkAt(chunkXZ.getKey(), chunkXZ.getValue());
|
||||
|
||||
for (int x = 0; x < 16; x++)
|
||||
{
|
||||
for (int z = 0; z < 16; z++)
|
||||
{
|
||||
for (int y = world.getMinHeight(); y < world.getMaxHeight(); y++)
|
||||
{
|
||||
chunk.getBlock(x, y, z).setBlockData(cd.getBlockData(x, y, z), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run populators
|
||||
cg.getDefaultPopulators(world).forEach(pop -> pop.populate(world, random, chunk));
|
||||
regenerator.regenerateChunk(chunk);
|
||||
|
||||
if (this.plugin.getSettings().isLogCleanSuperFlatChunks())
|
||||
{
|
||||
this.plugin.log("Regenerating superflat chunk in " + world.getName() +
|
||||
" at (" + chunkXZ.x + ", " + chunkXZ.z + ") " +
|
||||
" at (" + chunk.getX() + ", " + chunk.getZ() + ") " +
|
||||
"(" + this.chunkQueue.size() + " chunk(s) remaining in the queue)");
|
||||
}
|
||||
}
|
||||
@ -141,6 +126,7 @@ public class CleanSuperFlatListener extends FlagListener {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if chunk should be cleaned or not
|
||||
* @param world - world
|
||||
@ -152,7 +138,6 @@ public class CleanSuperFlatListener extends FlagListener {
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if super-flat must even be working.
|
||||
if (!this.getIWM().inWorld(world) ||
|
||||
!Flags.CLEAN_SUPER_FLAT.isSetForWorld(world) ||
|
||||
|
@ -23,6 +23,10 @@ import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Difficulty;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.WorldType;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
@ -300,6 +304,8 @@ public class AddonsManager {
|
||||
if (addon instanceof GameModeAddon gameMode) {
|
||||
// Create the gameWorlds
|
||||
gameMode.createWorlds();
|
||||
// Create the seed worlds
|
||||
createSeedWorlds(gameMode);
|
||||
plugin.getIWM().addGameMode(gameMode);
|
||||
// Save and load blueprints
|
||||
plugin.getBlueprintsManager().extractDefaultBlueprints(gameMode);
|
||||
@ -326,6 +332,29 @@ public class AddonsManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create seed worlds, which are used for deletion
|
||||
* @param gameMode
|
||||
*/
|
||||
private void createSeedWorlds(GameModeAddon gameMode) {
|
||||
if (gameMode.getOverWorld() != null) {
|
||||
seedWorld(gameMode, gameMode.getOverWorld());
|
||||
}
|
||||
if (gameMode.getNetherWorld() != null) {
|
||||
seedWorld(gameMode, gameMode.getNetherWorld());
|
||||
}
|
||||
if (gameMode.getEndWorld() != null) {
|
||||
seedWorld(gameMode, gameMode.getEndWorld());
|
||||
}
|
||||
}
|
||||
|
||||
private void seedWorld(GameModeAddon gameMode, @NonNull World world) {
|
||||
// Use the Flat type of world because this is a copy and no vanilla creation is required
|
||||
WorldCreator wc = WorldCreator.name("seeds/" + world.getName()).type(WorldType.FLAT).environment(world.getEnvironment());
|
||||
World w = gameMode.getWorldSettings().isUseOwnGenerator() ? wc.createWorld() : wc.generator(world.getGenerator()).createWorld();
|
||||
w.setDifficulty(Difficulty.PEACEFUL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an addon which failed to load due to an incompatibility (missing class, missing method).
|
||||
* @param addon instance of the Addon.
|
||||
|
@ -0,0 +1,267 @@
|
||||
package world.bentobox.bentobox.nms;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Banner;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.CreatureSpawner;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.AbstractHorse;
|
||||
import org.bukkit.entity.Ageable;
|
||||
import org.bukkit.entity.ChestedHorse;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Horse;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Tameable;
|
||||
import org.bukkit.entity.Villager;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.material.Colorable;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.BoundingBox;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import io.papermc.lib.PaperLib;
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.database.objects.IslandDeletion;
|
||||
|
||||
/**
|
||||
* Regenerates by using a seed world. The seed world is created using the same generator as the game
|
||||
* world so that features created by methods like generateNoise or generateCaves can be regenerated.
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public abstract class CopyWorldRegenerator implements WorldRegenerator {
|
||||
private static final String SEEDS = "seeds/";
|
||||
private final BentoBox plugin;
|
||||
|
||||
protected CopyWorldRegenerator() {
|
||||
this.plugin = BentoBox.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the low-level chunk information for the given block to the new block ID and data. This
|
||||
* change will not be propagated to clients until the chunk is refreshed to them.
|
||||
*
|
||||
* @param chunk - chunk to be changed
|
||||
* @param x - x coordinate within chunk 0 - 15
|
||||
* @param y - y coordinate within chunk 0 - world height, e.g. 255
|
||||
* @param z - z coordinate within chunk 0 - 15
|
||||
* @param blockData - block data to set the block
|
||||
* @param applyPhysics - apply physics or not
|
||||
*/
|
||||
protected abstract void setBlockInNativeChunk(Chunk chunk, int x, int y, int z, BlockData blockData, boolean applyPhysics);
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> regenerate(GameModeAddon gm, IslandDeletion di, World world) {
|
||||
CompletableFuture<Void> bigFuture = new CompletableFuture<>();
|
||||
new BukkitRunnable() {
|
||||
private int chunkX = di.getMinXChunk();
|
||||
private int chunkZ = di.getMinZChunk();
|
||||
CompletableFuture<Void> currentTask = CompletableFuture.completedFuture(null);
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!currentTask.isDone()) return;
|
||||
if (isEnded(chunkX)) {
|
||||
cancel();
|
||||
bigFuture.complete(null);
|
||||
return;
|
||||
}
|
||||
List<CompletableFuture<Void>> newTasks = new ArrayList<>();
|
||||
for (int i = 0; i < plugin.getSettings().getDeleteSpeed(); i++) {
|
||||
if (isEnded(chunkX)) {
|
||||
break;
|
||||
}
|
||||
final int x = chunkX;
|
||||
final int z = chunkZ;
|
||||
newTasks.add(regenerateChunk(di, world, x, z));
|
||||
chunkZ++;
|
||||
if (chunkZ > di.getMaxZChunk()) {
|
||||
chunkZ = di.getMinZChunk();
|
||||
chunkX++;
|
||||
}
|
||||
}
|
||||
currentTask = CompletableFuture.allOf(newTasks.toArray(new CompletableFuture[0]));
|
||||
}
|
||||
|
||||
private boolean isEnded(int chunkX) {
|
||||
return chunkX > di.getMaxXChunk();
|
||||
}
|
||||
}.runTaskTimer(plugin, 0L, 20L);
|
||||
return bigFuture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> regenerateChunk(Chunk chunk) {
|
||||
return regenerateChunk(null, chunk.getWorld(), chunk.getX(), chunk.getZ());
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> regenerateChunk(@Nullable IslandDeletion di, World world, int chunkX, int chunkZ) {
|
||||
CompletableFuture<Chunk> seedWorldFuture = getSeedWorldChunk(world, chunkX, chunkZ);
|
||||
|
||||
// Set up a future to get the chunk requests using Paper's Lib. If Paper is used, this should be done async
|
||||
CompletableFuture<Chunk> chunkFuture = PaperLib.getChunkAtAsync(world, chunkX, chunkZ);
|
||||
|
||||
// If there is no island, do not clean chunk
|
||||
CompletableFuture<Void> cleanFuture = di != null ? cleanChunk(chunkFuture, di) : CompletableFuture.completedFuture(null);
|
||||
|
||||
CompletableFuture<Void> copyFuture = CompletableFuture.allOf(cleanFuture, chunkFuture, seedWorldFuture);
|
||||
|
||||
copyFuture.thenRun(() -> {
|
||||
|
||||
try {
|
||||
Chunk chunkTo = chunkFuture.get();
|
||||
Chunk chunkFrom = seedWorldFuture.get();
|
||||
copyChunkDataToChunk(chunkTo, chunkFrom, di != null ? di.getBox() : null);
|
||||
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
});
|
||||
return CompletableFuture.allOf(cleanFuture, copyFuture);
|
||||
}
|
||||
|
||||
private CompletableFuture<Chunk> getSeedWorldChunk(World world, int chunkX, int chunkZ) {
|
||||
World seed = Bukkit.getWorld(SEEDS + world.getName());
|
||||
if (seed == null) return CompletableFuture.completedFuture(null);
|
||||
return PaperLib.getChunkAtAsync(seed, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the chunk of inventories and entities
|
||||
* @param chunkFuture the future chunk to be cleaned
|
||||
* @param di island deletion data
|
||||
* @return future completion of this task
|
||||
*/
|
||||
private CompletableFuture<Void> cleanChunk(CompletableFuture<Chunk> chunkFuture, IslandDeletion di) {
|
||||
// when it is complete, then run through all the tile entities in the chunk and clear them, e.g., chests are emptied
|
||||
CompletableFuture<Void> invFuture = chunkFuture.thenAccept(chunk ->
|
||||
Arrays.stream(chunk.getTileEntities()).filter(InventoryHolder.class::isInstance)
|
||||
.filter(te -> di.inBounds(te.getLocation().getBlockX(), te.getLocation().getBlockZ()))
|
||||
.forEach(te -> ((InventoryHolder) te).getInventory().clear())
|
||||
);
|
||||
|
||||
// Similarly, when the chunk is loaded, remove all the entities in the chunk apart from players
|
||||
CompletableFuture<Void> entitiesFuture = chunkFuture.thenAccept(chunk ->
|
||||
// Remove all entities in chunk, including any dropped items as a result of clearing the blocks above
|
||||
Arrays.stream(chunk.getEntities())
|
||||
.filter(e -> !(e instanceof Player) && di.inBounds(e.getLocation().getBlockX(), e.getLocation().getBlockZ()))
|
||||
.forEach(Entity::remove));
|
||||
return CompletableFuture.allOf(invFuture, entitiesFuture);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a chunk to another chunk
|
||||
* @param toChunk - chunk to be copied into
|
||||
* @param fromChunk - chunk to be copied from
|
||||
* @param limitBox - limit box that the chunk needs to be in
|
||||
*/
|
||||
private void copyChunkDataToChunk(Chunk toChunk, Chunk fromChunk, BoundingBox limitBox) {
|
||||
double baseX = toChunk.getX() << 4;
|
||||
double baseZ = toChunk.getZ() << 4;
|
||||
int minHeight = toChunk.getWorld().getMinHeight();
|
||||
int maxHeight = toChunk.getWorld().getMaxHeight();
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
if (limitBox != null && !limitBox.contains(baseX + x, 0, baseZ + z)) {
|
||||
continue;
|
||||
}
|
||||
for (int y = minHeight; y < maxHeight; y++) {
|
||||
setBlockInNativeChunk(toChunk, x, y, z, fromChunk.getBlock(x, y, z).getBlockData(), false);
|
||||
// 3D biomes, 4 blocks separated
|
||||
if (x % 4 == 0 && y % 4 == 0 && z % 4 == 0) {
|
||||
toChunk.getBlock(x, y, z).setBiome(fromChunk.getBlock(x, y, z).getBiome());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Entities
|
||||
Arrays.stream(fromChunk.getEntities()).forEach(e -> processEntity(e, e.getLocation().toVector().toLocation(toChunk.getWorld())));
|
||||
|
||||
// Tile Entities
|
||||
Arrays.stream(fromChunk.getTileEntities()).forEach(bs -> processTileEntity(bs.getBlock(), bs.getLocation().toVector().toLocation(toChunk.getWorld()).getBlock()));
|
||||
}
|
||||
|
||||
private void processEntity(Entity entity, Location location) {
|
||||
Entity bpe = location.getWorld().spawnEntity(location, entity.getType());
|
||||
bpe.setCustomName(entity.getCustomName());
|
||||
if (entity instanceof Villager villager && bpe instanceof Villager villager2) {
|
||||
setVillager(villager, villager2);
|
||||
}
|
||||
if (entity instanceof Colorable c && bpe instanceof Colorable cc) {
|
||||
if (c.getColor() != null) {
|
||||
cc.setColor(c.getColor());
|
||||
}
|
||||
}
|
||||
if (entity instanceof Tameable t && bpe instanceof Tameable tt) {
|
||||
tt.setTamed(t.isTamed());
|
||||
}
|
||||
if (entity instanceof ChestedHorse ch && bpe instanceof ChestedHorse ch2) {
|
||||
ch2.setCarryingChest(ch.isCarryingChest());
|
||||
}
|
||||
// Only set if child. Most animals are adults
|
||||
if (entity instanceof Ageable a && bpe instanceof Ageable aa) {
|
||||
if (a.isAdult()) aa.setAdult();
|
||||
}
|
||||
if (entity instanceof AbstractHorse horse && bpe instanceof AbstractHorse horse2) {
|
||||
horse2.setDomestication(horse.getDomestication());
|
||||
horse2.getInventory().setContents(horse.getInventory().getContents());
|
||||
}
|
||||
|
||||
if (entity instanceof Horse horse && bpe instanceof Horse horse2) {
|
||||
horse2.setStyle(horse.getStyle());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the villager stats
|
||||
* @param v - villager
|
||||
* @param villager2 villager
|
||||
*/
|
||||
private void setVillager(Villager v, Villager villager2) {
|
||||
villager2.setVillagerExperience(v.getVillagerExperience());
|
||||
villager2.setVillagerLevel(v.getVillagerLevel());
|
||||
villager2.setProfession(v.getProfession());
|
||||
villager2.setVillagerType(v.getVillagerType());
|
||||
}
|
||||
|
||||
private void processTileEntity(Block fromBlock, Block toBlock) {
|
||||
// Block state
|
||||
BlockState blockState = fromBlock.getState();
|
||||
BlockState b = toBlock.getState();
|
||||
|
||||
// Signs
|
||||
if (blockState instanceof Sign fromSign && b instanceof Sign toSign) {
|
||||
int i = 0;
|
||||
for (String line : fromSign.getLines()) {
|
||||
toSign.setLine(i++, line);
|
||||
}
|
||||
toSign.setGlowingText(fromSign.isGlowingText());
|
||||
}
|
||||
// Chests
|
||||
else if (blockState instanceof InventoryHolder ih && b instanceof InventoryHolder toChest) {
|
||||
toChest.getInventory().setContents(ih.getInventory().getContents());
|
||||
}
|
||||
// Spawner type
|
||||
else if (blockState instanceof CreatureSpawner spawner && b instanceof CreatureSpawner toSpawner) {
|
||||
toSpawner.setSpawnedType(spawner.getSpawnedType());
|
||||
}
|
||||
|
||||
// Banners
|
||||
else if (blockState instanceof Banner banner && b instanceof Banner toBanner) {
|
||||
toBanner.setBaseColor(banner.getBaseColor());
|
||||
toBanner.setPatterns(banner.getPatterns());
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package world.bentobox.bentobox.nms;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
@ -20,4 +21,11 @@ public interface WorldRegenerator {
|
||||
* @return the completable future
|
||||
*/
|
||||
CompletableFuture<Void> regenerate(GameModeAddon gm, IslandDeletion di, World world);
|
||||
|
||||
/**
|
||||
* Regenerate a specific chunk to what it should be. Mainly used by clear super flat.
|
||||
* @param chunk chunk to be regenerated
|
||||
* @return future when it is done
|
||||
*/
|
||||
CompletableFuture<Void> regenerateChunk(Chunk chunk);
|
||||
}
|
||||
|
@ -3,13 +3,13 @@ package world.bentobox.bentobox.nms.fallback;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import world.bentobox.bentobox.nms.SimpleWorldRegenerator;
|
||||
import world.bentobox.bentobox.nms.CopyWorldRegenerator;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class WorldRegeneratorImpl extends SimpleWorldRegenerator {
|
||||
public class WorldRegeneratorImpl extends CopyWorldRegenerator {
|
||||
|
||||
@Override
|
||||
protected void setBlockInNativeChunk(Chunk chunk, int x, int y, int z, BlockData blockData, boolean applyPhysics) {
|
||||
|
@ -10,10 +10,10 @@ import net.minecraft.core.BlockPosition;
|
||||
import net.minecraft.world.level.World;
|
||||
import net.minecraft.world.level.block.state.IBlockData;
|
||||
import net.minecraft.world.level.chunk.Chunk;
|
||||
import world.bentobox.bentobox.nms.SimpleWorldRegenerator;
|
||||
import world.bentobox.bentobox.nms.CopyWorldRegenerator;
|
||||
|
||||
|
||||
public class WorldRegeneratorImpl extends SimpleWorldRegenerator {
|
||||
public class WorldRegeneratorImpl extends CopyWorldRegenerator {
|
||||
|
||||
private static final IBlockData AIR = ((CraftBlockData) Bukkit.createBlockData(Material.AIR)).getState();
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package world.bentobox.bentobox.listeners.flags.worldsettings;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
@ -11,17 +10,14 @@ import static org.mockito.Mockito.when;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||
import org.bukkit.inventory.ItemFactory;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
@ -44,7 +40,7 @@ import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.lists.Flags;
|
||||
import world.bentobox.bentobox.managers.AddonsManager;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
import world.bentobox.bentobox.util.MyBiomeGrid;
|
||||
import world.bentobox.bentobox.nms.WorldRegenerator;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
/**
|
||||
@ -66,6 +62,8 @@ public class CleanSuperFlatListenerTest {
|
||||
private CleanSuperFlatListener l;
|
||||
@Mock
|
||||
private BukkitScheduler scheduler;
|
||||
@Mock
|
||||
private WorldRegenerator regenerator;
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
@ -83,8 +81,10 @@ public class CleanSuperFlatListenerTest {
|
||||
when(world.getEnvironment()).thenReturn(World.Environment.NORMAL);
|
||||
when(world.getName()).thenReturn("world");
|
||||
|
||||
PowerMockito.mockStatic(Util.class);
|
||||
PowerMockito.mockStatic(Util.class, Mockito.RETURNS_MOCKS);
|
||||
when(Util.getWorld(any())).thenReturn(world);
|
||||
// Regenerator
|
||||
when(Util.getRegenerator()).thenReturn(regenerator);
|
||||
|
||||
// World Settings
|
||||
when(plugin.getIWM()).thenReturn(iwm);
|
||||
@ -125,13 +125,12 @@ public class CleanSuperFlatListenerTest {
|
||||
AddonsManager am = mock(AddonsManager.class);
|
||||
@Nullable
|
||||
ChunkGenerator cg = mock(ChunkGenerator.class);
|
||||
ChunkData cd = mock(ChunkData.class);
|
||||
when(cg.generateChunkData(any(World.class), any(Random.class), anyInt(), anyInt(), any(MyBiomeGrid.class))).thenReturn(cd);
|
||||
BlockData bd = mock(BlockData.class);
|
||||
when(cd.getBlockData(anyInt(), anyInt(), anyInt())).thenReturn(bd);
|
||||
|
||||
when(plugin.getAddonsManager()).thenReturn(am);
|
||||
when(am.getDefaultWorldGenerator(anyString(), anyString())).thenReturn(cg);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
|
Loading…
Reference in New Issue
Block a user