Fixed chunk loaders can be placed next to each other and overlap chunks (#64)

This commit is contained in:
OmerBenGera 2023-01-13 16:48:36 +02:00
parent 6e0d1fa310
commit 22d8f0d1fb
5 changed files with 111 additions and 76 deletions

View File

@ -2,15 +2,18 @@ package com.bgsoftware.wildloaders.handlers;
import com.bgsoftware.wildloaders.WildLoadersPlugin; import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.LoaderData; import com.bgsoftware.wildloaders.api.loaders.LoaderData;
import com.bgsoftware.wildloaders.utils.ChunkLoaderChunks;
import com.bgsoftware.wildloaders.utils.ServerVersion; import com.bgsoftware.wildloaders.utils.ServerVersion;
import com.bgsoftware.wildloaders.utils.database.Database; import com.bgsoftware.wildloaders.utils.database.Database;
import com.bgsoftware.wildloaders.utils.locations.LocationUtils; import com.bgsoftware.wildloaders.utils.locations.LocationUtils;
import com.bgsoftware.wildloaders.utils.threads.Executor; import com.bgsoftware.wildloaders.utils.threads.Executor;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import java.io.File; import java.io.File;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
@ -18,20 +21,20 @@ public final class DataHandler {
private final WildLoadersPlugin plugin; private final WildLoadersPlugin plugin;
public DataHandler(WildLoadersPlugin plugin){ public DataHandler(WildLoadersPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
Executor.sync(() -> { Executor.sync(() -> {
try { try {
Database.start(new File(plugin.getDataFolder(), "database.db")); Database.start(new File(plugin.getDataFolder(), "database.db"));
loadDatabase(); loadDatabase();
}catch (Exception ex){ } catch (Exception ex) {
ex.printStackTrace(); ex.printStackTrace();
Bukkit.getPluginManager().disablePlugin(plugin); Bukkit.getPluginManager().disablePlugin(plugin);
} }
}, 2L); }, 2L);
} }
public void loadDatabase(){ public void loadDatabase() {
Database.executeUpdate("CREATE TABLE IF NOT EXISTS npc_identifiers (location TEXT NOT NULL PRIMARY KEY, uuid TEXT NOT NULL);"); Database.executeUpdate("CREATE TABLE IF NOT EXISTS npc_identifiers (location TEXT NOT NULL PRIMARY KEY, uuid TEXT NOT NULL);");
Database.executeQuery("SELECT * FROM npc_identifiers;", resultSet -> { Database.executeQuery("SELECT * FROM npc_identifiers;", resultSet -> {
while (resultSet.next()) { while (resultSet.next()) {
@ -43,27 +46,30 @@ public final class DataHandler {
Database.executeUpdate("CREATE TABLE IF NOT EXISTS chunk_loaders (location TEXT NOT NULL PRIMARY KEY, placer TEXT NOT NULL, loader_data TEXT NOT NULL, timeLeft BIGINT NOT NULL);"); Database.executeUpdate("CREATE TABLE IF NOT EXISTS chunk_loaders (location TEXT NOT NULL PRIMARY KEY, placer TEXT NOT NULL, loader_data TEXT NOT NULL, timeLeft BIGINT NOT NULL);");
Database.executeQuery("SELECT * FROM chunk_loaders;", resultSet -> { Database.executeQuery("SELECT * FROM chunk_loaders;", resultSet -> {
while(resultSet.next()){ while (resultSet.next()) {
Location location = LocationUtils.getLocation(resultSet.getString("location")); Location location = LocationUtils.getLocation(resultSet.getString("location"));
UUID placer = UUID.fromString(resultSet.getString("placer")); UUID placer = UUID.fromString(resultSet.getString("placer"));
Optional<LoaderData> loaderData = plugin.getLoaders().getLoaderData(resultSet.getString("loader_data")); Optional<LoaderData> loaderData = plugin.getLoaders().getLoaderData(resultSet.getString("loader_data"));
long timeLeft = resultSet.getLong("timeLeft"); long timeLeft = resultSet.getLong("timeLeft");
if(!loaderData.isPresent()) if (!loaderData.isPresent())
continue; continue;
Material blockType = location.getBlock().getType(); Material blockType = location.getBlock().getType();
if(ServerVersion.isLegacy() && blockType == Material.CAULDRON){ if (ServerVersion.isLegacy() && blockType == Material.CAULDRON) {
blockType = Material.CAULDRON_ITEM; blockType = Material.CAULDRON_ITEM;
} }
if(blockType != loaderData.get().getLoaderItem().getType()){ if (blockType != loaderData.get().getLoaderItem().getType()) {
WildLoadersPlugin.log("The chunk-loader at " + LocationUtils.getLocation(location) + " is invalid."); WildLoadersPlugin.log("The chunk-loader at " + LocationUtils.getLocation(location) + " is invalid.");
continue; continue;
} }
plugin.getLoaders().addChunkLoader(loaderData.get(), placer, location, timeLeft); List<Chunk> chunksToLoad = ChunkLoaderChunks.calculateChunks(loaderData.get(), placer, location);
chunksToLoad.removeIf(chunk -> plugin.getLoaders().getChunkLoader(chunk).isPresent());
plugin.getLoaders().addChunkLoaderWithoutDBSave(loaderData.get(), placer, location, timeLeft, chunksToLoad);
} }
}); });
} }

View File

@ -1,11 +1,12 @@
package com.bgsoftware.wildloaders.handlers; package com.bgsoftware.wildloaders.handlers;
import com.bgsoftware.wildloaders.WildLoadersPlugin; import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.managers.LoadersManager;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.loaders.LoaderData; import com.bgsoftware.wildloaders.api.loaders.LoaderData;
import com.bgsoftware.wildloaders.api.managers.LoadersManager;
import com.bgsoftware.wildloaders.loaders.WChunkLoader; import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import com.bgsoftware.wildloaders.loaders.WLoaderData; import com.bgsoftware.wildloaders.loaders.WLoaderData;
import com.bgsoftware.wildloaders.utils.ChunkLoaderChunks;
import com.bgsoftware.wildloaders.utils.chunks.ChunkPosition; import com.bgsoftware.wildloaders.utils.chunks.ChunkPosition;
import com.bgsoftware.wildloaders.utils.database.Query; import com.bgsoftware.wildloaders.utils.database.Query;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
@ -28,7 +29,7 @@ public final class LoadersHandler implements LoadersManager {
private final Map<String, LoaderData> loadersData = Maps.newConcurrentMap(); private final Map<String, LoaderData> loadersData = Maps.newConcurrentMap();
private final WildLoadersPlugin plugin; private final WildLoadersPlugin plugin;
public LoadersHandler(WildLoadersPlugin plugin){ public LoadersHandler(WildLoadersPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@ -59,7 +60,8 @@ public final class LoadersHandler implements LoadersManager {
@Override @Override
public ChunkLoader addChunkLoader(LoaderData loaderData, Player whoPlaced, Location location, long timeLeft) { public ChunkLoader addChunkLoader(LoaderData loaderData, Player whoPlaced, Location location, long timeLeft) {
WChunkLoader chunkLoader = addChunkLoader(loaderData, whoPlaced.getUniqueId(), location, timeLeft); WChunkLoader chunkLoader = addChunkLoaderWithoutDBSave(loaderData, whoPlaced.getUniqueId(), location, timeLeft,
ChunkLoaderChunks.calculateChunks(loaderData, whoPlaced.getUniqueId(), location));
Query.INSERT_CHUNK_LOADER.insertParameters() Query.INSERT_CHUNK_LOADER.insertParameters()
.setLocation(location) .setLocation(location)
@ -71,8 +73,8 @@ public final class LoadersHandler implements LoadersManager {
return chunkLoader; return chunkLoader;
} }
public WChunkLoader addChunkLoader(LoaderData loaderData, UUID placer, Location location, long timeLeft){ public WChunkLoader addChunkLoaderWithoutDBSave(LoaderData loaderData, UUID placer, Location location, long timeLeft, List<Chunk> loadedChunks) {
WChunkLoader chunkLoader = new WChunkLoader(loaderData, placer, location, timeLeft); WChunkLoader chunkLoader = new WChunkLoader(loaderData, placer, location, loadedChunks.toArray(new Chunk[0]), timeLeft);
chunkLoaders.put(location, chunkLoader); chunkLoaders.put(location, chunkLoader);
for (Chunk loadedChunk : chunkLoader.getLoadedChunks()) { for (Chunk loadedChunk : chunkLoader.getLoadedChunks()) {
chunkLoadersByChunks.put(ChunkPosition.of(loadedChunk), chunkLoader); chunkLoadersByChunks.put(ChunkPosition.of(loadedChunk), chunkLoader);

View File

@ -4,8 +4,10 @@ import com.bgsoftware.wildloaders.Locale;
import com.bgsoftware.wildloaders.WildLoadersPlugin; import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.loaders.LoaderData; import com.bgsoftware.wildloaders.api.loaders.LoaderData;
import com.bgsoftware.wildloaders.utils.ChunkLoaderChunks;
import com.bgsoftware.wildloaders.utils.chunks.ChunkPosition; import com.bgsoftware.wildloaders.utils.chunks.ChunkPosition;
import com.bgsoftware.wildloaders.utils.legacy.Materials; import com.bgsoftware.wildloaders.utils.legacy.Materials;
import org.bukkit.Chunk;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.block.Block; import org.bukkit.block.Block;
@ -27,31 +29,33 @@ public final class BlocksListener implements Listener {
private final WildLoadersPlugin plugin; private final WildLoadersPlugin plugin;
public BlocksListener(WildLoadersPlugin plugin){ public BlocksListener(WildLoadersPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onLoaderPlace(BlockPlaceEvent e){ public void onLoaderPlace(BlockPlaceEvent e) {
String loaderName = plugin.getNMSAdapter().getTag(e.getItemInHand(), "loader-name", ""); String loaderName = plugin.getNMSAdapter().getTag(e.getItemInHand(), "loader-name", "");
Optional<LoaderData> optionalLoaderData = plugin.getLoaders().getLoaderData(loaderName); Optional<LoaderData> optionalLoaderData = plugin.getLoaders().getLoaderData(loaderName);
if(!optionalLoaderData.isPresent()) if (!optionalLoaderData.isPresent())
return; return;
if(!e.getPlayer().hasPermission("wildloaders.use")) { if (!e.getPlayer().hasPermission("wildloaders.use")) {
e.setCancelled(true); e.setCancelled(true);
Locale.NO_PLACE_PERMISSION.send(e.getPlayer()); Locale.NO_PLACE_PERMISSION.send(e.getPlayer());
return; return;
} }
if(plugin.getLoaders().getChunkLoader(e.getBlock().getLocation().getChunk()).isPresent()){ LoaderData loaderData = optionalLoaderData.get();
for (Chunk chunk : ChunkLoaderChunks.calculateChunks(loaderData, e.getPlayer().getUniqueId(), e.getBlock().getLocation())) {
if (plugin.getLoaders().getChunkLoader(chunk).isPresent()) {
e.setCancelled(true); e.setCancelled(true);
Locale.ALREADY_LOADED.send(e.getPlayer()); Locale.ALREADY_LOADED.send(e.getPlayer());
return; return;
} }
}
LoaderData loaderData = optionalLoaderData.get();
long timeLeft = plugin.getNMSAdapter().getTag(e.getItemInHand(), "loader-time", loaderData.getTimeLeft()); long timeLeft = plugin.getNMSAdapter().getTag(e.getItemInHand(), "loader-time", loaderData.getTimeLeft());
@ -61,33 +65,33 @@ public final class BlocksListener implements Listener {
} }
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onLoaderBreak(BlockBreakEvent e){ public void onLoaderBreak(BlockBreakEvent e) {
if(handleLoaderBreak(e.getBlock(), e.getPlayer().getGameMode() != GameMode.CREATIVE)) if (handleLoaderBreak(e.getBlock(), e.getPlayer().getGameMode() != GameMode.CREATIVE))
Locale.BROKE_LOADER.send(e.getPlayer()); Locale.BROKE_LOADER.send(e.getPlayer());
} }
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onLoaderExplode(EntityExplodeEvent e){ public void onLoaderExplode(EntityExplodeEvent e) {
e.blockList().removeIf(block -> handleLoaderBreak(block, true)); e.blockList().removeIf(block -> handleLoaderBreak(block, true));
} }
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onSpawnerPlace(BlockPlaceEvent e){ public void onSpawnerPlace(BlockPlaceEvent e) {
if(e.getBlock().getType() != Materials.SPAWNER.toBukkitType()) if (e.getBlock().getType() != Materials.SPAWNER.toBukkitType())
return; return;
if(!plugin.getLoaders().getChunkLoader(e.getBlock().getChunk()).isPresent()) if (!plugin.getLoaders().getChunkLoader(e.getBlock().getChunk()).isPresent())
return; return;
plugin.getNMSAdapter().updateSpawner(e.getBlock().getLocation(), false); plugin.getNMSAdapter().updateSpawner(e.getBlock().getLocation(), false);
} }
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onLoaderInteract(PlayerInteractEvent e){ public void onLoaderInteract(PlayerInteractEvent e) {
if(e.getAction() != Action.RIGHT_CLICK_BLOCK) if (e.getAction() != Action.RIGHT_CLICK_BLOCK)
return; return;
if(plugin.getLoaders().getChunkLoader(e.getClickedBlock().getLocation()).isPresent()) if (plugin.getLoaders().getChunkLoader(e.getClickedBlock().getLocation()).isPresent())
e.setCancelled(true); e.setCancelled(true);
} }
@ -95,37 +99,39 @@ public final class BlocksListener implements Listener {
public void onLoaderPistonRetract(BlockPistonRetractEvent e) { public void onLoaderPistonRetract(BlockPistonRetractEvent e) {
try { try {
for (Block block : e.getBlocks()) { for (Block block : e.getBlocks()) {
if(plugin.getLoaders().getChunkLoader(block.getLocation()).isPresent()) { if (plugin.getLoaders().getChunkLoader(block.getLocation()).isPresent()) {
e.setCancelled(true); e.setCancelled(true);
return; return;
} }
} }
} catch (Throwable ignored) {} } catch (Throwable ignored) {
}
} }
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onLoaderPistonExtend(BlockPistonExtendEvent e) { public void onLoaderPistonExtend(BlockPistonExtendEvent e) {
try { try {
for (Block block : e.getBlocks()) { for (Block block : e.getBlocks()) {
if(plugin.getLoaders().getChunkLoader(block.getLocation()).isPresent()) { if (plugin.getLoaders().getChunkLoader(block.getLocation()).isPresent()) {
e.setCancelled(true); e.setCancelled(true);
return; return;
} }
} }
} catch (Throwable ignored) {} } catch (Throwable ignored) {
}
} }
private boolean handleLoaderBreak(Block block, boolean dropItem){ private boolean handleLoaderBreak(Block block, boolean dropItem) {
Location blockLoc = block.getLocation(); Location blockLoc = block.getLocation();
Optional<ChunkLoader> optionalChunkLoader = plugin.getLoaders().getChunkLoader(blockLoc); Optional<ChunkLoader> optionalChunkLoader = plugin.getLoaders().getChunkLoader(blockLoc);
if(!optionalChunkLoader.isPresent()) if (!optionalChunkLoader.isPresent())
return false; return false;
ChunkLoader chunkLoader = optionalChunkLoader.get(); ChunkLoader chunkLoader = optionalChunkLoader.get();
chunkLoader.remove(); chunkLoader.remove();
if(dropItem) if (dropItem)
blockLoc.getWorld().dropItemNaturally(blockLoc, chunkLoader.getLoaderItem()); blockLoc.getWorld().dropItemNaturally(blockLoc, chunkLoader.getLoaderItem());
return true; return true;

View File

@ -5,6 +5,7 @@ import com.bgsoftware.wildloaders.api.holograms.Hologram;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.loaders.LoaderData; import com.bgsoftware.wildloaders.api.loaders.LoaderData;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC; import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.utils.ChunkLoaderChunks;
import com.bgsoftware.wildloaders.utils.database.Query; import com.bgsoftware.wildloaders.utils.database.Query;
import com.bgsoftware.wildloaders.utils.threads.Executor; import com.bgsoftware.wildloaders.utils.threads.Executor;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -14,7 +15,6 @@ import org.bukkit.Material;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -33,11 +33,11 @@ public final class WChunkLoader implements ChunkLoader {
private boolean active = true; private boolean active = true;
private long timeLeft; private long timeLeft;
public WChunkLoader(LoaderData loaderData, UUID whoPlaced, Location location, long timeLeft) { public WChunkLoader(LoaderData loaderData, UUID whoPlaced, Location location, Chunk[] loadedChunks, long timeLeft) {
this.loaderName = loaderData.getName(); this.loaderName = loaderData.getName();
this.whoPlaced = whoPlaced; this.whoPlaced = whoPlaced;
this.location = location.clone(); this.location = location.clone();
this.loadedChunks = calculateChunks(loaderData, whoPlaced, this.location); this.loadedChunks = loadedChunks;
this.timeLeft = timeLeft; this.timeLeft = timeLeft;
this.tileEntityChunkLoader = plugin.getNMSAdapter().createLoader(this); this.tileEntityChunkLoader = plugin.getNMSAdapter().createLoader(this);
} }
@ -125,39 +125,5 @@ public final class WChunkLoader implements ChunkLoader {
return isInfinite() ? plugin.getSettings().infiniteHologramLines : plugin.getSettings().hologramLines; return isInfinite() ? plugin.getSettings().infiniteHologramLines : plugin.getSettings().hologramLines;
} }
private static Chunk[] calculateChunks(LoaderData loaderData, UUID whoPlaced, Location original) {
List<Chunk> chunkList = new ArrayList<>();
if (loaderData.isChunksSpread()) {
calculateClaimChunks(original.getChunk(), whoPlaced, chunkList);
}
if (chunkList.isEmpty()) {
int chunkX = original.getBlockX() >> 4, chunkZ = original.getBlockZ() >> 4;
for (int x = -loaderData.getChunksRadius(); x <= loaderData.getChunksRadius(); x++)
for (int z = -loaderData.getChunksRadius(); z <= loaderData.getChunksRadius(); z++)
chunkList.add(original.getWorld().getChunkAt(chunkX + x, chunkZ + z));
}
return chunkList.toArray(new Chunk[0]);
}
private static void calculateClaimChunks(Chunk originalChunk, UUID whoPlaced, List<Chunk> chunkList) {
if (!plugin.getProviders().hasChunkAccess(whoPlaced, originalChunk))
return;
chunkList.add(originalChunk);
int chunkX = originalChunk.getX(), chunkZ = originalChunk.getZ();
for (int x = -1; x <= 1; x++) {
for (int z = -1; z <= 1; z++) {
if (x != 0 || z != 0) // We don't want to add the originalChunk again.
calculateClaimChunks(originalChunk.getWorld().getChunkAt(chunkX + x, chunkZ + z), whoPlaced, chunkList);
}
}
}
} }

View File

@ -0,0 +1,55 @@
package com.bgsoftware.wildloaders.utils;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.LoaderData;
import org.bukkit.Chunk;
import org.bukkit.Location;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
public class ChunkLoaderChunks {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
private ChunkLoaderChunks() {
}
public static List<Chunk> calculateChunks(LoaderData loaderData, UUID whoPlaced, Location original) {
List<Chunk> chunkList = new LinkedList<>();
if (loaderData.isChunksSpread()) {
calculateClaimChunksRecursive(original.getChunk(), whoPlaced, chunkList);
}
if (chunkList.isEmpty()) {
int chunkX = original.getBlockX() >> 4, chunkZ = original.getBlockZ() >> 4;
for (int x = -loaderData.getChunksRadius(); x <= loaderData.getChunksRadius(); x++)
for (int z = -loaderData.getChunksRadius(); z <= loaderData.getChunksRadius(); z++)
chunkList.add(original.getWorld().getChunkAt(chunkX + x, chunkZ + z));
}
return chunkList;
}
private static void calculateClaimChunksRecursive(Chunk originalChunk, UUID whoPlaced, List<Chunk> chunkList) {
if (!plugin.getProviders().hasChunkAccess(whoPlaced, originalChunk))
return;
chunkList.add(originalChunk);
int chunkX = originalChunk.getX(), chunkZ = originalChunk.getZ();
for (int x = -1; x <= 1; x++) {
for (int z = -1; z <= 1; z++) {
if (x != 0 || z != 0) // We don't want to add the originalChunk again.
calculateClaimChunksRecursive(originalChunk.getWorld().getChunkAt(chunkX + x, chunkZ + z), whoPlaced, chunkList);
}
}
}
}