2020-04-16 04:52:39 +02:00
|
|
|
/*
|
|
|
|
* _____ _ _ _____ _
|
|
|
|
* | __ \| | | | / ____| | |
|
|
|
|
* | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| |
|
|
|
|
* | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
|
|
|
|
* | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| |
|
|
|
|
* |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_|
|
|
|
|
* | |
|
|
|
|
* |_|
|
|
|
|
* PlotSquared plot management system for Minecraft
|
|
|
|
* Copyright (C) 2020 IntellectualSites
|
|
|
|
*
|
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2020-04-11 02:19:18 +02:00
|
|
|
package com.plotsquared.bukkit;
|
2018-08-10 17:53:14 +02:00
|
|
|
|
2020-04-11 02:19:18 +02:00
|
|
|
import com.plotsquared.bukkit.entity.EntityWrapper;
|
|
|
|
import com.plotsquared.bukkit.entity.ReplicatingEntityWrapper;
|
|
|
|
import com.plotsquared.bukkit.util.BukkitUtil;
|
2020-04-16 06:11:03 +02:00
|
|
|
import com.plotsquared.core.PlotSquared;
|
2020-04-15 21:26:54 +02:00
|
|
|
import com.plotsquared.core.generator.AugmentedUtils;
|
|
|
|
import com.plotsquared.core.listener.WEExtent;
|
|
|
|
import com.plotsquared.core.location.Location;
|
2020-04-16 06:11:03 +02:00
|
|
|
import com.plotsquared.core.location.PlotLoc;
|
2020-04-15 21:26:54 +02:00
|
|
|
import com.plotsquared.core.plot.Plot;
|
|
|
|
import com.plotsquared.core.plot.PlotArea;
|
|
|
|
import com.plotsquared.core.queue.GlobalBlockQueue;
|
|
|
|
import com.plotsquared.core.queue.LocalBlockQueue;
|
|
|
|
import com.plotsquared.core.queue.ScopedLocalBlockQueue;
|
2020-04-16 06:11:03 +02:00
|
|
|
import com.plotsquared.core.util.ChunkManager;
|
2020-04-15 21:26:54 +02:00
|
|
|
import com.plotsquared.core.util.RegionUtil;
|
2020-04-16 06:11:03 +02:00
|
|
|
import com.plotsquared.core.util.entity.EntityCategories;
|
|
|
|
import com.plotsquared.core.util.task.RunnableVal;
|
|
|
|
import com.plotsquared.core.util.task.TaskManager;
|
2020-04-12 19:30:50 +02:00
|
|
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
2018-12-31 18:15:47 +01:00
|
|
|
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
2019-11-04 18:44:23 +01:00
|
|
|
import com.sk89q.worldedit.math.BlockVector2;
|
2018-12-31 18:15:47 +01:00
|
|
|
import com.sk89q.worldedit.math.BlockVector3;
|
2019-11-10 18:47:37 +01:00
|
|
|
import com.sk89q.worldedit.regions.CuboidRegion;
|
2018-12-31 18:15:47 +01:00
|
|
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
2019-11-10 18:47:37 +01:00
|
|
|
import com.sk89q.worldedit.world.block.BlockTypes;
|
2019-09-12 01:04:29 +02:00
|
|
|
import io.papermc.lib.PaperLib;
|
2019-01-16 00:58:21 +01:00
|
|
|
import org.bukkit.Bukkit;
|
|
|
|
import org.bukkit.Chunk;
|
|
|
|
import org.bukkit.World;
|
2018-12-31 18:15:47 +01:00
|
|
|
import org.bukkit.block.Block;
|
2018-12-17 20:57:21 +01:00
|
|
|
import org.bukkit.block.data.BlockData;
|
2019-01-16 00:58:21 +01:00
|
|
|
import org.bukkit.entity.Entity;
|
|
|
|
import org.bukkit.entity.Player;
|
2015-07-30 16:25:16 +02:00
|
|
|
|
2019-11-04 18:44:23 +01:00
|
|
|
import java.util.ArrayDeque;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
2016-07-25 07:19:29 +02:00
|
|
|
import java.util.Map.Entry;
|
2019-12-02 23:07:57 +01:00
|
|
|
import java.util.Objects;
|
2019-11-04 18:44:23 +01:00
|
|
|
import java.util.Set;
|
2019-09-12 01:04:29 +02:00
|
|
|
import java.util.concurrent.CompletableFuture;
|
2020-04-08 21:49:41 +02:00
|
|
|
import java.util.concurrent.Semaphore;
|
2016-07-25 07:19:29 +02:00
|
|
|
|
2019-12-02 23:07:57 +01:00
|
|
|
import static com.google.common.base.Preconditions.checkNotNull;
|
2020-04-16 06:11:03 +02:00
|
|
|
import static com.plotsquared.core.util.entity.EntityCategories.CAP_ANIMAL;
|
|
|
|
import static com.plotsquared.core.util.entity.EntityCategories.CAP_ENTITY;
|
|
|
|
import static com.plotsquared.core.util.entity.EntityCategories.CAP_MISC;
|
|
|
|
import static com.plotsquared.core.util.entity.EntityCategories.CAP_MOB;
|
|
|
|
import static com.plotsquared.core.util.entity.EntityCategories.CAP_MONSTER;
|
|
|
|
import static com.plotsquared.core.util.entity.EntityCategories.CAP_VEHICLE;
|
2019-12-02 23:07:57 +01:00
|
|
|
|
2016-04-05 18:37:11 +02:00
|
|
|
public class BukkitChunkManager extends ChunkManager {
|
2016-03-29 09:43:57 +02:00
|
|
|
|
2019-11-04 22:08:33 +01:00
|
|
|
public static boolean isIn(CuboidRegion region, int x, int z) {
|
|
|
|
return x >= region.getMinimumPoint().getX() && x <= region.getMaximumPoint().getX() && z >= region.getMinimumPoint().getZ() && z <= region.getMaximumPoint().getZ();
|
2016-04-05 18:37:11 +02:00
|
|
|
}
|
2016-03-29 09:43:57 +02:00
|
|
|
|
2018-08-10 17:01:10 +02:00
|
|
|
public static ContentMap swapChunk(World world1, World world2, Chunk pos1, Chunk pos2,
|
2019-11-04 22:08:33 +01:00
|
|
|
CuboidRegion r1, CuboidRegion r2) {
|
2016-04-05 18:37:11 +02:00
|
|
|
ContentMap map = new ContentMap();
|
2019-11-04 22:08:33 +01:00
|
|
|
int relX = r2.getMinimumPoint().getX() - r1.getMinimumPoint().getX();
|
|
|
|
int relZ = r2.getMinimumPoint().getZ() - r1.getMinimumPoint().getZ();
|
2016-02-14 02:01:18 +01:00
|
|
|
|
2016-04-05 18:37:11 +02:00
|
|
|
map.saveEntitiesIn(pos1, r1, relX, relZ, true);
|
|
|
|
map.saveEntitiesIn(pos2, r2, -relX, -relZ, true);
|
|
|
|
|
|
|
|
int sx = pos1.getX() << 4;
|
|
|
|
int sz = pos1.getZ() << 4;
|
|
|
|
|
|
|
|
String worldName1 = world1.getName();
|
|
|
|
String worldName2 = world2.getName();
|
|
|
|
|
2018-12-31 18:15:47 +01:00
|
|
|
BukkitWorld bukkitWorld1 = new BukkitWorld(world1);
|
|
|
|
BukkitWorld bukkitWorld2 = new BukkitWorld(world2);
|
|
|
|
|
2016-06-13 06:47:50 +02:00
|
|
|
LocalBlockQueue queue1 = GlobalBlockQueue.IMP.getNewQueue(worldName1, false);
|
|
|
|
LocalBlockQueue queue2 = GlobalBlockQueue.IMP.getNewQueue(worldName2, false);
|
|
|
|
|
2019-11-04 22:08:33 +01:00
|
|
|
for (int x = Math.max(r1.getMinimumPoint().getX(), sx); x <= Math.min(r1.getMaximumPoint().getX(), sx + 15); x++) {
|
|
|
|
for (int z = Math.max(r1.getMinimumPoint().getZ(), sz); z <= Math.min(r1.getMaximumPoint().getZ(), sz + 15); z++) {
|
2016-04-05 18:37:11 +02:00
|
|
|
for (int y = 0; y < 256; y++) {
|
|
|
|
Block block1 = world1.getBlockAt(x, y, z);
|
2019-01-16 00:58:21 +01:00
|
|
|
BaseBlock baseBlock1 = bukkitWorld1.getFullBlock(BlockVector3.at(x, y, z));
|
2018-12-17 20:57:21 +01:00
|
|
|
BlockData data1 = block1.getBlockData();
|
2018-12-31 18:15:47 +01:00
|
|
|
|
2016-04-05 18:37:11 +02:00
|
|
|
int xx = x + relX;
|
|
|
|
int zz = z + relZ;
|
2018-12-31 18:15:47 +01:00
|
|
|
|
2016-04-05 18:37:11 +02:00
|
|
|
Block block2 = world2.getBlockAt(xx, y, zz);
|
2018-12-31 18:15:47 +01:00
|
|
|
BaseBlock baseBlock2 = bukkitWorld2.getFullBlock(BlockVector3.at(xx, y, zz));
|
2018-12-17 20:57:21 +01:00
|
|
|
BlockData data2 = block2.getBlockData();
|
2018-12-31 18:15:47 +01:00
|
|
|
|
|
|
|
if (block1.isEmpty()) {
|
2019-01-16 00:58:21 +01:00
|
|
|
if (!block2.isEmpty()) {
|
2018-12-31 18:15:47 +01:00
|
|
|
queue1.setBlock(x, y, z, baseBlock2);
|
2019-01-16 00:58:21 +01:00
|
|
|
queue2.setBlock(xx, y, zz, WEExtent.AIRBASE);
|
2016-04-05 18:37:11 +02:00
|
|
|
}
|
2018-12-31 18:15:47 +01:00
|
|
|
} else if (block2.isEmpty()) {
|
2019-01-16 00:58:21 +01:00
|
|
|
queue1.setBlock(x, y, z, WEExtent.AIRBASE);
|
2018-12-31 18:15:47 +01:00
|
|
|
queue2.setBlock(xx, y, zz, baseBlock1);
|
|
|
|
} else if (block1.equals(block2)) {
|
2019-01-16 00:58:21 +01:00
|
|
|
if (!data1.matches(data2)) {
|
2018-12-17 20:57:21 +01:00
|
|
|
block1.setBlockData(data2);
|
|
|
|
block2.setBlockData(data1);
|
2016-04-05 18:37:11 +02:00
|
|
|
}
|
|
|
|
} else {
|
2018-12-31 18:15:47 +01:00
|
|
|
queue1.setBlock(x, y, z, baseBlock2);
|
|
|
|
queue2.setBlock(xx, y, zz, baseBlock1);
|
2016-04-05 18:37:11 +02:00
|
|
|
}
|
2016-03-29 09:43:57 +02:00
|
|
|
}
|
2015-02-23 06:29:45 +01:00
|
|
|
}
|
2016-03-29 09:43:57 +02:00
|
|
|
}
|
2016-06-13 06:47:50 +02:00
|
|
|
queue1.enqueue();
|
|
|
|
queue2.enqueue();
|
2016-04-05 18:37:11 +02:00
|
|
|
return map;
|
|
|
|
}
|
2016-03-29 09:43:57 +02:00
|
|
|
|
2019-11-04 18:44:23 +01:00
|
|
|
@Override public Set<BlockVector2> getChunkChunks(String world) {
|
|
|
|
Set<BlockVector2> chunks = super.getChunkChunks(world);
|
2020-04-08 21:49:41 +02:00
|
|
|
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 {
|
|
|
|
PlotSquared.debug("Attempting to make an asynchronous call to getLoadedChunks."
|
|
|
|
+ " Will halt the calling thread until completed.");
|
|
|
|
semaphore.acquire();
|
|
|
|
Bukkit.getScheduler().runTask(BukkitMain.getPlugin(BukkitMain.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();
|
|
|
|
});
|
|
|
|
semaphore.acquireUninterruptibly();
|
|
|
|
} catch (final Exception e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
2015-02-23 06:29:45 +01:00
|
|
|
}
|
2016-04-05 18:37:11 +02:00
|
|
|
return chunks;
|
|
|
|
}
|
2016-02-14 02:01:18 +01:00
|
|
|
|
2019-03-15 02:49:33 +01:00
|
|
|
@Override public int[] countEntities(Plot plot) {
|
|
|
|
int[] existing = (int[]) plot.getMeta("EntityCount");
|
|
|
|
if (existing != null && (System.currentTimeMillis() - (long) plot.getMeta("EntityCountTime")
|
|
|
|
< 1000)) {
|
|
|
|
return existing;
|
|
|
|
}
|
|
|
|
PlotArea area = plot.getArea();
|
2020-04-02 14:34:38 +02:00
|
|
|
World world = BukkitUtil.getWorld(area.getWorldName());
|
2019-03-15 02:49:33 +01:00
|
|
|
|
|
|
|
Location bot = plot.getBottomAbs();
|
|
|
|
Location top = plot.getTopAbs();
|
|
|
|
int bx = bot.getX() >> 4;
|
|
|
|
int bz = bot.getZ() >> 4;
|
|
|
|
|
|
|
|
int tx = top.getX() >> 4;
|
|
|
|
int tz = top.getZ() >> 4;
|
|
|
|
|
|
|
|
int size = tx - bx << 4;
|
|
|
|
|
|
|
|
Set<Chunk> chunks = new HashSet<>();
|
|
|
|
for (int X = bx; X <= tx; X++) {
|
|
|
|
for (int Z = bz; Z <= tz; Z++) {
|
|
|
|
if (world.isChunkLoaded(X, Z)) {
|
|
|
|
chunks.add(world.getChunkAt(X, Z));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean doWhole = false;
|
|
|
|
List<Entity> entities = null;
|
|
|
|
if (size > 200 && chunks.size() > 200) {
|
|
|
|
entities = world.getEntities();
|
|
|
|
if (entities.size() < 16 + size / 8) {
|
|
|
|
doWhole = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int[] count = new int[6];
|
|
|
|
if (doWhole) {
|
|
|
|
for (Entity entity : entities) {
|
|
|
|
org.bukkit.Location location = entity.getLocation();
|
2019-09-12 01:04:29 +02:00
|
|
|
PaperLib.getChunkAtAsync(location).thenAccept( chunk -> {
|
|
|
|
if (chunks.contains(chunk)) {
|
|
|
|
int X = chunk.getX();
|
|
|
|
int Z = chunk.getZ();
|
|
|
|
if (X > bx && X < tx && Z > bz && Z < tz) {
|
2019-03-15 02:49:33 +01:00
|
|
|
count(count, entity);
|
2019-09-12 01:04:29 +02:00
|
|
|
} else {
|
|
|
|
Plot other = area.getPlot(BukkitUtil.getLocation(location));
|
|
|
|
if (plot.equals(other)) {
|
|
|
|
count(count, entity);
|
|
|
|
}
|
2019-03-15 02:49:33 +01:00
|
|
|
}
|
|
|
|
}
|
2019-09-12 01:04:29 +02:00
|
|
|
});
|
2019-03-15 02:49:33 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (Chunk chunk : chunks) {
|
|
|
|
int X = chunk.getX();
|
|
|
|
int Z = chunk.getZ();
|
|
|
|
Entity[] entities1 = chunk.getEntities();
|
|
|
|
for (Entity entity : entities1) {
|
|
|
|
if (X == bx || X == tx || Z == bz || Z == tz) {
|
|
|
|
Plot other = area.getPlot(BukkitUtil.getLocation(entity));
|
|
|
|
if (plot.equals(other)) {
|
|
|
|
count(count, entity);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
count(count, entity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override public boolean copyRegion(Location pos1, Location pos2, Location newPos,
|
2018-08-10 17:01:10 +02:00
|
|
|
final Runnable whenDone) {
|
2016-04-05 18:37:11 +02:00
|
|
|
final int relX = newPos.getX() - pos1.getX();
|
|
|
|
final int relZ = newPos.getZ() - pos1.getZ();
|
2018-12-27 17:29:35 +01:00
|
|
|
|
2019-11-04 22:08:33 +01:00
|
|
|
final CuboidRegion region =
|
|
|
|
RegionUtil.createRegion(pos1.getX(), pos2.getX(), pos1.getZ(), pos2.getZ());
|
2016-04-05 18:37:11 +02:00
|
|
|
final World oldWorld = Bukkit.getWorld(pos1.getWorld());
|
2018-12-31 18:15:47 +01:00
|
|
|
final BukkitWorld oldBukkitWorld = new BukkitWorld(oldWorld);
|
2016-04-05 18:37:11 +02:00
|
|
|
final World newWorld = Bukkit.getWorld(newPos.getWorld());
|
2019-09-12 01:04:29 +02:00
|
|
|
assert newWorld != null;
|
|
|
|
assert oldWorld != null;
|
2016-04-05 18:37:11 +02:00
|
|
|
final String newWorldName = newWorld.getName();
|
|
|
|
final ContentMap map = new ContentMap();
|
2016-06-13 06:47:50 +02:00
|
|
|
final LocalBlockQueue queue = GlobalBlockQueue.IMP.getNewQueue(newWorldName, false);
|
2016-04-05 18:37:11 +02:00
|
|
|
ChunkManager.chunkTask(pos1, pos2, new RunnableVal<int[]>() {
|
2018-08-10 17:01:10 +02:00
|
|
|
@Override public void run(int[] value) {
|
2016-04-05 18:37:11 +02:00
|
|
|
int bx = value[2];
|
|
|
|
int bz = value[3];
|
|
|
|
int tx = value[4];
|
|
|
|
int tz = value[5];
|
2019-11-04 18:44:23 +01:00
|
|
|
BlockVector2 loc = BlockVector2.at(value[0], value[1]);
|
|
|
|
int cxx = loc.getX() << 4;
|
|
|
|
int czz = loc.getZ() << 4;
|
|
|
|
PaperLib.getChunkAtAsync(oldWorld, loc.getX(), loc.getZ())
|
2019-09-12 01:04:29 +02:00
|
|
|
.thenAccept(chunk1 -> map.saveEntitiesIn(chunk1, region)).thenRun(() -> {
|
|
|
|
for (int x = bx & 15; x <= (tx & 15); x++) {
|
|
|
|
for (int z = bz & 15; z <= (tz & 15); z++) {
|
|
|
|
map.saveBlocks(oldBukkitWorld, 256, cxx + x, czz + z, relX, relZ);
|
|
|
|
}
|
2016-03-29 09:43:57 +02:00
|
|
|
}
|
2019-09-12 01:04:29 +02:00
|
|
|
});
|
2015-02-23 06:29:45 +01:00
|
|
|
}
|
2018-12-21 00:33:24 +01:00
|
|
|
}, () -> {
|
2018-12-31 18:15:47 +01:00
|
|
|
for (Entry<PlotLoc, BaseBlock[]> entry : map.allBlocks.entrySet()) {
|
2018-12-21 00:33:24 +01:00
|
|
|
PlotLoc loc = entry.getKey();
|
2018-12-31 18:15:47 +01:00
|
|
|
BaseBlock[] blocks = entry.getValue();
|
2018-12-21 00:33:24 +01:00
|
|
|
for (int y = 0; y < blocks.length; y++) {
|
|
|
|
if (blocks[y] != null) {
|
2018-12-31 18:15:47 +01:00
|
|
|
BaseBlock block = blocks[y];
|
2019-04-04 18:26:10 +02:00
|
|
|
queue.setBlock(loc.getX(), y, loc.getZ(), block);
|
2016-03-29 09:43:57 +02:00
|
|
|
}
|
2015-05-21 10:42:00 +02:00
|
|
|
}
|
2015-02-23 06:29:45 +01:00
|
|
|
}
|
2018-12-21 00:33:24 +01:00
|
|
|
queue.enqueue();
|
2019-09-09 21:15:44 +02:00
|
|
|
GlobalBlockQueue.IMP.addEmptyTask(() -> {
|
2018-12-31 18:15:47 +01:00
|
|
|
//map.restoreBlocks(newWorld, 0, 0);
|
2018-12-21 00:33:24 +01:00
|
|
|
map.restoreEntities(newWorld, relX, relZ);
|
|
|
|
TaskManager.runTask(whenDone);
|
|
|
|
});
|
2016-04-05 18:37:11 +02:00
|
|
|
}, 5);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-03-15 02:49:33 +01:00
|
|
|
@Override public boolean regenerateRegion(final Location pos1, final Location pos2,
|
2018-08-10 17:01:10 +02:00
|
|
|
final boolean ignoreAugment, final Runnable whenDone) {
|
2016-04-05 18:37:11 +02:00
|
|
|
final String world = pos1.getWorld();
|
|
|
|
|
|
|
|
final int p1x = pos1.getX();
|
|
|
|
final int p1z = pos1.getZ();
|
|
|
|
final int p2x = pos2.getX();
|
|
|
|
final int p2z = pos2.getZ();
|
|
|
|
final int bcx = p1x >> 4;
|
|
|
|
final int bcz = p1z >> 4;
|
|
|
|
final int tcx = p2x >> 4;
|
|
|
|
final int tcz = p2z >> 4;
|
|
|
|
|
2019-11-04 18:44:23 +01:00
|
|
|
final List<BlockVector2> chunks = new ArrayList<>();
|
2016-04-05 18:37:11 +02:00
|
|
|
|
|
|
|
for (int x = bcx; x <= tcx; x++) {
|
|
|
|
for (int z = bcz; z <= tcz; z++) {
|
2019-11-04 18:44:23 +01:00
|
|
|
chunks.add(BlockVector2.at(x, z));
|
2015-02-23 06:29:45 +01:00
|
|
|
}
|
2016-04-05 18:37:11 +02:00
|
|
|
}
|
|
|
|
final World worldObj = Bukkit.getWorld(world);
|
2019-12-02 23:07:57 +01:00
|
|
|
checkNotNull(worldObj, "Critical error during regeneration.");
|
2018-12-31 18:15:47 +01:00
|
|
|
final BukkitWorld bukkitWorldObj = new BukkitWorld(worldObj);
|
2016-04-05 18:37:11 +02:00
|
|
|
TaskManager.runTask(new Runnable() {
|
2018-08-10 17:01:10 +02:00
|
|
|
@Override public void run() {
|
2016-04-05 18:37:11 +02:00
|
|
|
long start = System.currentTimeMillis();
|
|
|
|
while (!chunks.isEmpty() && System.currentTimeMillis() - start < 5) {
|
2019-11-04 18:44:23 +01:00
|
|
|
final BlockVector2 chunk = chunks.remove(0);
|
|
|
|
int x = chunk.getX();
|
|
|
|
int z = chunk.getZ();
|
2016-04-05 18:37:11 +02:00
|
|
|
int xxb = x << 4;
|
|
|
|
int zzb = z << 4;
|
|
|
|
int xxt = xxb + 15;
|
|
|
|
int zzt = zzb + 15;
|
2020-04-07 23:39:56 +02:00
|
|
|
PaperLib.getChunkAtAsync(worldObj, x, z, false).thenAccept(chunkObj -> {
|
|
|
|
if (chunkObj == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
final LocalBlockQueue queue = GlobalBlockQueue.IMP.getNewQueue(world, false);
|
|
|
|
if (xxb >= p1x && xxt <= p2x && zzb >= p1z && zzt <= p2z) {
|
|
|
|
AugmentedUtils.bypass(ignoreAugment,
|
|
|
|
() -> queue.regenChunkSafe(chunk.getX(), chunk.getZ()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
boolean checkX1 = false;
|
2016-04-05 18:37:11 +02:00
|
|
|
|
2020-04-07 23:39:56 +02:00
|
|
|
int xxb2;
|
2016-04-05 18:37:11 +02:00
|
|
|
|
2020-04-07 23:39:56 +02:00
|
|
|
if (x == bcx) {
|
|
|
|
xxb2 = p1x - 1;
|
|
|
|
checkX1 = true;
|
|
|
|
} else {
|
|
|
|
xxb2 = xxb;
|
|
|
|
}
|
|
|
|
boolean checkX2 = false;
|
|
|
|
int xxt2;
|
|
|
|
if (x == tcx) {
|
|
|
|
xxt2 = p2x + 1;
|
|
|
|
checkX2 = true;
|
|
|
|
} else {
|
|
|
|
xxt2 = xxt;
|
|
|
|
}
|
|
|
|
boolean checkZ1 = false;
|
|
|
|
int zzb2;
|
|
|
|
if (z == bcz) {
|
|
|
|
zzb2 = p1z - 1;
|
|
|
|
checkZ1 = true;
|
|
|
|
} else {
|
|
|
|
zzb2 = zzb;
|
|
|
|
}
|
|
|
|
boolean checkZ2 = false;
|
|
|
|
int zzt2;
|
|
|
|
if (z == tcz) {
|
|
|
|
zzt2 = p2z + 1;
|
|
|
|
checkZ2 = true;
|
|
|
|
} else {
|
|
|
|
zzt2 = zzt;
|
|
|
|
}
|
|
|
|
final ContentMap map = new ContentMap();
|
|
|
|
if (checkX1) {
|
|
|
|
map.saveRegion(bukkitWorldObj, xxb, xxb2, zzb2, zzt2); //
|
|
|
|
}
|
|
|
|
if (checkX2) {
|
|
|
|
map.saveRegion(bukkitWorldObj, xxt2, xxt, zzb2, zzt2); //
|
|
|
|
}
|
|
|
|
if (checkZ1) {
|
|
|
|
map.saveRegion(bukkitWorldObj, xxb2, xxt2, zzb, zzb2); //
|
|
|
|
}
|
|
|
|
if (checkZ2) {
|
|
|
|
map.saveRegion(bukkitWorldObj, xxb2, xxt2, zzt2, zzt); //
|
|
|
|
}
|
|
|
|
if (checkX1 && checkZ1) {
|
|
|
|
map.saveRegion(bukkitWorldObj, xxb, xxb2, zzb, zzb2); //
|
|
|
|
}
|
|
|
|
if (checkX2 && checkZ1) {
|
|
|
|
map.saveRegion(bukkitWorldObj, xxt2, xxt, zzb, zzb2); // ?
|
|
|
|
}
|
|
|
|
if (checkX1 && checkZ2) {
|
|
|
|
map.saveRegion(bukkitWorldObj, xxb, xxb2, zzt2, zzt); // ?
|
|
|
|
}
|
|
|
|
if (checkX2 && checkZ2) {
|
|
|
|
map.saveRegion(bukkitWorldObj, xxt2, xxt, zzt2, zzt); //
|
|
|
|
}
|
|
|
|
CuboidRegion currentPlotClear =
|
|
|
|
RegionUtil.createRegion(pos1.getX(), pos2.getX(), pos1.getZ(), pos2.getZ());
|
|
|
|
map.saveEntitiesOut(chunkObj, currentPlotClear);
|
|
|
|
AugmentedUtils.bypass(ignoreAugment,
|
|
|
|
() -> setChunkInPlotArea(null, new RunnableVal<ScopedLocalBlockQueue>() {
|
|
|
|
@Override public void run(ScopedLocalBlockQueue value) {
|
|
|
|
Location min = value.getMin();
|
|
|
|
int bx = min.getX();
|
|
|
|
int bz = min.getZ();
|
|
|
|
for (int x1 = 0; x1 < 16; x1++) {
|
|
|
|
for (int z1 = 0; z1 < 16; z1++) {
|
|
|
|
PlotLoc plotLoc = new PlotLoc(bx + x1, bz + z1);
|
|
|
|
BaseBlock[] ids = map.allBlocks.get(plotLoc);
|
|
|
|
if (ids != null) {
|
|
|
|
for (int y = 0; y < Math.min(128, ids.length); y++) {
|
|
|
|
BaseBlock id = ids[y];
|
|
|
|
if (id != null) {
|
|
|
|
value.setBlock(x1, y, z1, id);
|
|
|
|
} else {
|
|
|
|
value.setBlock(x1, y, z1, BlockTypes.AIR.getDefaultState());
|
|
|
|
}
|
2018-12-26 18:21:06 +01:00
|
|
|
}
|
2020-04-07 23:39:56 +02:00
|
|
|
for (int y = Math.min(128, ids.length);
|
|
|
|
y < ids.length; y++) {
|
|
|
|
BaseBlock id = ids[y];
|
|
|
|
if (id != null) {
|
|
|
|
value.setBlock(x1, y, z1, id);
|
|
|
|
}
|
2018-12-26 18:21:06 +01:00
|
|
|
}
|
2016-04-05 18:37:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-07 23:39:56 +02:00
|
|
|
}, world, chunk));
|
|
|
|
//map.restoreBlocks(worldObj, 0, 0);
|
|
|
|
map.restoreEntities(worldObj, 0, 0);
|
|
|
|
});
|
2016-04-05 18:37:11 +02:00
|
|
|
}
|
|
|
|
if (!chunks.isEmpty()) {
|
|
|
|
TaskManager.runTaskLater(this, 1);
|
|
|
|
} else {
|
|
|
|
TaskManager.runTaskLater(whenDone, 1);
|
2015-05-21 10:42:00 +02:00
|
|
|
}
|
2015-02-23 06:29:45 +01:00
|
|
|
}
|
2016-04-05 18:37:11 +02:00
|
|
|
});
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-12-02 23:07:57 +01:00
|
|
|
@Override public CompletableFuture<?> loadChunk(String world, BlockVector2 chunkLoc, boolean force) {
|
2019-11-04 18:44:23 +01:00
|
|
|
return PaperLib.getChunkAtAsync(BukkitUtil.getWorld(world),chunkLoc.getX(), chunkLoc.getZ(), force);
|
2019-03-15 02:49:33 +01:00
|
|
|
}
|
|
|
|
|
2019-09-08 20:02:45 +02:00
|
|
|
@Override
|
2019-11-04 18:44:23 +01:00
|
|
|
public void unloadChunk(final String world, final BlockVector2 chunkLoc, final boolean save) {
|
2019-03-15 02:49:33 +01:00
|
|
|
if (!PlotSquared.get().isMainThread(Thread.currentThread())) {
|
2019-09-08 20:02:45 +02:00
|
|
|
TaskManager.runTask(
|
2019-11-04 18:44:23 +01:00
|
|
|
() -> BukkitUtil.getWorld(world).unloadChunk(chunkLoc.getX(), chunkLoc.getZ(), save));
|
2019-03-15 02:49:33 +01:00
|
|
|
} else {
|
2019-11-04 18:44:23 +01:00
|
|
|
BukkitUtil.getWorld(world).unloadChunk(chunkLoc.getX(), chunkLoc.getZ(), save);
|
2019-03-15 02:49:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override public void clearAllEntities(Location pos1, Location pos2) {
|
2016-04-05 18:37:11 +02:00
|
|
|
String world = pos1.getWorld();
|
|
|
|
List<Entity> entities = BukkitUtil.getEntities(world);
|
|
|
|
int bx = pos1.getX();
|
|
|
|
int bz = pos1.getZ();
|
|
|
|
int tx = pos2.getX();
|
|
|
|
int tz = pos2.getZ();
|
|
|
|
for (Entity entity : entities) {
|
|
|
|
if (!(entity instanceof Player)) {
|
2016-06-02 17:38:47 +02:00
|
|
|
org.bukkit.Location location = entity.getLocation();
|
2018-08-10 17:01:10 +02:00
|
|
|
if (location.getX() >= bx && location.getX() <= tx && location.getZ() >= bz
|
|
|
|
&& location.getZ() <= tz) {
|
2018-08-19 22:18:58 +02:00
|
|
|
if (entity.hasMetadata("ps-tmp-teleport")) {
|
|
|
|
continue;
|
|
|
|
}
|
2016-04-05 18:37:11 +02:00
|
|
|
entity.remove();
|
2015-02-23 06:29:45 +01:00
|
|
|
}
|
2016-02-14 02:01:18 +01:00
|
|
|
}
|
|
|
|
}
|
2016-04-05 18:37:11 +02:00
|
|
|
}
|
2016-02-14 02:01:18 +01:00
|
|
|
|
2019-03-15 02:49:33 +01:00
|
|
|
@Override public void swap(Location bot1, Location top1, Location bot2, Location top2,
|
2018-08-10 17:01:10 +02:00
|
|
|
final Runnable whenDone) {
|
2019-11-04 22:08:33 +01:00
|
|
|
CuboidRegion region1 =
|
|
|
|
RegionUtil.createRegion(bot1.getX(), top1.getX(), bot1.getZ(), top1.getZ());
|
|
|
|
CuboidRegion region2 =
|
|
|
|
RegionUtil.createRegion(bot2.getX(), top2.getX(), bot2.getZ(), top2.getZ());
|
2016-04-05 18:37:11 +02:00
|
|
|
final World world1 = Bukkit.getWorld(bot1.getWorld());
|
2019-12-02 23:07:57 +01:00
|
|
|
final World world2 = Bukkit.getWorld(bot2.getWorld());
|
|
|
|
checkNotNull(world1,"Critical error during swap.");
|
|
|
|
checkNotNull(world2,"Critical error during swap.");
|
2016-04-05 18:37:11 +02:00
|
|
|
int relX = bot2.getX() - bot1.getX();
|
|
|
|
int relZ = bot2.getZ() - bot1.getZ();
|
|
|
|
|
|
|
|
final ArrayDeque<ContentMap> maps = new ArrayDeque<>();
|
|
|
|
|
|
|
|
for (int x = bot1.getX() >> 4; x <= top1.getX() >> 4; x++) {
|
|
|
|
for (int z = bot1.getZ() >> 4; z <= top1.getZ() >> 4; z++) {
|
|
|
|
Chunk chunk1 = world1.getChunkAt(x, z);
|
|
|
|
Chunk chunk2 = world2.getChunkAt(x + (relX >> 4), z + (relZ >> 4));
|
|
|
|
maps.add(swapChunk(world1, world2, chunk1, chunk2, region1, region2));
|
2016-02-14 02:01:18 +01:00
|
|
|
}
|
|
|
|
}
|
2019-09-09 21:15:44 +02:00
|
|
|
GlobalBlockQueue.IMP.addEmptyTask(() -> {
|
2018-12-20 02:23:48 +01:00
|
|
|
for (ContentMap map : maps) {
|
|
|
|
map.restoreEntities(world1, 0, 0);
|
|
|
|
TaskManager.runTaskLater(whenDone, 1);
|
2016-04-05 18:37:11 +02:00
|
|
|
}
|
|
|
|
});
|
2016-02-14 02:01:18 +01:00
|
|
|
}
|
|
|
|
|
2016-04-05 18:37:11 +02:00
|
|
|
private void count(int[] count, Entity entity) {
|
2020-04-12 19:30:50 +02:00
|
|
|
final com.sk89q.worldedit.world.entity.EntityType entityType =
|
|
|
|
BukkitAdapter.adapt(entity.getType());
|
|
|
|
|
|
|
|
if (EntityCategories.PLAYER.contains(entityType)) {
|
|
|
|
return;
|
|
|
|
} else if (EntityCategories.PROJECTILE.contains(entityType) ||
|
|
|
|
EntityCategories.OTHER.contains(entityType) ||
|
|
|
|
EntityCategories.HANGING.contains(entityType)) {
|
|
|
|
count[CAP_MISC]++;
|
|
|
|
} else if (EntityCategories.ANIMAL.contains(entityType) ||
|
|
|
|
EntityCategories.VILLAGER.contains(entityType) ||
|
|
|
|
EntityCategories.TAMEABLE.contains(entityType)) {
|
|
|
|
count[CAP_MOB]++;
|
|
|
|
count[CAP_ANIMAL]++;
|
|
|
|
} else if (EntityCategories.VEHICLE.contains(entityType)) {
|
|
|
|
count[CAP_VEHICLE]++;
|
|
|
|
} else if (EntityCategories.HOSTILE.contains(entityType)) {
|
|
|
|
count[CAP_MOB]++;
|
|
|
|
count[CAP_MONSTER]++;
|
2016-04-05 18:37:11 +02:00
|
|
|
}
|
2020-04-12 19:30:50 +02:00
|
|
|
count[CAP_ENTITY]++;
|
2016-04-05 18:37:11 +02:00
|
|
|
}
|
2016-02-14 02:01:18 +01:00
|
|
|
|
2019-03-15 02:49:33 +01:00
|
|
|
|
2016-04-05 18:37:11 +02:00
|
|
|
public static class ContentMap {
|
2016-02-14 02:01:18 +01:00
|
|
|
|
2016-09-14 00:10:01 +02:00
|
|
|
final Set<EntityWrapper> entities;
|
2018-12-31 18:15:47 +01:00
|
|
|
final Map<PlotLoc, BaseBlock[]> allBlocks;
|
2016-09-14 00:10:01 +02:00
|
|
|
|
|
|
|
ContentMap() {
|
2016-04-05 18:37:11 +02:00
|
|
|
this.entities = new HashSet<>();
|
|
|
|
this.allBlocks = new HashMap<>();
|
|
|
|
}
|
|
|
|
|
2018-12-31 18:15:47 +01:00
|
|
|
public void saveRegion(BukkitWorld world, int x1, int x2, int z1, int z2) {
|
2016-04-05 18:37:11 +02:00
|
|
|
if (z1 > z2) {
|
|
|
|
int tmp = z1;
|
|
|
|
z1 = z2;
|
|
|
|
z2 = tmp;
|
|
|
|
}
|
|
|
|
if (x1 > x2) {
|
|
|
|
int tmp = x1;
|
|
|
|
x1 = x2;
|
|
|
|
x2 = tmp;
|
|
|
|
}
|
|
|
|
for (int x = x1; x <= x2; x++) {
|
|
|
|
for (int z = z1; z <= z2; z++) {
|
2018-12-31 18:15:47 +01:00
|
|
|
saveBlocks(world, 256, x, z, 0, 0);
|
2016-04-05 18:37:11 +02:00
|
|
|
}
|
2016-02-14 02:01:18 +01:00
|
|
|
}
|
|
|
|
}
|
2016-04-05 18:37:11 +02:00
|
|
|
|
2019-11-04 22:08:33 +01:00
|
|
|
void saveEntitiesOut(Chunk chunk, CuboidRegion region) {
|
2016-04-05 18:37:11 +02:00
|
|
|
for (Entity entity : chunk.getEntities()) {
|
2019-09-08 20:02:45 +02:00
|
|
|
Location location = BukkitUtil.getLocation(entity);
|
|
|
|
int x = location.getX();
|
|
|
|
int z = location.getZ();
|
2016-04-05 18:37:11 +02:00
|
|
|
if (isIn(region, x, z)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (entity.getVehicle() != null) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-08-19 22:18:58 +02:00
|
|
|
EntityWrapper wrap = new ReplicatingEntityWrapper(entity, (short) 2);
|
|
|
|
wrap.saveEntity();
|
2016-04-05 18:37:11 +02:00
|
|
|
this.entities.add(wrap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-04 22:08:33 +01:00
|
|
|
void saveEntitiesIn(Chunk chunk, CuboidRegion region) {
|
2019-04-24 22:11:24 +02:00
|
|
|
saveEntitiesIn(chunk, region, 0, 0, false);
|
|
|
|
}
|
|
|
|
|
2019-11-04 22:08:33 +01:00
|
|
|
void saveEntitiesIn(Chunk chunk, CuboidRegion region, int offsetX, int offsetZ,
|
2018-08-10 17:01:10 +02:00
|
|
|
boolean delete) {
|
2016-04-05 18:37:11 +02:00
|
|
|
for (Entity entity : chunk.getEntities()) {
|
2019-09-08 20:02:45 +02:00
|
|
|
Location location = BukkitUtil.getLocation(entity);
|
|
|
|
int x = location.getX();
|
|
|
|
int z = location.getZ();
|
2016-04-05 18:37:11 +02:00
|
|
|
if (!isIn(region, x, z)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (entity.getVehicle() != null) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-08-19 22:18:58 +02:00
|
|
|
EntityWrapper wrap = new ReplicatingEntityWrapper(entity, (short) 2);
|
2016-04-05 18:37:11 +02:00
|
|
|
wrap.x += offsetX;
|
|
|
|
wrap.z += offsetZ;
|
2018-08-19 22:18:58 +02:00
|
|
|
wrap.saveEntity();
|
2016-04-05 18:37:11 +02:00
|
|
|
this.entities.add(wrap);
|
|
|
|
if (delete) {
|
|
|
|
if (!(entity instanceof Player)) {
|
|
|
|
entity.remove();
|
2015-07-31 12:47:10 +02:00
|
|
|
}
|
2016-04-05 18:37:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-02-14 02:01:18 +01:00
|
|
|
|
2019-04-24 22:11:24 +02:00
|
|
|
void restoreEntities(World world, int xOffset, int zOffset) {
|
2016-04-05 18:37:11 +02:00
|
|
|
for (EntityWrapper entity : this.entities) {
|
|
|
|
try {
|
|
|
|
entity.spawn(world, xOffset, zOffset);
|
|
|
|
} catch (Exception e) {
|
2018-11-14 14:19:56 +01:00
|
|
|
PlotSquared.debug("Failed to restore entity (e): " + e.toString());
|
2016-04-05 18:37:11 +02:00
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.entities.clear();
|
|
|
|
}
|
2016-02-14 02:01:18 +01:00
|
|
|
|
2019-03-15 02:49:33 +01:00
|
|
|
//todo optimize maxY
|
2019-04-24 22:11:24 +02:00
|
|
|
void saveBlocks(BukkitWorld world, int maxY, int x, int z, int offsetX, int offsetZ) {
|
2016-04-05 18:37:11 +02:00
|
|
|
maxY = Math.min(255, maxY);
|
2019-08-06 22:08:56 +02:00
|
|
|
BaseBlock[] ids = new BaseBlock[maxY + 1];
|
2016-04-05 18:37:11 +02:00
|
|
|
for (short y = 0; y <= maxY; y++) {
|
2018-12-31 18:15:47 +01:00
|
|
|
BaseBlock block = world.getFullBlock(BlockVector3.at(x, y, z));
|
|
|
|
ids[y] = block;
|
2016-04-05 18:37:11 +02:00
|
|
|
}
|
|
|
|
PlotLoc loc = new PlotLoc(x + offsetX, z + offsetZ);
|
|
|
|
this.allBlocks.put(loc, ids);
|
2015-04-14 16:35:01 +02:00
|
|
|
}
|
|
|
|
}
|
2015-02-23 06:29:45 +01:00
|
|
|
}
|