mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2024-12-25 18:48:15 +01:00
Rewrote chunk deletion (#648)
As of 1.14, chunk regeneration is no longer supported. This PR implements a not-chunk-based deletion that supports both 1.13 and 1.14 and which also allows us to get rid of the "multiple of 16" rule for island distances. This PR however does not remove the "multiple of 16" rule and a commit should be made thereafter.
This PR is also a pre-requisite to #640.
* Makes GameModes responsible for regenerating chunks.
* Deletes chunks manually to solve 1.14 chunk regen removal
* Fixes round up to 16 for island distance bug.
* Clean up - removing imports and stack traces
* Revert "Fixes round up to 16 for island distance bug."
This reverts commit 54f1ce0940
.
* Adds island edge protection for deletion. Needs full testing.
* Completed testing. Works correctly.
This commit is contained in:
parent
95c0c612da
commit
650e370ffe
@ -129,4 +129,5 @@ public abstract class GameModeAddon extends Addon {
|
|||||||
* @since 1.4.0
|
* @since 1.4.0
|
||||||
*/
|
*/
|
||||||
public abstract void saveWorldSettings();
|
public abstract void saveWorldSettings();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.util.BoundingBox;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import com.google.gson.annotations.Expose;
|
import com.google.gson.annotations.Expose;
|
||||||
|
|
||||||
@ -32,24 +34,35 @@ public class IslandDeletion implements DataObject {
|
|||||||
@Expose
|
@Expose
|
||||||
private int maxZChunk;
|
private int maxZChunk;
|
||||||
|
|
||||||
|
@Expose
|
||||||
|
private int minX;
|
||||||
|
|
||||||
|
@Expose
|
||||||
|
private int minZ;
|
||||||
|
|
||||||
|
@Expose
|
||||||
|
private int maxX;
|
||||||
|
|
||||||
|
@Expose
|
||||||
|
private int maxZ;
|
||||||
|
|
||||||
|
@Expose
|
||||||
|
BoundingBox box;
|
||||||
|
|
||||||
public IslandDeletion() {}
|
public IslandDeletion() {}
|
||||||
|
|
||||||
public IslandDeletion(Island island) {
|
public IslandDeletion(Island island) {
|
||||||
uniqueId = UUID.randomUUID().toString();
|
uniqueId = UUID.randomUUID().toString();
|
||||||
location = island.getCenter();
|
location = island.getCenter();
|
||||||
minXChunk = (location.getBlockX() - island.getMaxEverProtectionRange()) >> 4;
|
minX = location.getBlockX() - island.getMaxEverProtectionRange();
|
||||||
maxXChunk = (island.getMaxEverProtectionRange() + location.getBlockX() - 1) >> 4;
|
minXChunk = minX >> 4;
|
||||||
minZChunk = (location.getBlockZ() - island.getMaxEverProtectionRange()) >> 4;
|
maxX = island.getMaxEverProtectionRange() + location.getBlockX();
|
||||||
maxZChunk = (island.getMaxEverProtectionRange() + location.getBlockZ() - 1) >> 4;
|
maxXChunk = maxX >> 4;
|
||||||
}
|
minZ = location.getBlockZ() - island.getMaxEverProtectionRange();
|
||||||
|
minZChunk = minZ >> 4;
|
||||||
public IslandDeletion(Location location, int minXChunk, int maxXChunk, int minZChunk, int maxZChunk) {
|
maxZ = island.getMaxEverProtectionRange() + location.getBlockZ();
|
||||||
this.uniqueId = UUID.randomUUID().toString();
|
maxZChunk = maxZ >> 4;
|
||||||
this.location = location;
|
box = BoundingBox.of(new Vector(minX, 0, minZ), new Vector(maxX, 255, maxZ));
|
||||||
this.minXChunk = minXChunk;
|
|
||||||
this.maxXChunk = maxXChunk;
|
|
||||||
this.minZChunk = minZChunk;
|
|
||||||
this.maxZChunk = maxZChunk;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@ -170,9 +183,60 @@ public class IslandDeletion implements DataObject {
|
|||||||
this.minZChunk = minZChunk;
|
this.minZChunk = minZChunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getMinX() {
|
||||||
|
return minX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinX(int minX) {
|
||||||
|
this.minX = minX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMinZ() {
|
||||||
|
return minZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinZ(int minZ) {
|
||||||
|
this.minZ = minZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxX() {
|
||||||
|
return maxX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxX(int maxX) {
|
||||||
|
this.maxX = maxX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxZ() {
|
||||||
|
return maxZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxZ(int maxZ) {
|
||||||
|
this.maxZ = maxZ;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUniqueId(String uniqueId) {
|
public void setUniqueId(String uniqueId) {
|
||||||
this.uniqueId = uniqueId;
|
this.uniqueId = uniqueId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean inBounds(int x, int z) {
|
||||||
|
return box.contains(new Vector(x, 0, z));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the box
|
||||||
|
*/
|
||||||
|
public BoundingBox getBox() {
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param box the box to set
|
||||||
|
*/
|
||||||
|
public void setBox(BoundingBox box) {
|
||||||
|
this.box = box;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,29 @@
|
|||||||
package world.bentobox.bentobox.util;
|
package world.bentobox.bentobox.util;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.block.Biome;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
||||||
|
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||||
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import world.bentobox.bentobox.BentoBox;
|
import world.bentobox.bentobox.BentoBox;
|
||||||
|
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||||
import world.bentobox.bentobox.api.events.island.IslandEvent;
|
import world.bentobox.bentobox.api.events.island.IslandEvent;
|
||||||
import world.bentobox.bentobox.api.events.island.IslandEvent.Reason;
|
import world.bentobox.bentobox.api.events.island.IslandEvent.Reason;
|
||||||
import world.bentobox.bentobox.database.objects.IslandDeletion;
|
import world.bentobox.bentobox.database.objects.IslandDeletion;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes islands fast using chunk regeneration
|
* Deletes islands chunk by chunk
|
||||||
*
|
*
|
||||||
* @author tastybento
|
* @author tastybento
|
||||||
*/
|
*/
|
||||||
@ -19,39 +33,79 @@ public class DeleteIslandChunks {
|
|||||||
* This is how many chunks per world will be done in one tick.
|
* This is how many chunks per world will be done in one tick.
|
||||||
*/
|
*/
|
||||||
private static final int SPEED = 5;
|
private static final int SPEED = 5;
|
||||||
private int x;
|
private int chunkX;
|
||||||
private int z;
|
private int chunkZ;
|
||||||
private BukkitTask task;
|
private BukkitTask task;
|
||||||
|
private IslandDeletion di;
|
||||||
|
|
||||||
@SuppressWarnings({"deprecation", "squid:CallToDeprecatedMethod"})
|
|
||||||
public DeleteIslandChunks(BentoBox plugin, IslandDeletion di) {
|
public DeleteIslandChunks(BentoBox plugin, IslandDeletion di) {
|
||||||
// Fire event
|
// Fire event
|
||||||
IslandEvent.builder().deletedIslandInfo(di).reason(Reason.DELETE_CHUNKS).build();
|
IslandEvent.builder().deletedIslandInfo(di).reason(Reason.DELETE_CHUNKS).build();
|
||||||
x = di.getMinXChunk();
|
this.chunkX = di.getMinXChunk();
|
||||||
z = di.getMinZChunk();
|
this.chunkZ = di.getMinZChunk();
|
||||||
|
this.di = di;
|
||||||
// Run through all chunks of the islands and regenerate them.
|
// Run through all chunks of the islands and regenerate them.
|
||||||
task = Bukkit.getScheduler().runTaskTimer(plugin, () -> {
|
task = Bukkit.getScheduler().runTaskTimer(plugin, () -> {
|
||||||
for (int i = 0; i < SPEED; i++) {
|
for (int i = 0; i < SPEED; i++) {
|
||||||
// World#regenerateChunk(int, int) from Bukkit is deprecated because it may not regenerate decoration correctly
|
plugin.getIWM().getAddon(di.getWorld()).ifPresent(gm -> {
|
||||||
di.getWorld().regenerateChunk(x, z);
|
|
||||||
|
regerateChunk(gm, di.getWorld().getChunkAt(chunkX, chunkZ));
|
||||||
|
|
||||||
if (plugin.getIWM().isNetherGenerate(di.getWorld()) && plugin.getIWM().isNetherIslands(di.getWorld())) {
|
if (plugin.getIWM().isNetherGenerate(di.getWorld()) && plugin.getIWM().isNetherIslands(di.getWorld())) {
|
||||||
plugin.getIWM().getNetherWorld(di.getWorld()).regenerateChunk(x, z);
|
regerateChunk(gm, plugin.getIWM().getNetherWorld(di.getWorld()).getChunkAt(chunkX, chunkZ));
|
||||||
}
|
}
|
||||||
if (plugin.getIWM().isEndGenerate(di.getWorld()) && plugin.getIWM().isEndIslands(di.getWorld())) {
|
if (plugin.getIWM().isEndGenerate(di.getWorld()) && plugin.getIWM().isEndIslands(di.getWorld())) {
|
||||||
plugin.getIWM().getEndWorld(di.getWorld()).regenerateChunk(x, z);
|
regerateChunk(gm, plugin.getIWM().getEndWorld(di.getWorld()).getChunkAt(chunkX, chunkZ));
|
||||||
}
|
}
|
||||||
z++;
|
chunkZ++;
|
||||||
if (z > di.getMaxZChunk()) {
|
if (chunkZ > di.getMaxZChunk()) {
|
||||||
z = di.getMinZChunk();
|
chunkZ = di.getMinZChunk();
|
||||||
x++;
|
chunkX++;
|
||||||
if (x > di.getMaxXChunk()) {
|
if (chunkX > di.getMaxXChunk()) {
|
||||||
// We're done
|
// We're done
|
||||||
task.cancel();
|
task.cancel();
|
||||||
// Fire event
|
// Fire event
|
||||||
IslandEvent.builder().deletedIslandInfo(di).reason(Reason.DELETED).build();
|
IslandEvent.builder().deletedIslandInfo(di).reason(Reason.DELETED).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, 0L, 1L);
|
}, 0L, 1L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void regerateChunk(GameModeAddon gm, Chunk chunk) {
|
||||||
|
// Clear all inventories
|
||||||
|
Arrays.stream(chunk.getTileEntities()).filter(te -> (te instanceof InventoryHolder))
|
||||||
|
.filter(te -> di.inBounds(te.getLocation().getBlockX(), te.getLocation().getBlockZ()))
|
||||||
|
.forEach(te -> ((InventoryHolder)te).getInventory().clear());
|
||||||
|
// Reset blocks
|
||||||
|
MyBiomeGrid grid = new MyBiomeGrid();
|
||||||
|
ChunkData cd = gm.getDefaultWorldGenerator(chunk.getWorld().getName(), "").generateChunkData(chunk.getWorld(), new Random(), chunk.getX(), chunk.getZ(), grid);
|
||||||
|
int baseX = chunk.getX() << 4;
|
||||||
|
int baseZ = chunk.getZ() << 4;
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
if (di.inBounds(baseX + x, baseZ + z)) {
|
||||||
|
chunk.getBlock(x, 0, z).setBiome(grid.getBiome(x, z));
|
||||||
|
for (int y = 0; y < chunk.getWorld().getMaxHeight(); y++) {
|
||||||
|
chunk.getBlock(x, y, z).setBlockData(cd.getBlockData(x, y, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyBiomeGrid implements BiomeGrid {
|
||||||
|
Map<Vector, Biome> map = new HashMap<>();
|
||||||
|
@Override
|
||||||
|
public Biome getBiome(int x, int z) {
|
||||||
|
return map.getOrDefault(new Vector(x,0,z), Biome.PLAINS);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setBiome(int x, int z, Biome bio) {
|
||||||
|
map.put(new Vector(x,0,z), bio);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ public class SafeSpotTeleport {
|
|||||||
private static final int MAX_CHUNKS = 200;
|
private static final int MAX_CHUNKS = 200;
|
||||||
private static final long SPEED = 1;
|
private static final long SPEED = 1;
|
||||||
private static final int MAX_RADIUS = 200;
|
private static final int MAX_RADIUS = 200;
|
||||||
|
private static final int MAX_HEIGHT = 235;
|
||||||
private boolean checking;
|
private boolean checking;
|
||||||
private BukkitTask task;
|
private BukkitTask task;
|
||||||
|
|
||||||
@ -219,14 +220,12 @@ public class SafeSpotTeleport {
|
|||||||
* @return true if a safe spot was found
|
* @return true if a safe spot was found
|
||||||
*/
|
*/
|
||||||
private boolean scanChunk(ChunkSnapshot chunk) {
|
private boolean scanChunk(ChunkSnapshot chunk) {
|
||||||
// Max height
|
|
||||||
int maxHeight = location.getWorld().getMaxHeight() - 20;
|
|
||||||
// Run through the chunk
|
// Run through the chunk
|
||||||
for (int x = 0; x< 16; x++) {
|
for (int x = 0; x< 16; x++) {
|
||||||
for (int z = 0; z < 16; z++) {
|
for (int z = 0; z < 16; z++) {
|
||||||
// Work down from the entry point up
|
// Work down from the entry point up
|
||||||
for (int y = Math.min(chunk.getHighestBlockYAt(x, z), maxHeight); y >= 0; y--) {
|
for (int y = Math.min(chunk.getHighestBlockYAt(x, z), MAX_HEIGHT); y >= 0; y--) {
|
||||||
if (checkBlock(chunk, x,y,z, maxHeight)) {
|
if (checkBlock(chunk, x,y,z, MAX_HEIGHT)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} // end y
|
} // end y
|
||||||
|
Loading…
Reference in New Issue
Block a user