Disabled /is biome in 1.16 and trying to resolve with a thread pool

This commit is contained in:
Fabrizio La Rosa 2020-06-27 04:53:59 +02:00
parent b1be709c3c
commit 8602836406
12 changed files with 221 additions and 71 deletions

View File

@ -3,6 +3,7 @@ package com.songoda.skyblock;
import com.songoda.core.SongodaCore;
import com.songoda.core.SongodaPlugin;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerProject;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.core.configuration.Config;
import com.songoda.core.gui.GuiManager;
@ -117,13 +118,10 @@ public class SkyBlock extends SongodaPlugin {
return;
}
try {
Class.forName("com.destroystokyo.paper.PaperConfig");
paper = true;
if(paper = ServerProject.isServer(ServerProject.PAPER)){
paperAsync = Bukkit.spigot().getPaperConfig().getBoolean("settings.async-chunks.enable", false);
this.getLogger().info("Enabling Paper hooks");
} catch (ClassNotFoundException ignored) {
paper = false;
} else {
PaperLib.suggestPaper(this);
}
@ -229,6 +227,10 @@ public class SkyBlock extends SongodaPlugin {
@Override
public void onPluginDisable() {
if (this.biomeManager != null) {
this.biomeManager.onDisable();
}
if (this.userCacheManager != null) {
this.userCacheManager.onDisable();
}

View File

@ -19,6 +19,6 @@ public class BiomeManager {
Preconditions.checkArgument(island != null, "Cannot set biome to null island");
Preconditions.checkArgument(biome != null, "Cannot set biome to null biome");
this.biomeManager.setBiome(island.getIsland(), biome);
this.biomeManager.setBiome(island.getIsland(), biome, null);
}
}

View File

@ -2,78 +2,143 @@ package com.songoda.skyblock.biome;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.skyblock.SkyBlock;
import com.songoda.skyblock.blockscanner.ChunkLoader;
import com.songoda.skyblock.island.Island;
import com.songoda.skyblock.island.IslandEnvironment;
import com.songoda.skyblock.island.IslandWorld;
import com.songoda.skyblock.blockscanner.ChunkLoader;
import com.songoda.skyblock.utils.version.NMSUtil;
import org.bukkit.*;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.block.Biome;
import org.bukkit.entity.Player;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
public class BiomeManager {
private final SkyBlock skyblock;
private final List<Island> updatingIslands;
private final List<ExecutorService> pools;
public BiomeManager(SkyBlock skyblock) {
this.skyblock = skyblock;
this.updatingIslands = new ArrayList<>();
this.pools = new ArrayList<>();
}
public boolean isUpdating(Island island) {
return updatingIslands.contains(island);
}
public void addUpdatingIsland(Island island) {
updatingIslands.add(island);
}
public void removeUpdatingIsland(Island island) {
updatingIslands.remove(island);
}
public void setBiome(Island island, Biome biome) {
public void setBiome(Island island, Biome biome, CompleteTask task) {
addUpdatingIsland(island);
if (island.getLocation(IslandWorld.Normal, IslandEnvironment.Island) == null) return;
if(skyblock.isPaperAsync()){
// We keep it sequentially in order to use less RAM
ExecutorService threadPool = Executors.newFixedThreadPool(4);
pools.add(threadPool);
ChunkLoader.startChunkLoadingPerChunk(island, IslandWorld.Normal, skyblock.isPaperAsync(), (asyncChunk, syncChunk) -> {
Chunk chunk = asyncChunk.join();
setChunkBiome(biome, chunk);
updateBiomePacket(island, chunk);
});
if(ServerVersion.isServerVersionAtLeast(ServerVersion.V1_16)){ // TODO Should be 1.15 but it works fine there
setChunkBiome3D(island, biome, chunk, threadPool);
} else {
setChunkBiome2D(island, biome, chunk);
}
}, (island1 -> {
removeUpdatingIsland(island1);
if(task != null) {
task.onCompleteUpdate();
}
threadPool.shutdown();
pools.remove(threadPool);
}));
} else {
ChunkLoader.startChunkLoading(island, IslandWorld.Normal, skyblock.isPaperAsync(), (asyncChunks, syncChunks) -> {
Bukkit.getScheduler().runTaskAsynchronously(skyblock, () -> {
syncChunks.forEach(chunk -> {
setChunkBiome(biome, chunk);
updateBiomePacket(island, chunk);
});
});
});
ExecutorService threadPool = Executors.newFixedThreadPool(4);
pools.add(threadPool);
ChunkLoader.startChunkLoadingPerChunk(island, IslandWorld.Normal, skyblock.isPaperAsync(), (asyncChunk, syncChunk) -> {
if(ServerVersion.isServerVersionAtLeast(ServerVersion.V1_16)){ // TODO Should be 1.15 but it works fine there
setChunkBiome3D(island, biome, syncChunk, threadPool);
} else {
setChunkBiome2D(island, biome, syncChunk);
}
}, (island1 -> {
removeUpdatingIsland(island1);
if(task != null) {
task.onCompleteUpdate();
}
threadPool.shutdown();
pools.remove(threadPool);
}));
}
}
private void setChunkBiome(Biome biome, Chunk chunk) {
private void setChunkBiome2D(Island island, Biome biome, Chunk chunk) {
for(int xx = 0; xx < 16; xx++){
for(int zz = 0; zz < 16; zz++){
//if(ServerVersion.isServerVersionBelow(ServerVersion.V1_15)){
chunk.getBlock(xx, 0, zz).setBiome(biome);
//} else {
// for(int i = 0; i<256; i+=2){
// chunk.getBlock(xx, i, zz).setBiome(biome);
// }
//}
if(!chunk.getWorld().getBiome(xx, zz).equals(biome)){
chunk.getWorld().setBiome(xx, zz, biome);
}
}
}
updateBiomePacket(island, chunk);
}
private void setChunkBiome3D(Island island, Biome biome, Chunk chunk, ExecutorService pool) {
for(int i = 0; i<256; i+=16){
int finalI = i;
pool.execute(() -> {
for(int x = 0; x < 16; x++){
for(int z = 0; z < 16; z++){
for(int y = 0; y<16; y++){
chunk.getWorld().setBiome(x, y * finalI, z, biome);
if(!chunk.getWorld().getBiome(x, y * finalI, z).equals(biome)){
}
}
}
}
});
}
updateBiomePacket(island, chunk);
}
private Class<?> packetPlayOutMapChunkClass;
private Class<?> chunkClass;
private void updateBiomePacket(Island island, Chunk chunk) {
if (packetPlayOutMapChunkClass == null) {
packetPlayOutMapChunkClass = NMSUtil.getNMSClass("PacketPlayOutMapChunk");
chunkClass = NMSUtil.getNMSClass("Chunk");
}
Class<?> packetPlayOutMapChunkClass;
Class<?> chunkClass;
packetPlayOutMapChunkClass = NMSUtil.getNMSClass("PacketPlayOutMapChunk");
chunkClass = NMSUtil.getNMSClass("Chunk");
for (Player player : skyblock.getIslandManager().getPlayersAtIsland(island, IslandWorld.Normal)) {
try {
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)) {
NMSUtil.sendPacket(player,
packetPlayOutMapChunkClass.getConstructor(chunkClass, int.class).newInstance(player
.getLocation().getChunk().getClass().getMethod("getHandle").invoke(chunk),
65535));
if(ServerVersion.isServerVersionAtLeast(ServerVersion.V1_16)) {
NMSUtil.sendPacket(player,
packetPlayOutMapChunkClass.getConstructor(chunkClass, int.class, boolean.class).newInstance(player
.getLocation().getChunk().getClass().getMethod("getHandle").invoke(chunk),
65535, true));
} else {
NMSUtil.sendPacket(player,
packetPlayOutMapChunkClass.getConstructor(chunkClass, int.class).newInstance(player
.getLocation().getChunk().getClass().getMethod("getHandle").invoke(chunk),
65535));
}
} else {
NMSUtil.sendPacket(player,
packetPlayOutMapChunkClass.getConstructor(chunkClass, boolean.class, int.class)
@ -86,4 +151,14 @@ public class BiomeManager {
}
}
}
public void onDisable() {
for(ExecutorService pool : pools){
pool.shutdownNow();
}
}
public interface CompleteTask {
void onCompleteUpdate();
}
}

View File

@ -24,21 +24,25 @@ public class ChunkLoader extends BukkitRunnable {
private boolean chunkForChunk;
private boolean paper;
private World world;
private Island island;
private int x;
private int z;
private int minZ;
private int maxX;
private int maxZ;
private int chunkPerTick;
private CompleteTask completeTask;
private ChunkLoader(Island island, IslandWorld islandWorld, boolean paper, boolean chunkForChunk, ChunkForChunkScannerTask chunkTask) {
private ChunkLoader(Island island, IslandWorld islandWorld, boolean paper, boolean chunkForChunk, ChunkForChunkScannerTask chunkTask, CompleteTask complete) {
chunkPerTick = SkyBlock.getInstance().getFileManager()
.getConfig(new File(SkyBlock.getInstance().getDataFolder(), "config.yml"))
.getFileConfiguration().getInt("Island.Performance.ChunkPerTick", 25);
this.completeTask = complete;
this.chunkTask = chunkTask;
this.chunkForChunk = chunkForChunk;
this.paper = paper;
this.island = island;
Location islandLocation = island.getLocation(islandWorld, IslandEnvironment.Island);
if (islandLocation == null) return;
@ -64,14 +68,16 @@ public class ChunkLoader extends BukkitRunnable {
}
}
private ChunkLoader(Island island, IslandWorld islandWorld, boolean paper, boolean chunkForChunk, ChunkScannerTask generalTask) {
private ChunkLoader(Island island, IslandWorld islandWorld, boolean paper, boolean chunkForChunk, ChunkScannerTask generalTask, CompleteTask complete) {
chunkPerTick = SkyBlock.getInstance().getFileManager()
.getConfig(new File(SkyBlock.getInstance().getDataFolder(), "config.yml"))
.getFileConfiguration().getInt("Island.Performance.ChunkPerTick", 25);
this.completeTask = complete;
this.generalTask = generalTask;
this.chunkForChunk = chunkForChunk;
this.paper = paper;
this.island = island;
Location islandLocation = island.getLocation(islandWorld, IslandEnvironment.Island);
if (islandLocation == null) return;
@ -129,18 +135,21 @@ public class ChunkLoader extends BukkitRunnable {
if(generalTask != null) {
generalTask.onComplete(asyncPositions, syncPositions);
}
if(completeTask != null) {
completeTask.onComplete(island);
}
this.cancel();
return;
}
}
}
public static void startChunkLoading(Island island, IslandWorld islandWorld, boolean paper, ChunkScannerTask task){
new ChunkLoader(island, islandWorld, paper, false, task);
public static void startChunkLoading(Island island, IslandWorld islandWorld, boolean paper, ChunkScannerTask task, CompleteTask complete){
new ChunkLoader(island, islandWorld, paper, false, task, complete);
}
public static void startChunkLoadingPerChunk(Island island, IslandWorld islandWorld, boolean paper, ChunkForChunkScannerTask task){
new ChunkLoader(island, islandWorld, paper, true, task);
public static void startChunkLoadingPerChunk(Island island, IslandWorld islandWorld, boolean paper, ChunkForChunkScannerTask task, CompleteTask complete){
new ChunkLoader(island, islandWorld, paper, true, task, complete);
}
public interface ChunkScannerTask {
@ -154,4 +163,8 @@ public class ChunkLoader extends BukkitRunnable {
void onChunkComplete(CompletableFuture<Chunk> asyncChunk, Chunk syncChunk);
}
public interface CompleteTask {
void onComplete(Island island);
}
}

View File

@ -1,6 +1,7 @@
package com.songoda.skyblock.command.commands.admin;
import com.songoda.core.compatibility.CompatibleSound;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.skyblock.biome.BiomeManager;
import com.songoda.skyblock.command.SubCommand;
import com.songoda.skyblock.config.FileManager;
@ -43,7 +44,11 @@ public class SetBiomeCommand extends SubCommand {
Config config = fileManager.getConfig(new File(skyblock.getDataFolder(), "language.yml"));
FileConfiguration configLoad = config.getFileConfiguration();
if(ServerVersion.isServerVersionAtLeast(ServerVersion.V1_16)){
messageManager.sendMessage(sender, "&bSkyBlock &8| &6Warning&8: &eThis feature is not supported on this Minecraft version yet. Use at your own risk.");
}
if (args.length == 2) {
String biomeName = args[1].toUpperCase().trim();
@ -76,7 +81,7 @@ public class SetBiomeCommand extends SubCommand {
} else {
if (islandManager.containsIsland(islandOwnerUUID)) {
Island island = islandManager.getIsland(Bukkit.getServer().getOfflinePlayer(islandOwnerUUID));
biomeManager.setBiome(island, biome.getBiome());
biomeManager.setBiome(island, biome.getBiome(), null);
island.setBiome(biome.getBiome());
} else {
islandManager.loadIsland(Bukkit.getOfflinePlayer(islandOwnerUUID));
@ -86,7 +91,7 @@ public class SetBiomeCommand extends SubCommand {
configLoad.getString("Command.Island.Admin.SetBiome.Island.Data.Message"));
soundManager.playSound(sender, CompatibleSound.BLOCK_ANVIL_LAND.getSound(), 1.0F, 1.0F);
} else {
biomeManager.setBiome(island, biome.getBiome());
biomeManager.setBiome(island, biome.getBiome(), null);
island.setBiome(biome.getBiome());
}
}

View File

@ -1,6 +1,8 @@
package com.songoda.skyblock.command.commands.island;
import com.songoda.core.compatibility.CompatibleSound;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.skyblock.biome.BiomeManager;
import com.songoda.skyblock.command.SubCommand;
import com.songoda.skyblock.config.FileManager.Config;
import com.songoda.skyblock.gui.bank.GuiBank;
@ -26,20 +28,31 @@ public class BiomeCommand extends SubCommand {
MessageManager messageManager = skyblock.getMessageManager();
IslandManager islandManager = skyblock.getIslandManager();
SoundManager soundManager = skyblock.getSoundManager();
BiomeManager biomeManager = skyblock.getBiomeManager();
Config config = skyblock.getFileManager().getConfig(new File(skyblock.getDataFolder(), "language.yml"));
FileConfiguration configLoad = config.getFileConfiguration();
Island island = islandManager.getIsland(player);
if(ServerVersion.isServerVersionAtLeast(ServerVersion.V1_16)){
messageManager.sendMessage(player, "&bSkyBlock &8| &cError&8: &eThis feature is not available on this Minecraft version yet.");
soundManager.playSound(player, CompatibleSound.BLOCK_ANVIL_LAND.getSound(), 1.0F, 1.0F);
return;
}
if (island == null) {
messageManager.sendMessage(player, configLoad.getString("Command.Island.Biome.Owner.Message"));
soundManager.playSound(player, CompatibleSound.BLOCK_ANVIL_LAND.getSound(), 1.0F, 1.0F);
} else if ((island.hasRole(IslandRole.Operator, player.getUniqueId())
&& skyblock.getPermissionManager().hasPermission(island,"Biome", IslandRole.Operator))
|| island.hasRole(IslandRole.Owner, player.getUniqueId())) {
skyblock.getGuiManager().showGUI(player, new GuiBiome(skyblock, player, island, IslandWorld.Normal, null, false)); // TODO Nether and End support
soundManager.playSound(player, CompatibleSound.BLOCK_CHEST_OPEN.getSound(), 1.0F, 1.0F);
if(biomeManager.isUpdating(island)){
messageManager.sendMessage(player, configLoad.getString("Command.Island.Biome.InProgress.Message"));
soundManager.playSound(player, CompatibleSound.ENTITY_VILLAGER_NO.getSound(), 1.0F, 1.0F);
} else {
skyblock.getGuiManager().showGUI(player, new GuiBiome(skyblock, player, island, IslandWorld.Normal, null, false)); // TODO Nether and End support
soundManager.playSound(player, CompatibleSound.BLOCK_CHEST_OPEN.getSound(), 1.0F, 1.0F);
}
} else {
messageManager.sendMessage(player, configLoad.getString("Command.Island.Biome.Permission.Message"));
soundManager.playSound(player, CompatibleSound.ENTITY_VILLAGER_NO.getSound(), 1.0F, 1.0F);

View File

@ -175,7 +175,10 @@ public class GuiBiome extends Gui {
}
cooldownManager.createPlayer(CooldownType.Biome, player);
Bukkit.getScheduler().runTask(plugin, () -> {
biomeManager.setBiome(island, icon.biome.getBiome());
biomeManager.setBiome(island, icon.biome.getBiome(), () -> {
messageManager.sendMessage(player, languageLoad.getString("Command.Island.Biome.Completed.Message"));
soundManager.playSound(player, CompatibleSound.ENTITY_VILLAGER_YES.getSound(), 1.0F, 1.0F);
});
island.save();
});
island.setBiome(icon.biome.getBiome());

View File

@ -4,6 +4,7 @@ import com.bekvon.bukkit.residence.Residence;
import com.bekvon.bukkit.residence.containers.Flags;
import com.bekvon.bukkit.residence.protection.ClaimedResidence;
import com.google.common.base.Preconditions;
import com.songoda.core.compatibility.CompatibleBiome;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.CompatibleSound;
import com.songoda.skyblock.SkyBlock;
@ -272,23 +273,23 @@ public class IslandManager {
player.setFallDistance(0.0F);
}, configLoad.getInt("Island.Creation.TeleportTimeout") * 20);
String biomeName = fileManager.getConfig(new File(skyblock.getDataFolder(), "config.yml")).getFileConfiguration().getString("Island.Biome.Default.Type").toUpperCase();
SBiome sBiome;
/*String biomeName = fileManager.getConfig(new File(skyblock.getDataFolder(), "config.yml")).getFileConfiguration().getString("Island.Biome.Default.Type").toUpperCase();
CompatibleBiome cBiome;
try {
sBiome = SBiome.valueOf(biomeName);
cBiome = CompatibleBiome.valueOf(biomeName);
} catch (Exception ex) {
sBiome = SBiome.PLAINS;
cBiome = CompatibleBiome.PLAINS;
}
Biome biome = sBiome.getBiome();
Biome biome = cBiome.getBiome();
Bukkit.getServer().getScheduler().runTaskLater(skyblock, () -> {
skyblock.getBiomeManager().setBiome(island, biome);
skyblock.getBiomeManager().setBiome(island, biome, null);
if (structure.getCommands() != null) {
for (String commandList : structure.getCommands()) {
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), commandList.replace("%player", player.getName()));
}
}
}, 20L);
}, 20L);*/
// Recalculate island level after 5 seconds
if (configLoad.getBoolean("Island.Levelling.ScanAutomatically"))
@ -662,7 +663,7 @@ public class IslandManager {
}
snapshots.put(world, positions.stream().map(Chunk::getChunkSnapshot).collect(Collectors.toList()));
ChunkDeleteSplitter.startDeletion(snapshots);
});
}, null);
} else {
ChunkLoader.startChunkLoading(island, IslandWorld.Normal, skyblock.isPaperAsync(), (asyncChunks, syncChunks) -> {
Bukkit.getScheduler().runTask(skyblock, () -> {
@ -671,7 +672,7 @@ public class IslandManager {
snapshots.put(world, list);
ChunkDeleteSplitter.startDeletion(snapshots);
});
});
}, null);
}
}

View File

@ -209,7 +209,7 @@ public final class IslandScan extends BukkitRunnable {
snapshots.put(skyblock.getWorldManager().getWorld(world), syncPositions.stream().map(org.bukkit.Chunk::getChunkSnapshot).collect(Collectors.toList()));
}
task.onComplete();
});
}, null);
}
private interface PopulateTask {

View File

@ -136,7 +136,7 @@ public class Biome {
SBiome selectedBiomeType = SBiome.getFromGuiIcon(is.getType(), is.getData().getData());
cooldownManager.createPlayer(CooldownType.Biome, player);
biomeManager.setBiome(island, selectedBiomeType.getBiome());
biomeManager.setBiome(island, selectedBiomeType.getBiome(), null);
island.setBiome(selectedBiomeType.getBiome());
island.save();

View File

@ -1,30 +1,42 @@
package com.songoda.skyblock.world.generator;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import com.songoda.core.compatibility.CompatibleBiome;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.skyblock.SkyBlock;
import com.songoda.skyblock.island.IslandWorld;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.configuration.Configuration;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator;
import com.songoda.skyblock.SkyBlock;
import com.songoda.skyblock.island.IslandWorld;
import javax.annotation.Nonnull;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
public class VoidGenerator extends ChunkGenerator {
@Override
public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, BiomeGrid biome) {
public @Nonnull ChunkData generateChunkData(@Nonnull World world, @Nonnull Random random, int chunkX, int chunkZ, @Nonnull BiomeGrid biomeGrid) {
final ChunkData chunkData = createChunkData(world);
final SkyBlock skyblock = SkyBlock.getInstance();
final Configuration configLoad = skyblock.getFileManager().getConfig(new File(skyblock.getDataFolder(), "config.yml")).getFileConfiguration();
final ConfigurationSection worldSection = configLoad.getConfigurationSection("Island.World");
/*if(ServerVersion.isServerVersionAtLeast(ServerVersion.V1_16)) { // TODO Should be 1.15 but it works fine there
setChunkBiome3D(CompatibleBiome.valueOf(configLoad
.getString("Island.Biome.Default.Type").toUpperCase()).getBiome(), biomeGrid);
} else {
setChunkBiome2D(CompatibleBiome.valueOf(configLoad
.getString("Island.Biome.Default.Type").toUpperCase()).getBiome(), biomeGrid);
}*/
for (IslandWorld worldList : IslandWorld.values()) {
if (world.getEnvironment() == World.Environment.NETHER
@ -71,4 +83,26 @@ public class VoidGenerator extends ChunkGenerator {
}
}
}
private void setChunkBiome3D(Biome biome, BiomeGrid grid) {
for(int x = 0; x < 16; x++){
for(int z = 0; z < 16; z++){
for(int y = 0; y<256; y++){
if(!grid.getBiome(x, y, z).equals(biome)){
grid.setBiome(x, y, z, biome);
}
}
}
}
}
private void setChunkBiome2D(Biome biome, BiomeGrid grid) {
for(int x = 0; x < 16; x++){
for(int z = 0; z < 16; z++){
if(!grid.getBiome(x, z).equals(biome)){
grid.setBiome(x, z, biome);
}
}
}
}
}

View File

@ -830,6 +830,10 @@ Command:
Message: '&f&oOpens the Island Biome menu.'
Permission:
Message: '&bSkyBlock &8| &cError&8: &eYou do not have the right to change your Island''s biome.'
InProgress:
Message: '&bSkyBlock &8| &cError&8: &eA biome update is still in progress for this Island.'
Completed:
Message: '&bSkyBlock &8| &aInfo&8: &eThe biome update is now complete'
Owner:
Message: '&bSkyBlock &8| &cError&8: &eYou are not an Island Owner.'
Visitors: