mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2025-02-19 13:51:24 +01:00
Added PotionEffectTypeAdapter for GSON
This commit is contained in:
parent
cf792779f9
commit
c10f413173
@ -1,392 +0,0 @@
|
||||
package us.tastybento.bskyblock.database.managers.island;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
|
||||
import us.tastybento.bskyblock.BSkyBlock;
|
||||
import us.tastybento.bskyblock.database.objects.Island;
|
||||
import us.tastybento.bskyblock.util.Util;
|
||||
|
||||
public class IslandCache {
|
||||
private static final boolean DEBUG2 = false;
|
||||
private static final boolean DEBUG = false;
|
||||
private BSkyBlock plugin = BSkyBlock.getInstance();
|
||||
private BiMap<Location, Island> islandsByLocation;
|
||||
/**
|
||||
* Every player who is associated with an island is in this map.
|
||||
*/
|
||||
private HashMap<UUID, Island> islandsByUUID;
|
||||
// 2D islandGrid of islands, x,z
|
||||
private TreeMap<Integer, TreeMap<Integer, Island>> islandGrid = new TreeMap<>();
|
||||
|
||||
public IslandCache() {
|
||||
islandsByLocation = HashBiMap.create();
|
||||
islandsByUUID = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an island to the grid
|
||||
* @param island
|
||||
*/
|
||||
public void addIsland(Island island) {
|
||||
islandsByLocation.put(island.getCenter(), island);
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: owner = " + island.getOwner());
|
||||
}
|
||||
islandsByUUID.put(island.getOwner(), island);
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: island has " + island.getMemberSet().size() + " members");
|
||||
}
|
||||
for (UUID member: island.getMemberSet()) {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: " + member);
|
||||
}
|
||||
islandsByUUID.put(member, island);
|
||||
}
|
||||
addToGrid(island);
|
||||
}
|
||||
|
||||
public void addPlayer(UUID playerUUID, Island teamIsland) {
|
||||
islandsByUUID.put(playerUUID, teamIsland);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an island to the grid register
|
||||
* @param newIsland
|
||||
*/
|
||||
private void addToGrid(Island newIsland) {
|
||||
if (islandGrid.containsKey(newIsland.getMinX())) {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: min x is in the grid :" + newIsland.getMinX());
|
||||
}
|
||||
TreeMap<Integer, Island> zEntry = islandGrid.get(newIsland.getMinX());
|
||||
if (zEntry.containsKey(newIsland.getMinZ())) {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: min z is in the grid :" + newIsland.getMinZ());
|
||||
}
|
||||
// Island already exists
|
||||
Island conflict = islandGrid.get(newIsland.getMinX()).get(newIsland.getMinZ());
|
||||
plugin.getLogger().warning("*** Duplicate or overlapping islands! ***");
|
||||
plugin.getLogger().warning(
|
||||
"Island at (" + newIsland.getCenter().getBlockX() + ", " + newIsland.getCenter().getBlockZ() + ") conflicts with ("
|
||||
+ conflict.getCenter().getBlockX() + ", " + conflict.getCenter().getBlockZ() + ")");
|
||||
if (conflict.getOwner() != null) {
|
||||
plugin.getLogger().warning("Accepted island is owned by " + plugin.getPlayers().getName(conflict.getOwner()));
|
||||
plugin.getLogger().warning(conflict.getOwner().toString() + ".yml");
|
||||
} else {
|
||||
plugin.getLogger().warning("Accepted island is unowned.");
|
||||
}
|
||||
if (newIsland.getOwner() != null) {
|
||||
plugin.getLogger().warning("Denied island is owned by " + plugin.getPlayers().getName(newIsland.getOwner()));
|
||||
plugin.getLogger().warning(newIsland.getOwner().toString() + ".yml");
|
||||
} else {
|
||||
plugin.getLogger().warning("Denied island is unowned and was just found in the islands folder. Skipping it...");
|
||||
}
|
||||
plugin.getLogger().warning("Recommend that the denied player file is deleted otherwise weird things can happen.");
|
||||
return;
|
||||
} else {
|
||||
// Add island
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: added island to grid at " + newIsland.getMinX() + "," + newIsland.getMinZ());
|
||||
}
|
||||
zEntry.put(newIsland.getMinZ(), newIsland);
|
||||
islandGrid.put(newIsland.getMinX(), zEntry);
|
||||
// plugin.getLogger().info("Debug: " + newIsland.toString());
|
||||
}
|
||||
} else {
|
||||
// Add island
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: added island to grid at " + newIsland.getMinX() + "," + newIsland.getMinZ());
|
||||
}
|
||||
TreeMap<Integer, Island> zEntry = new TreeMap<>();
|
||||
zEntry.put(newIsland.getMinZ(), newIsland);
|
||||
islandGrid.put(newIsland.getMinX(), zEntry);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
islandsByLocation.clear();
|
||||
islandsByUUID.clear();
|
||||
}
|
||||
|
||||
public Island createIsland(Island island) {
|
||||
islandsByLocation.put(island.getCenter(), island);
|
||||
if (island.getOwner() != null) {
|
||||
islandsByUUID.put(island.getOwner(), island);
|
||||
}
|
||||
addToGrid(island);
|
||||
return island;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an island with no owner at location
|
||||
* @param location - the location
|
||||
*/
|
||||
public Island createIsland(Location location){
|
||||
return createIsland(location, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an island with owner. Note this does not create the schematic. It just creates the island data object.
|
||||
* @param location - the location
|
||||
* @param owner - the island owner UUID
|
||||
*/
|
||||
public Island createIsland(Location location, UUID owner){
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: adding island for " + owner + " at " + location);
|
||||
}
|
||||
Island island = new Island(location, owner, plugin.getSettings().getIslandProtectionRange());
|
||||
islandsByLocation.put(location, island);
|
||||
if (owner != null) {
|
||||
islandsByUUID.put(owner, island);
|
||||
}
|
||||
addToGrid(island);
|
||||
return island;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an island from the database. Does not remove blocks
|
||||
* @param island
|
||||
*/
|
||||
public void deleteIslandFromCache(Island island) {
|
||||
if (!islandsByLocation.remove(island.getCenter(), island)) {
|
||||
plugin.getLogger().severe("Could not remove island from cache!");
|
||||
}
|
||||
Iterator<Entry<UUID, Island>> it = islandsByUUID.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry<UUID, Island> en = it.next();
|
||||
if (en.getValue().equals(island)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
// Remove from grid
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: deleting island at " + island.getCenter());
|
||||
}
|
||||
if (island != null) {
|
||||
int x = island.getMinX();
|
||||
int z = island.getMinZ();
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: x = " + x + " z = " + z);
|
||||
}
|
||||
if (islandGrid.containsKey(x)) {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: x found");
|
||||
}
|
||||
TreeMap<Integer, Island> zEntry = islandGrid.get(x);
|
||||
if (zEntry.containsKey(z)) {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: z found - deleting the island");
|
||||
}
|
||||
// Island exists - delete it
|
||||
zEntry.remove(z);
|
||||
islandGrid.put(x, zEntry);
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: could not find z");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Island get(Location location) {
|
||||
return islandsByLocation.get(location);
|
||||
}
|
||||
|
||||
public Island get(UUID uuid) {
|
||||
return islandsByUUID.get(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the island for this player. If they are in a team, the team island is returned
|
||||
* @param uuid - UUID
|
||||
* @return Island
|
||||
*/
|
||||
public Island getIsland(UUID uuid){
|
||||
return islandsByUUID.get(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the island at the x,z location or null if there is none.
|
||||
* This includes the full island space, not just the protected area.
|
||||
*
|
||||
* @param x - x coordinate
|
||||
* @param z - z coordinate
|
||||
* @return Island or null
|
||||
*/
|
||||
public Island getIslandAt(int x, int z) {
|
||||
if (DEBUG2) {
|
||||
plugin.getLogger().info("DEBUG: getting island at " + x + "," + z);
|
||||
plugin.getLogger().info("DEBUG: island grid is " + islandGrid.size());
|
||||
}
|
||||
Entry<Integer, TreeMap<Integer, Island>> en = islandGrid.floorEntry(x);
|
||||
if (en != null) {
|
||||
Entry<Integer, Island> ent = en.getValue().floorEntry(z);
|
||||
if (ent != null) {
|
||||
// Check if in the island range
|
||||
Island island = ent.getValue();
|
||||
if (island.inIslandSpace(x, z)) {
|
||||
if (DEBUG2) {
|
||||
plugin.getLogger().info("DEBUG: In island space");
|
||||
}
|
||||
return island;
|
||||
}
|
||||
if (DEBUG2) {
|
||||
plugin.getLogger().info("DEBUG: not in island space");
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the island at the location or null if there is none.
|
||||
* This includes the full island space, not just the protected area
|
||||
*
|
||||
* @param location - the location
|
||||
* @return Island object
|
||||
*/
|
||||
public Island getIslandAt(Location location) {
|
||||
if (location == null) {
|
||||
//plugin.getLogger().info("DEBUG: location is null");
|
||||
return null;
|
||||
}
|
||||
// World check
|
||||
if (!Util.inWorld(location)) {
|
||||
//plugin.getLogger().info("DEBUG: not in right world");
|
||||
return null;
|
||||
}
|
||||
return getIslandAt(location.getBlockX(), location.getBlockZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the player's island location.
|
||||
* Returns an island location OR a team island location
|
||||
*
|
||||
* @param playerUUID - the player's UUID
|
||||
* @return Location of player's island or null if one does not exist
|
||||
*/
|
||||
public Location getIslandLocation(UUID playerUUID) {
|
||||
if (hasIsland(playerUUID)) {
|
||||
return getIsland(playerUUID).getCenter();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name of the island owned by owner
|
||||
* @param owner - the island owner
|
||||
* @return Returns the name of owner's island, or the owner's name if there is none.
|
||||
*/
|
||||
public String getIslandName(UUID owner) {
|
||||
String result = plugin.getPlayers().getName(owner);
|
||||
if (islandsByUUID.containsKey(owner)) {
|
||||
Island island = islandsByUUID.get(owner);
|
||||
if (!island.getName().isEmpty()) {
|
||||
result = island.getName();
|
||||
}
|
||||
}
|
||||
return ChatColor.translateAlternateColorCodes('&', result) + ChatColor.RESET;
|
||||
}
|
||||
|
||||
public Collection<Island> getIslands() {
|
||||
return Collections.unmodifiableCollection(islandsByLocation.values());
|
||||
}
|
||||
|
||||
public Set<UUID> getMembers(UUID playerUUID) {
|
||||
Island island = islandsByUUID.get(playerUUID);
|
||||
if (island != null) {
|
||||
return island.getMemberSet();
|
||||
}
|
||||
return new HashSet<>(0);
|
||||
}
|
||||
|
||||
public UUID getTeamLeader(UUID playerUUID) {
|
||||
if (islandsByUUID.containsKey(playerUUID)) {
|
||||
return islandsByUUID.get(playerUUID).getOwner();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param playerUUID - the player's UUID
|
||||
* @return true if player has island and owns it
|
||||
*/
|
||||
public boolean hasIsland(UUID playerUUID) {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: checking if " + playerUUID + " has an island");
|
||||
plugin.getLogger().info("DEBUG: islandsByUUID : " + islandsByUUID.toString());
|
||||
|
||||
if (!islandsByUUID.containsKey(playerUUID)) {
|
||||
plugin.getLogger().info("DEBUG: player is not in islandsByUUID");
|
||||
} else {
|
||||
plugin.getLogger().info("DEBUG: owner = " + islandsByUUID.get(playerUUID).getOwner());
|
||||
}
|
||||
}
|
||||
if (islandsByUUID.containsKey(playerUUID) && islandsByUUID.get(playerUUID).getOwner() != null) {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: checking for equals");
|
||||
}
|
||||
if (islandsByUUID.get(playerUUID).getOwner().equals(playerUUID)) {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: has island");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: doesn't have island");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void removePlayer(UUID playerUUID) {
|
||||
Island island = islandsByUUID.get(playerUUID);
|
||||
if (island != null) {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: island found");
|
||||
}
|
||||
if (island.getOwner() != null && island.getOwner().equals(playerUUID)) {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: player is the owner of this island");
|
||||
}
|
||||
// Clear ownership and members
|
||||
island.getMembers().clear();
|
||||
island.setOwner(null);
|
||||
}
|
||||
island.removeMember(playerUUID);
|
||||
}
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: removing reference to island by UUID");
|
||||
}
|
||||
islandsByUUID.remove(playerUUID);
|
||||
|
||||
}
|
||||
|
||||
public void setIslandName(UUID owner, String name) {
|
||||
if (islandsByUUID.containsKey(owner)) {
|
||||
Island island = islandsByUUID.get(owner);
|
||||
island.setName(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return islandsByLocation.size();
|
||||
}
|
||||
|
||||
}
|
@ -1,252 +0,0 @@
|
||||
package us.tastybento.bskyblock.database.managers.island;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import us.tastybento.bskyblock.BSkyBlock;
|
||||
import us.tastybento.bskyblock.api.events.IslandBaseEvent;
|
||||
import us.tastybento.bskyblock.api.events.island.IslandEvent;
|
||||
import us.tastybento.bskyblock.api.events.island.IslandEvent.Reason;
|
||||
import us.tastybento.bskyblock.database.objects.Island;
|
||||
import us.tastybento.bskyblock.island.builders.IslandBuilder;
|
||||
import us.tastybento.bskyblock.island.builders.IslandBuilder.IslandType;
|
||||
|
||||
/**
|
||||
* Create and paste a new island
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class NewIsland {
|
||||
private static final boolean DEBUG = false;
|
||||
private BSkyBlock plugin;
|
||||
private Island island;
|
||||
private final Player player;
|
||||
private final Reason reason;
|
||||
|
||||
private NewIsland(Island oldIsland, Player player, Reason reason) {
|
||||
super();
|
||||
plugin = BSkyBlock.getInstance();
|
||||
this.player = player;
|
||||
this.reason = reason;
|
||||
newIsland();
|
||||
if (oldIsland != null) {
|
||||
// Delete the old island
|
||||
plugin.getIslands().deleteIsland(oldIsland, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the island that was created
|
||||
*/
|
||||
public Island getIsland() {
|
||||
return island;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start building a new island
|
||||
* @return New island builder object
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a new island for a player using a schematic
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public static class Builder {
|
||||
private Island oldIsland;
|
||||
private Player player;
|
||||
private Reason reason;
|
||||
|
||||
public Builder oldIsland(Island oldIsland) {
|
||||
this.oldIsland = oldIsland;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public Builder player(Player player) {
|
||||
this.player = player;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder reason(Reason reason) {
|
||||
this.reason = reason;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Island build() throws IOException {
|
||||
if (player != null) {
|
||||
NewIsland newIsland = new NewIsland(oldIsland, player, reason);
|
||||
return newIsland.getIsland();
|
||||
}
|
||||
throw new IOException("Insufficient parameters. Must have a schematic and a player");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an island.
|
||||
*/
|
||||
public void newIsland() {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: new island");
|
||||
}
|
||||
//long time = System.nanoTime();
|
||||
final UUID playerUUID = player.getUniqueId();
|
||||
/*
|
||||
boolean firstTime = false;
|
||||
if (!plugin.getPlayers().hasIsland(playerUUID)) {
|
||||
firstTime = true;
|
||||
}*/
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: finding island location");
|
||||
}
|
||||
Location next = getNextIsland();
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: found " + next);
|
||||
}
|
||||
|
||||
// Add to the grid
|
||||
island = plugin.getIslands().createIsland(next, playerUUID);
|
||||
// Save the player so that if the server is reset weird things won't happen
|
||||
//plugin.getPlayers().save(true);
|
||||
//plugin.getIslands().save(true);
|
||||
|
||||
// Clear any old home locations (they should be clear, but just in case)
|
||||
plugin.getPlayers().clearHomeLocations(playerUUID);
|
||||
|
||||
// Set the biome
|
||||
//BiomesPanel.setIslandBiome(next, schematic.getBiome());
|
||||
// Set home loction
|
||||
plugin.getPlayers().setHomeLocation(playerUUID, next, 1);
|
||||
|
||||
// Fire event
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: firing event");
|
||||
}
|
||||
IslandBaseEvent event = IslandEvent.builder()
|
||||
.involvedPlayer(player.getUniqueId())
|
||||
.reason(reason)
|
||||
.island(island)
|
||||
.location(island.getCenter())
|
||||
.build();
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: event cancelled status = " + event.isCancelled());
|
||||
}
|
||||
if (!event.isCancelled()) {
|
||||
// Create island
|
||||
new IslandBuilder(plugin, island)
|
||||
.setPlayer(player)
|
||||
.setChestItems(plugin.getSettings().getChestItems())
|
||||
.setType(IslandType.ISLAND)
|
||||
.build();
|
||||
if (plugin.getSettings().isNetherGenerate() && plugin.getSettings().isNetherIslands() && plugin.getIslandWorldManager().getNetherWorld() != null) {
|
||||
new IslandBuilder(plugin,island)
|
||||
.setPlayer(player)
|
||||
.setChestItems(plugin.getSettings().getChestItems())
|
||||
.setType(IslandType.NETHER)
|
||||
.build();
|
||||
}
|
||||
if (plugin.getSettings().isEndGenerate() && plugin.getSettings().isEndIslands() && plugin.getIslandWorldManager().getEndWorld() != null) {
|
||||
new IslandBuilder(plugin,island)
|
||||
.setPlayer(player)
|
||||
.setChestItems(plugin.getSettings().getChestItems())
|
||||
.setType(IslandType.END)
|
||||
.build();
|
||||
}
|
||||
// Teleport player to their island
|
||||
plugin.getIslands().homeTeleport(player);
|
||||
// Fire exit event
|
||||
Reason reasonDone = Reason.CREATED;
|
||||
switch (reason) {
|
||||
case CREATE:
|
||||
reasonDone = Reason.CREATED;
|
||||
break;
|
||||
case RESET:
|
||||
reasonDone = Reason.RESETTED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
IslandEvent.builder()
|
||||
.involvedPlayer(player.getUniqueId())
|
||||
.reason(reasonDone)
|
||||
.island(island)
|
||||
.location(island.getCenter())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the location of next free island spot
|
||||
* @return Location of island spot
|
||||
*/
|
||||
private Location getNextIsland() {
|
||||
Location last = plugin.getIslands().getLast();
|
||||
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: last = " + last);
|
||||
// Find the next free spot
|
||||
}
|
||||
|
||||
if (last == null) {
|
||||
last = new Location(plugin.getIslandWorldManager().getIslandWorld(), plugin.getSettings().getIslandXOffset() + plugin.getSettings().getIslandStartX(),
|
||||
plugin.getSettings().getIslandHeight(), plugin.getSettings().getIslandZOffset() + plugin.getSettings().getIslandStartZ());
|
||||
}
|
||||
Location next = last.clone();
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: last 2 = " + last);
|
||||
}
|
||||
while (plugin.getIslands().isIsland(next)) {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: getting next loc");
|
||||
}
|
||||
next = nextGridLocation(next);
|
||||
}
|
||||
// Make the last next, last
|
||||
last = next.clone();
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: last 3 = " + last);
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the next free island spot based off the last known island Uses
|
||||
* island_distance setting from the config file Builds up in a grid fashion
|
||||
*
|
||||
* @param lastIsland
|
||||
* @return Location of next free island
|
||||
*/
|
||||
private Location nextGridLocation(final Location lastIsland) {
|
||||
int x = lastIsland.getBlockX();
|
||||
int z = lastIsland.getBlockZ();
|
||||
Location nextPos = lastIsland;
|
||||
if (x < z) {
|
||||
if (-1 * x < z) {
|
||||
nextPos.setX(nextPos.getX() + plugin.getSettings().getIslandDistance()*2);
|
||||
return nextPos;
|
||||
}
|
||||
nextPos.setZ(nextPos.getZ() + plugin.getSettings().getIslandDistance()*2);
|
||||
return nextPos;
|
||||
}
|
||||
if (x > z) {
|
||||
if (-1 * x >= z) {
|
||||
nextPos.setX(nextPos.getX() - plugin.getSettings().getIslandDistance()*2);
|
||||
return nextPos;
|
||||
}
|
||||
nextPos.setZ(nextPos.getZ() - plugin.getSettings().getIslandDistance()*2);
|
||||
return nextPos;
|
||||
}
|
||||
if (x <= 0) {
|
||||
nextPos.setZ(nextPos.getZ() + plugin.getSettings().getIslandDistance()*2);
|
||||
return nextPos;
|
||||
}
|
||||
nextPos.setZ(nextPos.getZ() - plugin.getSettings().getIslandDistance()*2);
|
||||
return nextPos;
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
package us.tastybento.bskyblock.database.mysql;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class MySQLDatabaseResourceCloser {
|
||||
|
||||
/**
|
||||
* Closes the provided ResultSets
|
||||
*
|
||||
* @param resultSets
|
||||
* ResultSets that should be closed
|
||||
*/
|
||||
public static void close(ResultSet... resultSets) {
|
||||
|
||||
if (resultSets == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ResultSet resultSet : resultSets) {
|
||||
if (resultSet != null) {
|
||||
try {
|
||||
resultSet.close();
|
||||
} catch (SQLException e) {
|
||||
Bukkit.getLogger().severe("Could not close MySQL resultset");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the provided Statements
|
||||
*
|
||||
* @param statements
|
||||
* Statements that should be closed
|
||||
*/
|
||||
public static void close(Statement... statements) {
|
||||
/*
|
||||
* No need to create methods for PreparedStatement and
|
||||
* CallableStatement, because they extend Statement.
|
||||
*/
|
||||
|
||||
if (statements == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Statement statement : statements) {
|
||||
if (statement != null) {
|
||||
try {
|
||||
statement.close();
|
||||
} catch (SQLException e) {
|
||||
Bukkit.getLogger().severe("Could not close MySQL statement");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the provided Connections
|
||||
*
|
||||
* @param connections
|
||||
* Connections that should be closed
|
||||
*/
|
||||
public static void close(Connection... connections) {
|
||||
if (connections == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Connection connection : connections) {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
Bukkit.getLogger().severe("Could not close MySQL connection");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
package us.tastybento.bskyblock.database.mysql.adapters;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
public class PotionEffectTypeAdapter extends TypeAdapter<PotionEffectType> {
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter out, PotionEffectType value) throws IOException {
|
||||
if (value == null) {
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
out.value(value.getName());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public PotionEffectType read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
return null;
|
||||
}
|
||||
return PotionEffectType.getByName(reader.nextString());
|
||||
}
|
||||
}
|
@ -1,349 +0,0 @@
|
||||
package us.tastybento.bskyblock.database.mysql;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
||||
import us.tastybento.bskyblock.api.flags.Flag;
|
||||
import us.tastybento.bskyblock.database.objects.DataObject;
|
||||
import us.tastybento.bskyblock.database.objects.adapters.Adapter;
|
||||
import us.tastybento.bskyblock.database.objects.adapters.FlagSerializer;
|
||||
|
||||
|
||||
public class MySQLDatabaseHandlerTestDataObject implements DataObject {
|
||||
|
||||
private String uniqueId = "";
|
||||
|
||||
//// Island ////
|
||||
// The center of the island itself
|
||||
private Location center;
|
||||
|
||||
// Island range
|
||||
private int range;
|
||||
|
||||
// Coordinates of the island area
|
||||
private int minX;
|
||||
|
||||
private int minZ;
|
||||
|
||||
// Coordinates of minimum protected area
|
||||
private int minProtectedX;
|
||||
|
||||
private int minProtectedZ;
|
||||
|
||||
// Protection size
|
||||
private int protectionRange;
|
||||
|
||||
// World the island is in
|
||||
private World world;
|
||||
|
||||
// Display name
|
||||
private String name;
|
||||
|
||||
// Time parameters
|
||||
private long createdDate;
|
||||
|
||||
private long updatedDate;
|
||||
|
||||
//// Team ////
|
||||
private UUID owner;
|
||||
private HashMap<UUID, Integer> members = new HashMap<>();
|
||||
|
||||
//// State ////
|
||||
private boolean locked = false;
|
||||
private boolean spawn = false;
|
||||
|
||||
private boolean purgeProtected = false;
|
||||
|
||||
//// Protection flags ////
|
||||
@Adapter(FlagSerializer.class)
|
||||
private HashMap<Flag, Integer> flags = new HashMap<>();
|
||||
|
||||
private int levelHandicap;
|
||||
private Location spawnPoint;
|
||||
|
||||
public MySQLDatabaseHandlerTestDataObject() {}
|
||||
|
||||
/**
|
||||
* @return the uniqueId
|
||||
*/
|
||||
public String getUniqueId() {
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uniqueId - unique ID the uniqueId to set
|
||||
*/
|
||||
public void setUniqueId(String uniqueId) {
|
||||
this.uniqueId = uniqueId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the center
|
||||
*/
|
||||
public Location getCenter() {
|
||||
return center;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param center the center to set
|
||||
*/
|
||||
public void setCenter(Location center) {
|
||||
this.center = center;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the range
|
||||
*/
|
||||
public int getRange() {
|
||||
return range;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param range the range to set
|
||||
*/
|
||||
public void setRange(int range) {
|
||||
this.range = range;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minX
|
||||
*/
|
||||
public int getMinX() {
|
||||
return minX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param minX the minX to set
|
||||
*/
|
||||
public void setMinX(int minX) {
|
||||
this.minX = minX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minZ
|
||||
*/
|
||||
public int getMinZ() {
|
||||
return minZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param minZ the minZ to set
|
||||
*/
|
||||
public void setMinZ(int minZ) {
|
||||
this.minZ = minZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minProtectedX
|
||||
*/
|
||||
public int getMinProtectedX() {
|
||||
return minProtectedX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param minProtectedX the minProtectedX to set
|
||||
*/
|
||||
public void setMinProtectedX(int minProtectedX) {
|
||||
this.minProtectedX = minProtectedX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minProtectedZ
|
||||
*/
|
||||
public int getMinProtectedZ() {
|
||||
return minProtectedZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param minProtectedZ the minProtectedZ to set
|
||||
*/
|
||||
public void setMinProtectedZ(int minProtectedZ) {
|
||||
this.minProtectedZ = minProtectedZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the protectionRange
|
||||
*/
|
||||
public int getProtectionRange() {
|
||||
return protectionRange;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param protectionRange the protectionRange to set
|
||||
*/
|
||||
public void setProtectionRange(int protectionRange) {
|
||||
this.protectionRange = protectionRange;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the world
|
||||
*/
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param world the world to set
|
||||
*/
|
||||
public void setWorld(World world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name the name to set
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the createdDate
|
||||
*/
|
||||
public long getCreatedDate() {
|
||||
return createdDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param createdDate the createdDate to set
|
||||
*/
|
||||
public void setCreatedDate(long createdDate) {
|
||||
this.createdDate = createdDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the updatedDate
|
||||
*/
|
||||
public long getUpdatedDate() {
|
||||
return updatedDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param updatedDate the updatedDate to set
|
||||
*/
|
||||
public void setUpdatedDate(long updatedDate) {
|
||||
this.updatedDate = updatedDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the owner
|
||||
*/
|
||||
public UUID getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param owner - the island owner the owner to set
|
||||
*/
|
||||
public void setOwner(UUID owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the members
|
||||
*/
|
||||
public HashMap<UUID, Integer> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param members the members to set
|
||||
*/
|
||||
public void setMembers(HashMap<UUID, Integer> members) {
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the locked
|
||||
*/
|
||||
public boolean isLocked() {
|
||||
return locked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param locked the locked to set
|
||||
*/
|
||||
public void setLocked(boolean locked) {
|
||||
this.locked = locked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the spawn
|
||||
*/
|
||||
public boolean isSpawn() {
|
||||
return spawn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param spawn the spawn to set
|
||||
*/
|
||||
public void setSpawn(boolean spawn) {
|
||||
this.spawn = spawn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the purgeProtected
|
||||
*/
|
||||
public boolean isPurgeProtected() {
|
||||
return purgeProtected;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param purgeProtected the purgeProtected to set
|
||||
*/
|
||||
public void setPurgeProtected(boolean purgeProtected) {
|
||||
this.purgeProtected = purgeProtected;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the flags
|
||||
*/
|
||||
public HashMap<Flag, Integer> getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param flags the flags to set
|
||||
*/
|
||||
public void setFlags(HashMap<Flag, Integer> flags) {
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the levelHandicap
|
||||
*/
|
||||
public int getLevelHandicap() {
|
||||
return levelHandicap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param levelHandicap the levelHandicap to set
|
||||
*/
|
||||
public void setLevelHandicap(int levelHandicap) {
|
||||
this.levelHandicap = levelHandicap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the spawnPoint
|
||||
*/
|
||||
public Location getSpawnPoint() {
|
||||
return spawnPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param spawnPoint the spawnPoint to set
|
||||
*/
|
||||
public void setSpawnPoint(Location spawnPoint) {
|
||||
this.spawnPoint = spawnPoint;
|
||||
}
|
||||
|
||||
}
|
@ -1,276 +0,0 @@
|
||||
package us.tastybento.bskyblock.database.mysqljson;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import us.tastybento.bskyblock.BSkyBlock;
|
||||
import us.tastybento.bskyblock.database.objects.DataObject;
|
||||
|
||||
/**
|
||||
* Tracks the following info on the player
|
||||
*
|
||||
* @author tastybento
|
||||
*/
|
||||
public class Players implements DataObject {
|
||||
private Map<Integer, Location> homeLocations = new HashMap<>();
|
||||
private String uniqueId;
|
||||
private String playerName;
|
||||
private int resetsLeft;
|
||||
private String locale = "";
|
||||
private int deaths;
|
||||
private Map<Location, Long> kickedList = new HashMap<>();
|
||||
|
||||
/**
|
||||
* This is required for database storage
|
||||
*/
|
||||
public Players() {}
|
||||
|
||||
/**
|
||||
* @param plugin - BSkyBlock plugin object
|
||||
* @param uniqueId - unique ID
|
||||
* Constructor - initializes the state variables
|
||||
*
|
||||
*/
|
||||
public Players(BSkyBlock plugin, final UUID uniqueId) {
|
||||
this.uniqueId = uniqueId.toString();
|
||||
homeLocations = new HashMap<>();
|
||||
playerName = "";
|
||||
resetsLeft = plugin.getSettings().getResetLimit();
|
||||
locale = "";
|
||||
kickedList = new HashMap<>();
|
||||
playerName = Bukkit.getServer().getOfflinePlayer(uniqueId).getName();
|
||||
if (playerName == null) {
|
||||
playerName = uniqueId.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default home location.
|
||||
* @return Location
|
||||
*/
|
||||
public Location getHomeLocation() {
|
||||
return getHomeLocation(1); // Default
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the home location by number.
|
||||
* @param number - a number
|
||||
* @return Location of this home or null if not available
|
||||
*/
|
||||
public Location getHomeLocation(int number) {
|
||||
/*
|
||||
Bukkit.getLogger().info("DEBUG: getting home location " + number);
|
||||
|
||||
Bukkit.getLogger().info("DEBUG: " + homeLocations.toString());
|
||||
for (Entry<Integer, Location> en : homeLocations.entrySet()) {
|
||||
Bukkit.getLogger().info("DEBUG: " + en.getKey() + " ==> " + en.getValue());
|
||||
if (number == en.getKey())
|
||||
Bukkit.getLogger().info("DEBUG: key = number");
|
||||
}*/
|
||||
return homeLocations.get(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of home locations
|
||||
*/
|
||||
public Map<Integer,Location> getHomeLocations() {
|
||||
return homeLocations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the kickedList
|
||||
*/
|
||||
public Map<Location, Long> getKickedList() {
|
||||
return kickedList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param kickedList the kickedList to set
|
||||
*/
|
||||
public void setKickedList(Map<Location, Long> kickedList) {
|
||||
this.kickedList = kickedList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param homeLocations the homeLocations to set
|
||||
*/
|
||||
public void setHomeLocations(Map<Integer, Location> homeLocations) {
|
||||
//Bukkit.getLogger().info("DEBUG: " + homeLocations.toString());
|
||||
this.homeLocations = homeLocations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param playerName the playerName to set
|
||||
*/
|
||||
public void setPlayerName(String playerName) {
|
||||
this.playerName = playerName;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return Bukkit.getPlayer(UUID.fromString(uniqueId));
|
||||
}
|
||||
|
||||
public UUID getPlayerUUID() {
|
||||
return UUID.fromString(uniqueId);
|
||||
}
|
||||
|
||||
public String getPlayerName() {
|
||||
return playerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the resetsLeft
|
||||
*/
|
||||
public int getResetsLeft() {
|
||||
return resetsLeft;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resetsLeft
|
||||
* the resetsLeft to set
|
||||
*/
|
||||
public void setResetsLeft(int resetsLeft) {
|
||||
this.resetsLeft = resetsLeft;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the home location of the player in a String format
|
||||
*
|
||||
* @param l
|
||||
* a Bukkit location
|
||||
*/
|
||||
public void setHomeLocation(final Location l) {
|
||||
setHomeLocation(l, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the numbered home location of the player. Numbering starts at 1.
|
||||
* @param location - the location
|
||||
* @param number - a number
|
||||
*/
|
||||
public void setHomeLocation(final Location location, int number) {
|
||||
if (location == null) {
|
||||
homeLocations.clear();
|
||||
} else {
|
||||
homeLocations.put(number, location);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the uuid for this player object
|
||||
* @param uuid - UUID
|
||||
*/
|
||||
public void setPlayerUUID(final UUID uuid) {
|
||||
uniqueId = uuid.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all home Locations
|
||||
*/
|
||||
public void clearHomeLocations() {
|
||||
homeLocations.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the locale
|
||||
*/
|
||||
public String getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param locale the locale to set
|
||||
*/
|
||||
public void setLocale(String locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the deaths
|
||||
*/
|
||||
public int getDeaths() {
|
||||
return deaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param deaths the deaths to set
|
||||
*/
|
||||
public void setDeaths(int deaths) {
|
||||
this.deaths = deaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add death
|
||||
*/
|
||||
public void addDeath() {
|
||||
deaths++;
|
||||
if (deaths > getPlugin().getSettings().getDeathsMax()) {
|
||||
deaths = getPlugin().getSettings().getDeathsMax();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can invite or still waiting for cool down to end
|
||||
*
|
||||
* @param location - the location
|
||||
* to check
|
||||
* @return number of mins/hours left until cool down ends
|
||||
*/
|
||||
public long getInviteCoolDownTime(Location location) {
|
||||
// Check the hashmap
|
||||
if (location != null && kickedList.containsKey(location)) {
|
||||
// plugin.getLogger().info("DEBUG: Location is known");
|
||||
// The location is in the list
|
||||
// Check the date/time
|
||||
Date kickedDate = new Date(kickedList.get(location));
|
||||
// plugin.getLogger().info("DEBUG: kicked date = " + kickedDate);
|
||||
Calendar coolDownTime = Calendar.getInstance();
|
||||
coolDownTime.setTime(kickedDate);
|
||||
// coolDownTime.add(Calendar.HOUR_OF_DAY, Settings.inviteWait);
|
||||
coolDownTime.add(Calendar.MINUTE, getPlugin().getSettings().getInviteWait());
|
||||
// Add the invite cooldown period
|
||||
Calendar timeNow = Calendar.getInstance();
|
||||
// plugin.getLogger().info("DEBUG: date now = " + timeNow);
|
||||
if (coolDownTime.before(timeNow)) {
|
||||
// The time has expired
|
||||
kickedList.remove(location);
|
||||
return 0;
|
||||
} else {
|
||||
// Still not there yet
|
||||
// long hours = (coolDownTime.getTimeInMillis() -
|
||||
// timeNow.getTimeInMillis())/(1000 * 60 * 60);
|
||||
// Temp minutes
|
||||
return (coolDownTime.getTimeInMillis() - timeNow.getTimeInMillis()) / (1000 * 60);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the invite cooldown timer for location. Location should be the center of an island.
|
||||
* @param location - the location
|
||||
*/
|
||||
public void startInviteCoolDownTimer(Location location) {
|
||||
if (location != null) {
|
||||
kickedList.put(location, System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueId() {
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUniqueId(String uniqueId) {
|
||||
this.uniqueId = uniqueId;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user