Do not keep references of World objects & handle cases when worlds are loaded & unloaded

This commit is contained in:
OmerBenGera 2024-06-01 16:57:18 +03:00
parent f22df7c611
commit 328212b0ca
16 changed files with 364 additions and 181 deletions

View File

@ -2,12 +2,28 @@ package com.bgsoftware.wildloaders.api.hooks;
import org.bukkit.Chunk;
import java.util.Collection;
public interface TickableProvider {
/**
* Simulate a tick on a list of provided chunks.
*
* @param chunks The chunks to tick.
* @deprecated See {@link #tick(Collection)}
*/
@Deprecated
default void tick(Chunk[] chunks) {
throw new UnsupportedOperationException("TickableProvider#tick is not supported anymore");
}
/**
* Simulate a tick on a list of provided chunks.
*
* @param chunks The chunks to tick.
*/
void tick(Chunk[] chunks);
default void tick(Collection<Chunk> chunks) {
tick(chunks.toArray(new Chunk[0]));
}
}

View File

@ -34,9 +34,17 @@ public interface ChunkLoader {
/**
* Get the chunks that this chunk-loader is loading.
*
* @deprecated See {@link #getLoadedChunksCollection()}
*/
@Deprecated
Chunk[] getLoadedChunks();
/**
* Get the chunks that this chunk-loader is loading.
*/
Collection<Chunk> getLoadedChunksCollection();
/**
* Get the NPC of this chunk loader.
*/

View File

@ -5,25 +5,26 @@ import com.songoda.epicspawners.EpicSpawners;
import org.bukkit.Chunk;
import org.bukkit.Location;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.HashSet;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.Set;
public final class TickableProvider_EpicSpawners6 implements TickableProvider {
private final Map<Location, TickDelay> spawnerDelays = new HashMap<>();
@Override
public void tick(Chunk[] chunks) {
public void tick(Collection<Chunk> chunks) {
if (EpicSpawners.getInstance().getSpawnerManager() == null)
return;
List<Long> chunkList = Stream.of(chunks).map(chunk -> pair(chunk.getX(), chunk.getZ())).collect(Collectors.toList());
Set<Long> chunkKeys = new HashSet<>();
chunks.forEach(chunk -> chunkKeys.add(pair(chunk.getX(), chunk.getZ())));
EpicSpawners.getInstance().getSpawnerManager().getSpawners().stream()
.filter(spawner -> chunkList.contains(pair(spawner.getX() >> 4, spawner.getZ() >> 4)))
.filter(spawner -> chunkKeys.contains(pair(spawner.getX() >> 4, spawner.getZ() >> 4)))
.forEach(spawner -> {
Location location = spawner.getLocation();
TickDelay tickDelay = spawnerDelays.get(location);

View File

@ -5,25 +5,26 @@ import com.songoda.epicspawners.EpicSpawners;
import org.bukkit.Chunk;
import org.bukkit.Location;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.HashSet;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.Set;
public final class TickableProvider_EpicSpawners7 implements TickableProvider {
private final Map<Location, TickDelay> spawnerDelays = new HashMap<>();
@Override
public void tick(Chunk[] chunks) {
public void tick(Collection<Chunk> chunks) {
if (EpicSpawners.getInstance().getSpawnerManager() == null)
return;
List<Long> chunkList = Stream.of(chunks).map(chunk -> pair(chunk.getX(), chunk.getZ())).collect(Collectors.toList());
Set<Long> chunkKeys = new HashSet<>();
chunks.forEach(chunk -> chunkKeys.add(pair(chunk.getX(), chunk.getZ())));
EpicSpawners.getInstance().getSpawnerManager().getSpawners().stream()
.filter(spawner -> chunkList.contains(pair(spawner.getX() >> 4, spawner.getZ() >> 4)))
.filter(spawner -> chunkKeys.contains(pair(spawner.getX() >> 4, spawner.getZ() >> 4)))
.forEach(spawner -> {
Location location = spawner.getLocation();
TickDelay tickDelay = spawnerDelays.get(location);

View File

@ -5,25 +5,26 @@ import com.craftaro.epicspawners.api.EpicSpawnersApi;
import org.bukkit.Chunk;
import org.bukkit.Location;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.HashSet;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.Set;
public final class TickableProvider_EpicSpawners8 implements TickableProvider {
private final Map<Location, TickDelay> spawnerDelays = new HashMap<>();
@Override
public void tick(Chunk[] chunks) {
public void tick(Collection<Chunk> chunks) {
if (EpicSpawnersApi.getSpawnerManager() == null)
return;
List<Long> chunkList = Stream.of(chunks).map(chunk -> pair(chunk.getX(), chunk.getZ())).collect(Collectors.toList());
Set<Long> chunkKeys = new HashSet<>();
chunks.forEach(chunk -> chunkKeys.add(pair(chunk.getX(), chunk.getZ())));
EpicSpawnersApi.getSpawnerManager().getSpawners().stream()
.filter(spawner -> chunkList.contains(pair(spawner.getX() >> 4, spawner.getZ() >> 4)))
.filter(spawner -> chunkKeys.contains(pair(spawner.getX() >> 4, spawner.getZ() >> 4)))
.forEach(spawner -> {
Location location = spawner.getLocation();
TickDelay tickDelay = spawnerDelays.get(location);

View File

@ -2,18 +2,16 @@ package com.bgsoftware.wildloaders.handlers;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.LoaderData;
import com.bgsoftware.wildloaders.utils.ChunkLoaderChunks;
import com.bgsoftware.wildloaders.utils.BlockPosition;
import com.bgsoftware.wildloaders.utils.ServerVersion;
import com.bgsoftware.wildloaders.utils.database.Database;
import com.bgsoftware.wildloaders.utils.locations.LocationUtils;
import com.bgsoftware.wildloaders.utils.threads.Executor;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import java.io.File;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@ -38,16 +36,16 @@ public final class DataHandler {
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 -> {
while (resultSet.next()) {
Location location = LocationUtils.getLocation(resultSet.getString("location"));
BlockPosition blockPosition = BlockPosition.deserialize(resultSet.getString("location"));
UUID uuid = UUID.fromString(resultSet.getString("uuid"));
plugin.getNPCs().registerUUID(location, uuid);
plugin.getNPCs().registerUUID(blockPosition, uuid);
}
});
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 -> {
while (resultSet.next()) {
Location location = LocationUtils.getLocation(resultSet.getString("location"));
BlockPosition blockPosition = BlockPosition.deserialize(resultSet.getString("location"));
UUID placer = UUID.fromString(resultSet.getString("placer"));
Optional<LoaderData> loaderData = plugin.getLoaders().getLoaderData(resultSet.getString("loader_data"));
long timeLeft = resultSet.getLong("timeLeft");
@ -55,21 +53,14 @@ public final class DataHandler {
if (!loaderData.isPresent())
continue;
Material blockType = location.getBlock().getType();
if (ServerVersion.isLegacy() && blockType == Material.CAULDRON) {
blockType = Material.CAULDRON_ITEM;
World world = blockPosition.getWorld();
if (world != null) {
Location location = blockPosition.getLocation();
plugin.getLoaders().addChunkLoaderWithoutDBSave(loaderData.get(), placer,
location, timeLeft, true);
} else {
plugin.getLoaders().addUnloadedChunkLoader(loaderData.get(), placer, blockPosition, timeLeft);
}
if (blockType != loaderData.get().getLoaderItem().getType()) {
WildLoadersPlugin.log("The chunk-loader at " + LocationUtils.getLocation(location) + " is invalid.");
continue;
}
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

@ -4,19 +4,25 @@ import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.loaders.LoaderData;
import com.bgsoftware.wildloaders.api.managers.LoadersManager;
import com.bgsoftware.wildloaders.loaders.UnloadedChunkLoader;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import com.bgsoftware.wildloaders.loaders.WLoaderData;
import com.bgsoftware.wildloaders.utils.BlockPosition;
import com.bgsoftware.wildloaders.utils.ChunkLoaderChunks;
import com.bgsoftware.wildloaders.utils.ServerVersion;
import com.bgsoftware.wildloaders.utils.chunks.ChunkPosition;
import com.bgsoftware.wildloaders.utils.database.Query;
import com.google.common.collect.Maps;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@ -24,8 +30,10 @@ import java.util.UUID;
public final class LoadersHandler implements LoadersManager {
private final Map<Location, ChunkLoader> chunkLoaders = Maps.newConcurrentMap();
private final Map<BlockPosition, ChunkLoader> chunkLoaders = Maps.newConcurrentMap();
private final Map<ChunkPosition, ChunkLoader> chunkLoadersByChunks = Maps.newConcurrentMap();
private final Map<String, List<ChunkLoader>> chunkLoadersByWorlds = Maps.newConcurrentMap();
private final Map<String, List<UnloadedChunkLoader>> unloadedChunkLoadersByWorlds = Maps.newConcurrentMap();
private final Map<String, LoaderData> loadersData = Maps.newConcurrentMap();
private final WildLoadersPlugin plugin;
@ -40,12 +48,12 @@ public final class LoadersHandler implements LoadersManager {
@Override
public Optional<ChunkLoader> getChunkLoader(Location location) {
return Optional.ofNullable(chunkLoaders.get(location));
return Optional.ofNullable(chunkLoaders.get(BlockPosition.of(location)));
}
@Override
public List<ChunkLoader> getChunkLoaders() {
return Collections.unmodifiableList(new ArrayList<>(chunkLoaders.values()));
return Collections.unmodifiableList(new LinkedList<>(chunkLoaders.values()));
}
@Override
@ -60,41 +68,117 @@ public final class LoadersHandler implements LoadersManager {
@Override
public ChunkLoader addChunkLoader(LoaderData loaderData, Player whoPlaced, Location location, long timeLeft) {
WChunkLoader chunkLoader = addChunkLoaderWithoutDBSave(loaderData, whoPlaced.getUniqueId(), location, timeLeft,
ChunkLoaderChunks.calculateChunks(loaderData, whoPlaced.getUniqueId(), location));
BlockPosition blockPosition = BlockPosition.of(location);
WChunkLoader chunkLoader = addChunkLoaderWithoutDBSave(loaderData, whoPlaced.getUniqueId(),
location, timeLeft, false);
Query.INSERT_CHUNK_LOADER.insertParameters()
.setLocation(location)
.setLocation(blockPosition)
.setObject(whoPlaced.getUniqueId().toString())
.setObject(loaderData.getName())
.setObject(timeLeft)
.queue(location);
.queue(blockPosition);
return chunkLoader;
}
public WChunkLoader addChunkLoaderWithoutDBSave(LoaderData loaderData, UUID placer, Location location, long timeLeft, List<Chunk> loadedChunks) {
WChunkLoader chunkLoader = new WChunkLoader(loaderData, placer, location, loadedChunks.toArray(new Chunk[0]), timeLeft);
chunkLoaders.put(location, chunkLoader);
for (Chunk loadedChunk : chunkLoader.getLoadedChunks()) {
public WChunkLoader addChunkLoaderWithoutDBSave(LoaderData loaderData, UUID placer, Location location,
long timeLeft, boolean validateBlock) {
BlockPosition blockPosition = BlockPosition.of(location);
if (validateBlock) {
Material blockType = location.getBlock().getType();
if (ServerVersion.isLegacy() && blockType == Material.CAULDRON) {
blockType = Material.CAULDRON_ITEM;
}
if (blockType != loaderData.getLoaderItem().getType()) {
WildLoadersPlugin.log("The chunk-loader at " + blockPosition.serialize() + " is invalid.");
return null;
}
}
List<Chunk> loadedChunks = ChunkLoaderChunks.calculateChunks(loaderData, placer, location);
loadedChunks.removeIf(chunk -> plugin.getLoaders().getChunkLoader(chunk).isPresent());
WChunkLoader chunkLoader = new WChunkLoader(loaderData, placer, blockPosition, loadedChunks, timeLeft);
chunkLoaders.put(blockPosition, chunkLoader);
chunkLoadersByWorlds.computeIfAbsent(blockPosition.getWorldName(), i -> new LinkedList<>()).add(chunkLoader);
for (Chunk loadedChunk : chunkLoader.getLoadedChunksCollection()) {
chunkLoadersByChunks.put(ChunkPosition.of(loadedChunk), chunkLoader);
}
plugin.getNPCs().createNPC(location);
plugin.getNPCs().createNPC(blockPosition);
return chunkLoader;
}
public void addUnloadedChunkLoader(LoaderData loaderData, UUID placer, BlockPosition blockPosition, long timeLeft) {
UnloadedChunkLoader unloadedChunkLoader = new UnloadedChunkLoader(loaderData, placer, blockPosition, timeLeft);
unloadedChunkLoadersByWorlds.computeIfAbsent(blockPosition.getWorldName(), i -> new LinkedList<>())
.add(unloadedChunkLoader);
}
public void loadUnloadedChunkLoaders(World world) {
List<UnloadedChunkLoader> unloadedChunkLoaders = this.unloadedChunkLoadersByWorlds.remove(world.getName());
if (unloadedChunkLoaders == null || unloadedChunkLoaders.isEmpty())
return;
unloadedChunkLoaders.forEach(unloadedChunkLoader -> {
Location location = unloadedChunkLoader.getBlockPosition().getLocation();
if (location.getWorld() != world)
throw new IllegalStateException();
addChunkLoaderWithoutDBSave(unloadedChunkLoader.getLoaderData(), unloadedChunkLoader.getPlacer(),
location, unloadedChunkLoader.getTimeLeft(), true);
});
}
public void unloadWorld(World world) {
List<ChunkLoader> worldChunkLoaders = this.chunkLoadersByWorlds.remove(world.getName());
if (worldChunkLoaders == null || worldChunkLoaders.isEmpty())
return;
List<UnloadedChunkLoader> unloadedChunkLoaders = new LinkedList<>();
worldChunkLoaders.forEach(chunkLoader -> {
plugin.getNMSAdapter().removeLoader(chunkLoader, false);
BlockPosition blockPosition = removeChunkLoaderWithoutDBSave(chunkLoader);
UnloadedChunkLoader unloadedChunkLoader = new UnloadedChunkLoader(chunkLoader.getLoaderData(),
chunkLoader.getWhoPlaced().getUniqueId(), blockPosition, chunkLoader.getTimeLeft());
unloadedChunkLoaders.add(unloadedChunkLoader);
Query.UPDATE_CHUNK_LOADER_TIME_LEFT.insertParameters()
.setObject(unloadedChunkLoader.getTimeLeft())
.setLocation(blockPosition)
.queue(blockPosition);
});
this.unloadedChunkLoadersByWorlds.put(world.getName(), unloadedChunkLoaders);
}
@Override
public void removeChunkLoader(ChunkLoader chunkLoader) {
Location location = chunkLoader.getLocation();
chunkLoaders.remove(location);
for (Chunk loadedChunk : chunkLoader.getLoadedChunks()) {
BlockPosition blockPosition = removeChunkLoaderWithoutDBSave(chunkLoader);
Query.DELETE_CHUNK_LOADER.insertParameters()
.setLocation(blockPosition)
.queue(blockPosition);
}
private BlockPosition removeChunkLoaderWithoutDBSave(ChunkLoader chunkLoader) {
BlockPosition blockPosition = BlockPosition.of(chunkLoader.getLocation());
chunkLoaders.remove(blockPosition);
for (Chunk loadedChunk : chunkLoader.getLoadedChunksCollection()) {
chunkLoadersByChunks.remove(ChunkPosition.of(loadedChunk));
}
chunkLoader.getNPC().ifPresent(npc -> plugin.getNPCs().killNPC(npc));
Query.DELETE_CHUNK_LOADER.insertParameters()
.setLocation(location)
.queue(location);
List<ChunkLoader> worldChunkLoaders = chunkLoadersByWorlds.get(blockPosition.getWorldName());
if (worldChunkLoaders != null)
worldChunkLoaders.remove(chunkLoader);
chunkLoader.getNPC().ifPresent(npc -> plugin.getNPCs().killNPC(npc));
return blockPosition;
}
@Override
@ -114,5 +198,6 @@ public final class LoadersHandler implements LoadersManager {
chunkLoaders.values().forEach(chunkLoader -> plugin.getNMSAdapter().removeLoader(chunkLoader, false));
chunkLoaders.clear();
chunkLoadersByChunks.clear();
chunkLoadersByWorlds.clear();
}
}

View File

@ -3,7 +3,7 @@ package com.bgsoftware.wildloaders.handlers;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.managers.NPCManager;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.NPCIdentifier;
import com.bgsoftware.wildloaders.utils.BlockPosition;
import com.bgsoftware.wildloaders.utils.database.Query;
import com.google.common.collect.Maps;
import org.bukkit.Location;
@ -21,8 +21,8 @@ public final class NPCHandler implements NPCManager {
private static int NPCS_COUNTER = 0;
private final WildLoadersPlugin plugin;
private final Map<NPCIdentifier, ChunkLoaderNPC> npcs = Maps.newConcurrentMap();
private final Map<NPCIdentifier, UUID> npcUUIDs = Maps.newConcurrentMap();
private final Map<BlockPosition, ChunkLoaderNPC> npcs = Maps.newConcurrentMap();
private final Map<BlockPosition, UUID> npcUUIDs = Maps.newConcurrentMap();
public NPCHandler(WildLoadersPlugin plugin) {
@ -31,13 +31,21 @@ public final class NPCHandler implements NPCManager {
@Override
public Optional<ChunkLoaderNPC> getNPC(Location location) {
return Optional.ofNullable(npcs.get(new NPCIdentifier(location)));
return getNPC(BlockPosition.of(location));
}
public Optional<ChunkLoaderNPC> getNPC(BlockPosition blockPosition) {
return Optional.ofNullable(npcs.get(blockPosition));
}
@Override
public ChunkLoaderNPC createNPC(Location location) {
return npcs.computeIfAbsent(new NPCIdentifier(location), i -> {
ChunkLoaderNPC npc = plugin.getNMSAdapter().createNPC(i.getSpawnLocation(), getUUID(i));
return createNPC(BlockPosition.of(location));
}
public ChunkLoaderNPC createNPC(BlockPosition blockPosition) {
return npcs.computeIfAbsent(blockPosition, i -> {
ChunkLoaderNPC npc = plugin.getNMSAdapter().createNPC(i.getLocation(), getUUID(i));
Entity npcEntity = npc.getPlayer();
npcEntity.setMetadata("NPC", new FixedMetadataValue(plugin, true));
return npc;
@ -52,13 +60,13 @@ public final class NPCHandler implements NPCManager {
@Override
public void killNPC(ChunkLoaderNPC npc) {
NPCIdentifier identifier = new NPCIdentifier(npc.getLocation());
npcs.remove(identifier);
BlockPosition blockPosition = BlockPosition.of(npc.getLocation());
npcUUIDs.remove(identifier);
npcs.remove(blockPosition);
npcUUIDs.remove(blockPosition);
Query.DELETE_NPC_IDENTIFIER.insertParameters()
.setLocation(identifier.getSpawnLocation())
.setLocation(blockPosition)
.queue(npc.getUniqueId());
Entity npcEntity = npc.getPlayer();
@ -76,28 +84,27 @@ public final class NPCHandler implements NPCManager {
npcs.clear();
}
public Map<NPCIdentifier, ChunkLoaderNPC> getNPCs() {
public Map<BlockPosition, ChunkLoaderNPC> getNPCs() {
return Collections.unmodifiableMap(npcs);
}
public void registerUUID(Location location, UUID uuid) {
npcUUIDs.put(new NPCIdentifier(location), uuid);
public void registerUUID(BlockPosition blockPosition, UUID uuid) {
npcUUIDs.put(blockPosition, uuid);
}
private UUID getUUID(NPCIdentifier identifier) {
if (npcUUIDs.containsKey(identifier))
return npcUUIDs.get(identifier);
UUID uuid;
private UUID getUUID(BlockPosition blockPosition) {
UUID uuid = npcUUIDs.get(blockPosition);
if (uuid != null)
return uuid;
do {
uuid = UUID.randomUUID();
} while (npcUUIDs.containsValue(uuid));
npcUUIDs.put(identifier, uuid);
npcUUIDs.put(blockPosition, uuid);
Query.INSERT_NPC_IDENTIFIER.insertParameters()
.setLocation(identifier.getSpawnLocation())
.setLocation(blockPosition)
.setObject(uuid.toString())
.queue(uuid);

View File

@ -93,7 +93,7 @@ public final class ProvidersHandler implements ProvidersManager {
return false;
}
public void tick(Chunk[] chunks) {
public void tick(List<Chunk> chunks) {
tickableProviders.forEach(tickableProvider -> tickableProvider.tick(chunks));
}

View File

@ -5,22 +5,35 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
@SuppressWarnings("unused")
public final class ChunksListener implements Listener {
private final WildLoadersPlugin plugin;
public ChunksListener(WildLoadersPlugin plugin){
public ChunksListener(WildLoadersPlugin plugin) {
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onChunkUnload(ChunkUnloadEvent e){
public void onChunkUnload(ChunkUnloadEvent e) {
try {
if (plugin.getLoaders().getChunkLoader(e.getChunk()).isPresent())
e.setCancelled(true);
}catch (Throwable ignored){}
} catch (Throwable ignored) {
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onWorldLoad(WorldLoadEvent e) {
plugin.getLoaders().loadUnloadedChunkLoaders(e.getWorld());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onWorldUnload(WorldUnloadEvent e) {
plugin.getLoaders().unloadWorld(e.getWorld());
}
}

View File

@ -0,0 +1,38 @@
package com.bgsoftware.wildloaders.loaders;
import com.bgsoftware.wildloaders.api.loaders.LoaderData;
import com.bgsoftware.wildloaders.utils.BlockPosition;
import java.util.UUID;
public class UnloadedChunkLoader {
private final LoaderData loaderData;
private final UUID placer;
private final BlockPosition blockPosition;
private final long timeLeft;
public UnloadedChunkLoader(LoaderData loaderData, UUID placer, BlockPosition blockPosition, long timeLeft) {
this.loaderData = loaderData;
this.placer = placer;
this.blockPosition = blockPosition;
this.timeLeft = timeLeft;
}
public LoaderData getLoaderData() {
return loaderData;
}
public UUID getPlacer() {
return placer;
}
public BlockPosition getBlockPosition() {
return blockPosition;
}
public long getTimeLeft() {
return timeLeft;
}
}

View File

@ -5,7 +5,7 @@ import com.bgsoftware.wildloaders.api.holograms.Hologram;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.loaders.LoaderData;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.utils.ChunkLoaderChunks;
import com.bgsoftware.wildloaders.utils.BlockPosition;
import com.bgsoftware.wildloaders.utils.database.Query;
import com.bgsoftware.wildloaders.utils.threads.Executor;
import org.bukkit.Bukkit;
@ -16,6 +16,7 @@ import org.bukkit.OfflinePlayer;
import org.bukkit.inventory.ItemStack;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@ -25,18 +26,18 @@ public final class WChunkLoader implements ChunkLoader {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
private final UUID whoPlaced;
private final Location location;
private final Chunk[] loadedChunks;
private final BlockPosition blockPosition;
private final List<Chunk> loadedChunks;
private final String loaderName;
private final ITileEntityChunkLoader tileEntityChunkLoader;
private boolean active = true;
private long timeLeft;
public WChunkLoader(LoaderData loaderData, UUID whoPlaced, Location location, Chunk[] loadedChunks, long timeLeft) {
public WChunkLoader(LoaderData loaderData, UUID whoPlaced, BlockPosition blockPosition, List<Chunk> loadedChunks, long timeLeft) {
this.loaderName = loaderData.getName();
this.whoPlaced = whoPlaced;
this.location = location.clone();
this.blockPosition = blockPosition;
this.loadedChunks = loadedChunks;
this.timeLeft = timeLeft;
this.tileEntityChunkLoader = plugin.getNMSAdapter().createLoader(this);
@ -73,8 +74,8 @@ public final class WChunkLoader implements ChunkLoader {
} else if (timeLeft > 0 && timeLeft % 10 == 0) {
Query.UPDATE_CHUNK_LOADER_TIME_LEFT.insertParameters()
.setObject(timeLeft)
.setLocation(location)
.queue(location);
.setLocation(this.blockPosition)
.queue(this.blockPosition);
}
}
}
@ -85,17 +86,23 @@ public final class WChunkLoader implements ChunkLoader {
@Override
public Location getLocation() {
return location.clone();
return this.blockPosition.getLocation();
}
@Override
@Deprecated
public Chunk[] getLoadedChunks() {
return loadedChunks;
return loadedChunks.toArray(new Chunk[0]);
}
@Override
public Collection<Chunk> getLoadedChunksCollection() {
return Collections.unmodifiableCollection(loadedChunks);
}
@Override
public Optional<ChunkLoaderNPC> getNPC() {
return plugin.getNPCs().getNPC(location);
return plugin.getNPCs().getNPC(this.blockPosition);
}
@Override

View File

@ -1,41 +0,0 @@
package com.bgsoftware.wildloaders.npc;
import org.bukkit.Location;
import java.util.Objects;
public final class NPCIdentifier {
private final Object identifier;
public NPCIdentifier(Location location){
this.identifier = getBlockLocation(location);
}
public Location getSpawnLocation(){
return (Location) identifier;
}
@Override
public String toString() {
return identifier.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NPCIdentifier that = (NPCIdentifier) o;
return Objects.equals(identifier, that.identifier);
}
@Override
public int hashCode() {
return Objects.hash(identifier);
}
private static Location getBlockLocation(Location location){
return new Location(location.getWorld(), location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
}

View File

@ -0,0 +1,92 @@
package com.bgsoftware.wildloaders.utils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import java.lang.ref.WeakReference;
import java.util.Objects;
public class BlockPosition {
private final String worldName;
private final int x;
private final int y;
private final int z;
private WeakReference<World> cachedWorld = new WeakReference<>(null);
public static BlockPosition of(Location location) {
World world = location.getWorld();
return new BlockPosition(world == null ? "null" : world.getName(),
location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
public static BlockPosition deserialize(String serialized) {
String[] locationSections = serialized.split(",");
if (locationSections.length != 4)
throw new IllegalArgumentException("Cannot parse location " + serialized);
String worldName = locationSections[0];
int x = (int) Double.parseDouble(locationSections[1]);
int y = (int) Double.parseDouble(locationSections[2]);
int z = (int) Double.parseDouble(locationSections[3]);
return new BlockPosition(worldName, x, y, z);
}
public BlockPosition(String worldName, int x, int y, int z) {
this.worldName = worldName;
this.x = x;
this.y = y;
this.z = z;
}
public String getWorldName() {
return worldName;
}
public World getWorld() {
World cachedWorld = this.cachedWorld.get();
if (cachedWorld == null) {
cachedWorld = Bukkit.getWorld(this.worldName);
this.cachedWorld = new WeakReference<>(cachedWorld);
}
return cachedWorld;
}
public Location getLocation() {
return new Location(getWorld(), this.x, this.y, this.z);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
public String serialize() {
return this.worldName + "," + this.x + "," + this.y + "," + this.z;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BlockPosition that = (BlockPosition) o;
return x == that.x && y == that.y && z == that.z && Objects.equals(worldName, that.worldName);
}
@Override
public int hashCode() {
return Objects.hash(worldName, x, y, z);
}
}

View File

@ -1,5 +1,6 @@
package com.bgsoftware.wildloaders.utils.database;
import com.bgsoftware.wildloaders.utils.BlockPosition;
import org.bukkit.Location;
import java.sql.PreparedStatement;
@ -12,7 +13,7 @@ public final class QueryParameters {
private final Query query;
private final List<Object> parameters;
public QueryParameters(Query query){
public QueryParameters(Query query) {
this.query = query;
this.parameters = new ArrayList<>(query.getParametersCount());
}
@ -22,20 +23,24 @@ public final class QueryParameters {
}
public void executeQuery(PreparedStatement preparedStatement) throws SQLException {
for(int i = 0; i < parameters.size(); i++)
for (int i = 0; i < parameters.size(); i++)
preparedStatement.setObject(i + 1, parameters.get(i));
}
public void queue(Object caller){
public void queue(Object caller) {
DatabaseQueue.queue(caller, this);
}
public QueryParameters setLocation(Location loc){
public QueryParameters setLocation(Location loc) {
return setObject(loc.getWorld().getName() + "," + loc.getBlockX() + "," + loc.getBlockY() + "," + loc.getBlockZ());
}
public QueryParameters setObject(Object object){
if(object instanceof Location)
public QueryParameters setLocation(BlockPosition blockPos) {
return setObject(blockPos.getWorldName() + "," + blockPos.getX() + "," + blockPos.getY() + "," + blockPos.getZ());
}
public QueryParameters setObject(Object object) {
if (object instanceof Location)
return setLocation((Location) object);
parameters.add(object);

View File

@ -1,41 +0,0 @@
package com.bgsoftware.wildloaders.utils.locations;
import org.bukkit.Bukkit;
import org.bukkit.Location;
public final class LocationUtils {
private LocationUtils(){}
public static String getLocation(Location location){
try {
return location.getWorld().getName() + "," + location.getBlockX() + "," + location.getBlockY() + "," + location.getBlockZ();
}catch (Exception ex){
System.out.println(location);
throw ex;
}
}
public static Location getLocation(String location){
String[] locationSections = location.split(",");
if(locationSections.length != 4)
throw new IllegalArgumentException("Cannot parse location " + location);
String worldName = locationSections[0];
double x = parseDouble(locationSections[1]);
double y = parseDouble(locationSections[2]);
double z = parseDouble(locationSections[3]);
return new Location(Bukkit.getWorld(worldName), x, y, z);
}
private static double parseDouble(String str){
try{
return Double.parseDouble(str);
}catch (Exception ex){
throw new IllegalArgumentException("Cannot parse double " + str);
}
}
}