285 lines
9.8 KiB
Java
285 lines
9.8 KiB
Java
package world.bentobox.bentobox.managers.island;
|
|
|
|
import java.io.IOException;
|
|
import java.util.EnumMap;
|
|
import java.util.Map;
|
|
|
|
import org.bukkit.Location;
|
|
import org.bukkit.Material;
|
|
import org.bukkit.World;
|
|
import org.bukkit.World.Environment;
|
|
import org.bukkit.util.Vector;
|
|
|
|
import world.bentobox.bentobox.BentoBox;
|
|
import world.bentobox.bentobox.api.events.IslandBaseEvent;
|
|
import world.bentobox.bentobox.api.events.island.IslandEvent;
|
|
import world.bentobox.bentobox.api.events.island.IslandEvent.Reason;
|
|
import world.bentobox.bentobox.api.user.User;
|
|
import world.bentobox.bentobox.database.objects.Island;
|
|
import world.bentobox.bentobox.util.Util;
|
|
|
|
/**
|
|
* Create and paste a new island
|
|
* @author tastybento
|
|
*
|
|
*/
|
|
public class NewIsland {
|
|
private static final Integer MAX_UNOWNED_ISLANDS = 10;
|
|
private BentoBox plugin;
|
|
private Island island;
|
|
private final User user;
|
|
private final Reason reason;
|
|
private final World world;
|
|
private enum Result {
|
|
ISLAND_FOUND,
|
|
BLOCK_AT_CENTER,
|
|
BLOCKS_IN_AREA,
|
|
FREE
|
|
}
|
|
|
|
private NewIsland(Island oldIsland, User user, Reason reason, World world) {
|
|
super();
|
|
plugin = BentoBox.getInstance();
|
|
this.user = user;
|
|
this.reason = reason;
|
|
this.world = world;
|
|
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
|
|
* @author tastybento
|
|
*
|
|
*/
|
|
public static class Builder {
|
|
private Island oldIsland2;
|
|
private User user2;
|
|
private Reason reason2;
|
|
private World world2;
|
|
|
|
public Builder oldIsland(Island oldIsland) {
|
|
this.oldIsland2 = oldIsland;
|
|
this.world2 = oldIsland.getWorld();
|
|
return this;
|
|
}
|
|
|
|
|
|
public Builder player(User player) {
|
|
this.user2 = player;
|
|
return this;
|
|
}
|
|
|
|
public Builder reason(Reason reason) {
|
|
this.reason2 = reason;
|
|
return this;
|
|
}
|
|
|
|
public Builder world(World world) {
|
|
this.world2 = world;
|
|
return this;
|
|
}
|
|
|
|
public Island build() throws IOException {
|
|
if (user2 != null) {
|
|
NewIsland newIsland = new NewIsland(oldIsland2, user2, reason2, world2);
|
|
return newIsland.getIsland();
|
|
}
|
|
throw new IOException("Insufficient parameters. Must have a schematic and a player");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes an island.
|
|
*/
|
|
public void newIsland() {
|
|
Location next = getNextIsland();
|
|
if (next == null) {
|
|
plugin.logError("Failed to make island - no unoccupied spot found");
|
|
return;
|
|
}
|
|
// Add to the grid
|
|
island = plugin.getIslands().createIsland(next, user.getUniqueId());
|
|
// Save the player so that if the server is reset weird things won't happen
|
|
|
|
// Clear any old home locations (they should be clear, but just in case)
|
|
plugin.getPlayers().clearHomeLocations(world, user.getUniqueId());
|
|
|
|
// Set home location
|
|
plugin.getPlayers().setHomeLocation(user, next, 1);
|
|
|
|
// Fire event
|
|
IslandBaseEvent event = IslandEvent.builder()
|
|
.involvedPlayer(user.getUniqueId())
|
|
.reason(reason)
|
|
.island(island)
|
|
.location(island.getCenter())
|
|
.build();
|
|
if (event.isCancelled()) {
|
|
return;
|
|
}
|
|
// Create island
|
|
plugin.getSchemsManager().paste(world, island, () -> {
|
|
// Set initial spawn point if one exists
|
|
if (island.getSpawnPoint(Environment.NORMAL) != null) {
|
|
plugin.getPlayers().setHomeLocation(user, island.getSpawnPoint(Environment.NORMAL), 1);
|
|
}
|
|
// Stop the player from falling or moving if they are
|
|
user.getPlayer().setVelocity(new Vector(0,0,0));
|
|
user.getPlayer().setFallDistance(0F);
|
|
|
|
// Teleport player after this island is built
|
|
plugin.getIslands().homeTeleport(world, user.getPlayer(), true);
|
|
});
|
|
// Make nether island
|
|
if (plugin.getIWM().isNetherGenerate(world) && plugin.getIWM().isNetherIslands(world) && plugin.getIWM().getNetherWorld(world) != null) {
|
|
plugin.getSchemsManager().paste(plugin.getIWM().getNetherWorld(world), island);
|
|
}
|
|
|
|
// Make end island
|
|
if (plugin.getIWM().isEndGenerate(world) && plugin.getIWM().isEndIslands(world) && plugin.getIWM().getEndWorld(world) != null) {
|
|
plugin.getSchemsManager().paste(plugin.getIWM().getEndWorld(world), island);
|
|
}
|
|
|
|
// Set default settings
|
|
island.setFlagsDefaults();
|
|
|
|
// 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(user.getUniqueId())
|
|
.reason(reasonDone)
|
|
.island(island)
|
|
.location(island.getCenter())
|
|
.build();
|
|
|
|
}
|
|
|
|
/**
|
|
* Get the location of next free island spot
|
|
* @return Location of island spot or null if one cannot be found
|
|
*/
|
|
private Location getNextIsland() {
|
|
Location last = plugin.getIslands().getLast(world);
|
|
if (last == null) {
|
|
last = new Location(world, plugin.getIWM().getIslandXOffset(world) + plugin.getIWM().getIslandStartX(world),
|
|
plugin.getIWM().getIslandHeight(world), plugin.getIWM().getIslandZOffset(world) + plugin.getIWM().getIslandStartZ(world));
|
|
}
|
|
// Find a free spot
|
|
Map<Result, Integer> result = new EnumMap<>(Result.class);
|
|
Result r = isIsland(last);
|
|
while (!r.equals(Result.FREE) && result.getOrDefault(Result.BLOCK_AT_CENTER, 0) < MAX_UNOWNED_ISLANDS) {
|
|
last = nextGridLocation(last);
|
|
result.merge(r, 1, (k,v) -> v++);
|
|
r = isIsland(last);
|
|
}
|
|
if (!r.equals(Result.FREE)) {
|
|
// We could not find a free spot within the limit required. It's likely this world is not empty
|
|
plugin.logError("Could not find a free spot for islands! Is this world empty?");
|
|
plugin.logError("Blocks at center locations: " + result.getOrDefault(Result.BLOCK_AT_CENTER, 0) + " max " + MAX_UNOWNED_ISLANDS);
|
|
plugin.logError("Blocks around center locations: " + result.getOrDefault(Result.BLOCKS_IN_AREA, 0) + " max " + MAX_UNOWNED_ISLANDS);
|
|
plugin.logError("Known islands: " + result.getOrDefault(Result.ISLAND_FOUND, 0) + " max unlimited.");
|
|
return null;
|
|
}
|
|
plugin.getIslands().setLast(last);
|
|
return last;
|
|
}
|
|
|
|
/**
|
|
* Checks if there is an island or blocks at this location
|
|
* @param location - the location
|
|
* @return true if island found, null if blocks found, false if nothing found
|
|
*/
|
|
private Result isIsland(Location location){
|
|
location = Util.getClosestIsland(location);
|
|
if (plugin.getIslands().getIslandAt(location).isPresent()) {
|
|
return Result.ISLAND_FOUND;
|
|
}
|
|
|
|
if (!plugin.getIWM().isUseOwnGenerator(location.getWorld())) {
|
|
// Block check
|
|
if (!location.getBlock().isEmpty() && !location.getBlock().getType().equals(Material.WATER)) {
|
|
plugin.getIslands().createIsland(location);
|
|
return Result.BLOCK_AT_CENTER;
|
|
}
|
|
// Look around
|
|
for (int x = -5; x <= 5; x++) {
|
|
for (int y = 10; y < location.getWorld().getMaxHeight(); y++) {
|
|
for (int z = -5; z <= 5; z++) {
|
|
if (!location.getWorld().getBlockAt(x + location.getBlockX(), y, z + location.getBlockZ()).isEmpty()
|
|
&& !location.getWorld().getBlockAt(x + location.getBlockX(), y, z + location.getBlockZ()).getType().equals(Material.WATER)) {
|
|
plugin.getIslands().createIsland(location);
|
|
return Result.BLOCKS_IN_AREA;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Result.FREE;
|
|
}
|
|
|
|
|
|
/**
|
|
* 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 - last island location
|
|
* @return Location of next free island
|
|
*/
|
|
private Location nextGridLocation(final Location lastIsland) {
|
|
int x = lastIsland.getBlockX();
|
|
int z = lastIsland.getBlockZ();
|
|
int d = plugin.getIWM().getIslandDistance(lastIsland.getWorld()) * 2;
|
|
if (x < z) {
|
|
if (-1 * x < z) {
|
|
lastIsland.setX(lastIsland.getX() + d);
|
|
return lastIsland;
|
|
}
|
|
lastIsland.setZ(lastIsland.getZ() + d);
|
|
return lastIsland;
|
|
}
|
|
if (x > z) {
|
|
if (-1 * x >= z) {
|
|
lastIsland.setX(lastIsland.getX() - d);
|
|
return lastIsland;
|
|
}
|
|
lastIsland.setZ(lastIsland.getZ() - d);
|
|
return lastIsland;
|
|
}
|
|
if (x <= 0) {
|
|
lastIsland.setZ(lastIsland.getZ() + d);
|
|
return lastIsland;
|
|
}
|
|
lastIsland.setZ(lastIsland.getZ() - d);
|
|
return lastIsland;
|
|
}
|
|
}
|