mirror of
https://github.com/PryPurity/WorldBorder.git
synced 2024-11-25 12:05:15 +01:00
Reformated + Update to support 1.15+
This commit is contained in:
parent
44f388f3ba
commit
35f4af67c2
191
pom.xml
191
pom.xml
@ -1,100 +1,101 @@
|
|||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.wimbli.WorldBorder</groupId>
|
||||||
|
<artifactId>WorldBorder</artifactId>
|
||||||
|
<version>1.9.10 (beta)</version>
|
||||||
|
<name>WorldBorder</name>
|
||||||
|
<url>https://github.com/Brettflan/WorldBorder</url>
|
||||||
|
<issueManagement>
|
||||||
|
<system>GitHub</system>
|
||||||
|
<url>https://github.com/Brettflan/WorldBorder/issues</url>
|
||||||
|
</issueManagement>
|
||||||
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
<properties>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<groupId>com.wimbli.WorldBorder</groupId>
|
</properties>
|
||||||
<artifactId>WorldBorder</artifactId>
|
|
||||||
<version>1.9.10 (beta)</version>
|
|
||||||
<name>WorldBorder</name>
|
|
||||||
<url>https://github.com/Brettflan/WorldBorder</url>
|
|
||||||
<issueManagement>
|
|
||||||
<system>GitHub</system>
|
|
||||||
<url>https://github.com/Brettflan/WorldBorder/issues</url>
|
|
||||||
</issueManagement>
|
|
||||||
|
|
||||||
<properties>
|
<repositories>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<repository>
|
||||||
</properties>
|
<id>spigot-repo</id>
|
||||||
|
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>dynmap-repo</id>
|
||||||
|
<url>https://repo.mikeprimm.com/</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>papermc</id>
|
||||||
|
<url>https://papermc.io/repo/repository/maven-public/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
<repositories>
|
<dependencies>
|
||||||
<repository>
|
<!--Spigot-API-->
|
||||||
<id>spigot-repo</id>
|
<dependency>
|
||||||
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
|
<groupId>org.spigotmc</groupId>
|
||||||
</repository>
|
<artifactId>spigot-api</artifactId>
|
||||||
<repository>
|
<version>1.15.2-R0.1-SNAPSHOT</version>
|
||||||
<id>dynmap-repo</id>
|
<scope>provided</scope>
|
||||||
<url>https://repo.mikeprimm.com/</url>
|
</dependency>
|
||||||
</repository>
|
<!--Bukkit API-->
|
||||||
<repository>
|
<dependency>
|
||||||
<id>papermc</id>
|
<groupId>org.bukkit</groupId>
|
||||||
<url>https://papermc.io/repo/repository/maven-public/</url>
|
<artifactId>bukkit</artifactId>
|
||||||
</repository>
|
<version>1.15.2-R0.1-SNAPSHOT</version>
|
||||||
</repositories>
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<!--Dynmap API-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>us.dynmap</groupId>
|
||||||
|
<artifactId>dynmap-api</artifactId>
|
||||||
|
<version>2.5</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.papermc</groupId>
|
||||||
|
<artifactId>paperlib</artifactId>
|
||||||
|
<version>1.0.2</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
<dependencies>
|
<build>
|
||||||
<!--Spigot-API-->
|
<defaultGoal>clean install</defaultGoal>
|
||||||
<dependency>
|
<finalName>${project.artifactId}</finalName>
|
||||||
<groupId>org.spigotmc</groupId>
|
<plugins>
|
||||||
<artifactId>spigot-api</artifactId>
|
<plugin>
|
||||||
<version>1.14-R0.1-SNAPSHOT</version>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<scope>provided</scope>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
</dependency>
|
<version>3.8.0</version>
|
||||||
<!--Bukkit API-->
|
<configuration>
|
||||||
<dependency>
|
<source>1.8</source>
|
||||||
<groupId>org.bukkit</groupId>
|
<target>1.8</target>
|
||||||
<artifactId>bukkit</artifactId>
|
</configuration>
|
||||||
<version>1.14-R0.1-SNAPSHOT</version>
|
</plugin>
|
||||||
<scope>provided</scope>
|
<plugin>
|
||||||
</dependency>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<!--Dynmap API-->
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<dependency>
|
<version>3.1.1</version>
|
||||||
<groupId>us.dynmap</groupId>
|
<configuration>
|
||||||
<artifactId>dynmap-api</artifactId>
|
<dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml
|
||||||
<version>2.5</version>
|
</dependencyReducedPomLocation>
|
||||||
<scope>provided</scope>
|
<relocations>
|
||||||
</dependency>
|
<relocation>
|
||||||
<dependency>
|
<pattern>io.papermc.lib</pattern>
|
||||||
<groupId>io.papermc</groupId>
|
<shadedPattern>com.wimbli.WorldBorder.paperlib</shadedPattern> <!-- Replace this -->
|
||||||
<artifactId>paperlib</artifactId>
|
</relocation>
|
||||||
<version>1.0.2</version>
|
</relocations>
|
||||||
<scope>compile</scope>
|
</configuration>
|
||||||
</dependency>
|
<executions>
|
||||||
</dependencies>
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
<build>
|
<goals>
|
||||||
<defaultGoal>clean install</defaultGoal>
|
<goal>shade</goal>
|
||||||
<finalName>${project.artifactId}</finalName>
|
</goals>
|
||||||
<plugins>
|
</execution>
|
||||||
<plugin>
|
</executions>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
</plugin>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
</plugins>
|
||||||
<version>3.8.0</version>
|
</build>
|
||||||
<configuration>
|
|
||||||
<source>1.8</source>
|
|
||||||
<target>1.8</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
|
||||||
<version>3.1.1</version>
|
|
||||||
<configuration>
|
|
||||||
<dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml</dependencyReducedPomLocation>
|
|
||||||
<relocations>
|
|
||||||
<relocation>
|
|
||||||
<pattern>io.papermc.lib</pattern>
|
|
||||||
<shadedPattern>com.wimbli.WorldBorder.paperlib</shadedPattern> <!-- Replace this -->
|
|
||||||
</relocation>
|
|
||||||
</relocations>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>shade</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -9,27 +9,23 @@ import org.bukkit.event.Listener;
|
|||||||
import org.bukkit.event.block.BlockPlaceEvent;
|
import org.bukkit.event.block.BlockPlaceEvent;
|
||||||
|
|
||||||
|
|
||||||
public class BlockPlaceListener implements Listener
|
public class BlockPlaceListener implements Listener {
|
||||||
{
|
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
public void onBlockPlace(BlockPlaceEvent event) {
|
||||||
public void onBlockPlace(BlockPlaceEvent event)
|
Location loc = event.getBlockPlaced().getLocation();
|
||||||
{
|
if (loc == null) return;
|
||||||
Location loc = event.getBlockPlaced().getLocation();
|
|
||||||
if (loc == null) return;
|
|
||||||
|
|
||||||
World world = loc.getWorld();
|
World world = loc.getWorld();
|
||||||
if (world == null) return;
|
if (world == null) return;
|
||||||
BorderData border = Config.Border(world.getName());
|
BorderData border = Config.Border(world.getName());
|
||||||
if (border == null) return;
|
if (border == null) return;
|
||||||
|
|
||||||
if (!border.insideBorder(loc.getX(), loc.getZ(), Config.ShapeRound()))
|
if (!border.insideBorder(loc.getX(), loc.getZ(), Config.ShapeRound())) {
|
||||||
{
|
event.setCancelled(true);
|
||||||
event.setCancelled(true);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void unregister()
|
public void unregister() {
|
||||||
{
|
HandlerList.unregisterAll(this);
|
||||||
HandlerList.unregisterAll(this);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,178 +1,157 @@
|
|||||||
package com.wimbli.WorldBorder;
|
package com.wimbli.WorldBorder;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.LivingEntity;
|
import org.bukkit.entity.LivingEntity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
import org.bukkit.World;
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
|
||||||
public class BorderCheckTask implements Runnable
|
public class BorderCheckTask implements Runnable {
|
||||||
{
|
// track players who are being handled (moved back inside the border) already; needed since Bukkit is sometimes sending teleport events with the old (now incorrect) location still indicated, which can lead to a loop when we then teleport them thinking they're outside the border, triggering event again, etc.
|
||||||
@Override
|
private static Set<String> handlingPlayers = Collections.synchronizedSet(new LinkedHashSet<String>());
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
// if knockback is set to 0, simply return
|
|
||||||
if (Config.KnockBack() == 0.0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Collection<Player> players = ImmutableList.copyOf(Bukkit.getServer().getOnlinePlayers());
|
// set targetLoc only if not current player location; set returnLocationOnly to true to have new Location returned if they need to be moved to one, instead of directly handling it
|
||||||
|
public static Location checkPlayer(Player player, Location targetLoc, boolean returnLocationOnly, boolean notify) {
|
||||||
|
if (player == null || !player.isOnline()) return null;
|
||||||
|
|
||||||
for (Player player : players)
|
Location loc = (targetLoc == null) ? player.getLocation().clone() : targetLoc;
|
||||||
{
|
if (loc == null) return null;
|
||||||
checkPlayer(player, null, false, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// track players who are being handled (moved back inside the border) already; needed since Bukkit is sometimes sending teleport events with the old (now incorrect) location still indicated, which can lead to a loop when we then teleport them thinking they're outside the border, triggering event again, etc.
|
World world = loc.getWorld();
|
||||||
private static Set<String> handlingPlayers = Collections.synchronizedSet(new LinkedHashSet<String>());
|
if (world == null) return null;
|
||||||
|
BorderData border = Config.Border(world.getName());
|
||||||
|
if (border == null) return null;
|
||||||
|
|
||||||
// set targetLoc only if not current player location; set returnLocationOnly to true to have new Location returned if they need to be moved to one, instead of directly handling it
|
if (border.insideBorder(loc.getX(), loc.getZ(), Config.ShapeRound()))
|
||||||
public static Location checkPlayer(Player player, Location targetLoc, boolean returnLocationOnly, boolean notify)
|
return null;
|
||||||
{
|
|
||||||
if (player == null || !player.isOnline()) return null;
|
|
||||||
|
|
||||||
Location loc = (targetLoc == null) ? player.getLocation().clone() : targetLoc;
|
// if player is in bypass list (from bypass command), allow them beyond border; also ignore players currently being handled already
|
||||||
if (loc == null) return null;
|
if (Config.isPlayerBypassing(player.getUniqueId()) || handlingPlayers.contains(player.getName().toLowerCase()))
|
||||||
|
return null;
|
||||||
|
|
||||||
World world = loc.getWorld();
|
// tag this player as being handled so we can't get stuck in a loop due to Bukkit currently sometimes repeatedly providing incorrect location through teleport event
|
||||||
if (world == null) return null;
|
handlingPlayers.add(player.getName().toLowerCase());
|
||||||
BorderData border = Config.Border(world.getName());
|
|
||||||
if (border == null) return null;
|
|
||||||
|
|
||||||
if (border.insideBorder(loc.getX(), loc.getZ(), Config.ShapeRound()))
|
Location newLoc = newLocation(player, loc, border, notify);
|
||||||
return null;
|
boolean handlingVehicle = false;
|
||||||
|
|
||||||
// if player is in bypass list (from bypass command), allow them beyond border; also ignore players currently being handled already
|
/*
|
||||||
if (Config.isPlayerBypassing(player.getUniqueId()) || handlingPlayers.contains(player.getName().toLowerCase()))
|
* since we need to forcibly eject players who are inside vehicles, that fires a teleport event (go figure) and
|
||||||
return null;
|
* so would effectively double trigger for us, so we need to handle it here to prevent sending two messages and
|
||||||
|
* two log entries etc.
|
||||||
|
* after players are ejected we can wait a few ticks (long enough for their client to receive new entity location)
|
||||||
|
* and then set them as passenger of the vehicle again
|
||||||
|
*/
|
||||||
|
if (player.isInsideVehicle()) {
|
||||||
|
Entity ride = player.getVehicle();
|
||||||
|
player.leaveVehicle();
|
||||||
|
if (ride != null) { // vehicles need to be offset vertically and have velocity stopped
|
||||||
|
double vertOffset = (ride instanceof LivingEntity) ? 0 : ride.getLocation().getY() - loc.getY();
|
||||||
|
Location rideLoc = newLoc.clone();
|
||||||
|
rideLoc.setY(newLoc.getY() + vertOffset);
|
||||||
|
if (Config.Debug())
|
||||||
|
Config.logWarn("Player was riding a \"" + ride.toString() + "\".");
|
||||||
|
|
||||||
// tag this player as being handled so we can't get stuck in a loop due to Bukkit currently sometimes repeatedly providing incorrect location through teleport event
|
ride.setVelocity(new Vector(0, 0, 0));
|
||||||
handlingPlayers.add(player.getName().toLowerCase());
|
ride.teleport(rideLoc, TeleportCause.PLUGIN);
|
||||||
|
|
||||||
Location newLoc = newLocation(player, loc, border, notify);
|
if (Config.RemountTicks() > 0) {
|
||||||
boolean handlingVehicle = false;
|
setPassengerDelayed(ride, player, player.getName(), Config.RemountTicks());
|
||||||
|
handlingVehicle = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
// check if player has something (a pet, maybe?) riding them; only possible through odd plugins.
|
||||||
* since we need to forcibly eject players who are inside vehicles, that fires a teleport event (go figure) and
|
// it can prevent all teleportation of the player completely, so it's very much not good and needs handling
|
||||||
* so would effectively double trigger for us, so we need to handle it here to prevent sending two messages and
|
List<Entity> passengers = player.getPassengers();
|
||||||
* two log entries etc.
|
if (!passengers.isEmpty()) {
|
||||||
* after players are ejected we can wait a few ticks (long enough for their client to receive new entity location)
|
player.eject();
|
||||||
* and then set them as passenger of the vehicle again
|
for (Entity rider : passengers) {
|
||||||
*/
|
rider.teleport(newLoc, TeleportCause.PLUGIN);
|
||||||
if (player.isInsideVehicle())
|
if (Config.Debug())
|
||||||
{
|
Config.logWarn("Player had a passenger riding on them: " + rider.getType());
|
||||||
Entity ride = player.getVehicle();
|
}
|
||||||
player.leaveVehicle();
|
player.sendMessage("Your passenger" + ((passengers.size() > 1) ? "s have" : " has") + " been ejected.");
|
||||||
if (ride != null)
|
}
|
||||||
{ // vehicles need to be offset vertically and have velocity stopped
|
|
||||||
double vertOffset = (ride instanceof LivingEntity) ? 0 : ride.getLocation().getY() - loc.getY();
|
|
||||||
Location rideLoc = newLoc.clone();
|
|
||||||
rideLoc.setY(newLoc.getY() + vertOffset);
|
|
||||||
if (Config.Debug())
|
|
||||||
Config.logWarn("Player was riding a \"" + ride.toString() + "\".");
|
|
||||||
|
|
||||||
ride.setVelocity(new Vector(0, 0, 0));
|
// give some particle and sound effects where the player was beyond the border, if "whoosh effect" is enabled
|
||||||
ride.teleport(rideLoc, TeleportCause.PLUGIN);
|
Config.showWhooshEffect(loc);
|
||||||
|
|
||||||
if (Config.RemountTicks() > 0)
|
if (!returnLocationOnly)
|
||||||
{
|
player.teleport(newLoc, TeleportCause.PLUGIN);
|
||||||
setPassengerDelayed(ride, player, player.getName(), Config.RemountTicks());
|
|
||||||
handlingVehicle = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if player has something (a pet, maybe?) riding them; only possible through odd plugins.
|
if (!handlingVehicle)
|
||||||
// it can prevent all teleportation of the player completely, so it's very much not good and needs handling
|
handlingPlayers.remove(player.getName().toLowerCase());
|
||||||
List<Entity> passengers = player.getPassengers();
|
|
||||||
if (!passengers.isEmpty())
|
|
||||||
{
|
|
||||||
player.eject();
|
|
||||||
for (Entity rider : passengers)
|
|
||||||
{
|
|
||||||
rider.teleport(newLoc, TeleportCause.PLUGIN);
|
|
||||||
if (Config.Debug())
|
|
||||||
Config.logWarn("Player had a passenger riding on them: " + rider.getType());
|
|
||||||
}
|
|
||||||
player.sendMessage("Your passenger" + ((passengers.size() > 1) ? "s have" : " has") + " been ejected.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// give some particle and sound effects where the player was beyond the border, if "whoosh effect" is enabled
|
if (returnLocationOnly)
|
||||||
Config.showWhooshEffect(loc);
|
return newLoc;
|
||||||
|
|
||||||
if (!returnLocationOnly)
|
return null;
|
||||||
player.teleport(newLoc, TeleportCause.PLUGIN);
|
}
|
||||||
|
|
||||||
if (!handlingVehicle)
|
public static Location checkPlayer(Player player, Location targetLoc, boolean returnLocationOnly) {
|
||||||
handlingPlayers.remove(player.getName().toLowerCase());
|
return checkPlayer(player, targetLoc, returnLocationOnly, true);
|
||||||
|
}
|
||||||
|
|
||||||
if (returnLocationOnly)
|
private static Location newLocation(Player player, Location loc, BorderData border, boolean notify) {
|
||||||
return newLoc;
|
if (Config.Debug()) {
|
||||||
|
Config.logWarn((notify ? "Border crossing" : "Check was run") + " in \"" + loc.getWorld().getName() + "\". Border " + border.toString());
|
||||||
|
Config.logWarn("Player position X: " + Config.coord.format(loc.getX()) + " Y: " + Config.coord.format(loc.getY()) + " Z: " + Config.coord.format(loc.getZ()));
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
Location newLoc = border.correctedPosition(loc, Config.ShapeRound(), player.isFlying());
|
||||||
}
|
|
||||||
public static Location checkPlayer(Player player, Location targetLoc, boolean returnLocationOnly)
|
|
||||||
{
|
|
||||||
return checkPlayer(player, targetLoc, returnLocationOnly, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Location newLocation(Player player, Location loc, BorderData border, boolean notify)
|
// it's remotely possible (such as in the Nether) a suitable location isn't available, in which case...
|
||||||
{
|
if (newLoc == null) {
|
||||||
if (Config.Debug())
|
if (Config.Debug())
|
||||||
{
|
Config.logWarn("Target new location unviable, using spawn or killing player.");
|
||||||
Config.logWarn((notify ? "Border crossing" : "Check was run") + " in \"" + loc.getWorld().getName() + "\". Border " + border.toString());
|
if (Config.getIfPlayerKill()) {
|
||||||
Config.logWarn("Player position X: " + Config.coord.format(loc.getX()) + " Y: " + Config.coord.format(loc.getY()) + " Z: " + Config.coord.format(loc.getZ()));
|
player.setHealth(0.0D);
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
newLoc = player.getWorld().getSpawnLocation();
|
||||||
|
}
|
||||||
|
|
||||||
Location newLoc = border.correctedPosition(loc, Config.ShapeRound(), player.isFlying());
|
if (Config.Debug())
|
||||||
|
Config.logWarn("New position in world \"" + newLoc.getWorld().getName() + "\" at X: " + Config.coord.format(newLoc.getX()) + " Y: " + Config.coord.format(newLoc.getY()) + " Z: " + Config.coord.format(newLoc.getZ()));
|
||||||
|
|
||||||
// it's remotely possible (such as in the Nether) a suitable location isn't available, in which case...
|
if (notify)
|
||||||
if (newLoc == null)
|
player.sendMessage(Config.Message());
|
||||||
{
|
|
||||||
if (Config.Debug())
|
|
||||||
Config.logWarn("Target new location unviable, using spawn or killing player.");
|
|
||||||
if (Config.getIfPlayerKill())
|
|
||||||
{
|
|
||||||
player.setHealth(0.0D);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
newLoc = player.getWorld().getSpawnLocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config.Debug())
|
return newLoc;
|
||||||
Config.logWarn("New position in world \"" + newLoc.getWorld().getName() + "\" at X: " + Config.coord.format(newLoc.getX()) + " Y: " + Config.coord.format(newLoc.getY()) + " Z: " + Config.coord.format(newLoc.getZ()));
|
}
|
||||||
|
|
||||||
if (notify)
|
private static void setPassengerDelayed(final Entity vehicle, final Player player, final String playerName, long delay) {
|
||||||
player.sendMessage(Config.Message());
|
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(WorldBorder.plugin, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
handlingPlayers.remove(playerName.toLowerCase());
|
||||||
|
if (vehicle == null || player == null)
|
||||||
|
return;
|
||||||
|
|
||||||
return newLoc;
|
vehicle.addPassenger(player);
|
||||||
}
|
}
|
||||||
|
}, delay);
|
||||||
|
}
|
||||||
|
|
||||||
private static void setPassengerDelayed(final Entity vehicle, final Player player, final String playerName, long delay)
|
@Override
|
||||||
{
|
public void run() {
|
||||||
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(WorldBorder.plugin, new Runnable()
|
// if knockback is set to 0, simply return
|
||||||
{
|
if (Config.KnockBack() == 0.0)
|
||||||
@Override
|
return;
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
handlingPlayers.remove(playerName.toLowerCase());
|
|
||||||
if (vehicle == null || player == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
vehicle.addPassenger(player);
|
Collection<Player> players = ImmutableList.copyOf(Bukkit.getServer().getOnlinePlayers());
|
||||||
}
|
|
||||||
}, delay);
|
for (Player player : players) {
|
||||||
}
|
checkPlayer(player, null, false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,493 +1,461 @@
|
|||||||
package com.wimbli.WorldBorder;
|
package com.wimbli.WorldBorder;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
|
||||||
|
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
public class BorderData
|
|
||||||
{
|
|
||||||
// the main data interacted with
|
|
||||||
private double x = 0;
|
|
||||||
private double z = 0;
|
|
||||||
private int radiusX = 0;
|
|
||||||
private int radiusZ = 0;
|
|
||||||
private Boolean shapeRound = null;
|
|
||||||
private boolean wrapping = false;
|
|
||||||
|
|
||||||
// some extra data kept handy for faster border checks
|
|
||||||
private double maxX;
|
|
||||||
private double minX;
|
|
||||||
private double maxZ;
|
|
||||||
private double minZ;
|
|
||||||
private double radiusXSquared;
|
|
||||||
private double radiusZSquared;
|
|
||||||
private double DefiniteRectangleX;
|
|
||||||
private double DefiniteRectangleZ;
|
|
||||||
private double radiusSquaredQuotient;
|
|
||||||
|
|
||||||
public BorderData(double x, double z, int radiusX, int radiusZ, Boolean shapeRound, boolean wrap)
|
|
||||||
{
|
|
||||||
setData(x, z, radiusX, radiusZ, shapeRound, wrap);
|
|
||||||
}
|
|
||||||
public BorderData(double x, double z, int radiusX, int radiusZ)
|
|
||||||
{
|
|
||||||
setData(x, z, radiusX, radiusZ, null);
|
|
||||||
}
|
|
||||||
public BorderData(double x, double z, int radiusX, int radiusZ, Boolean shapeRound)
|
|
||||||
{
|
|
||||||
setData(x, z, radiusX, radiusZ, shapeRound);
|
|
||||||
}
|
|
||||||
public BorderData(double x, double z, int radius)
|
|
||||||
{
|
|
||||||
setData(x, z, radius, null);
|
|
||||||
}
|
|
||||||
public BorderData(double x, double z, int radius, Boolean shapeRound)
|
|
||||||
{
|
|
||||||
setData(x, z, radius, shapeRound);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void setData(double x, double z, int radiusX, int radiusZ, Boolean shapeRound, boolean wrap)
|
|
||||||
{
|
|
||||||
this.x = x;
|
|
||||||
this.z = z;
|
|
||||||
this.shapeRound = shapeRound;
|
|
||||||
this.wrapping = wrap;
|
|
||||||
this.setRadiusX(radiusX);
|
|
||||||
this.setRadiusZ(radiusZ);
|
|
||||||
}
|
|
||||||
public final void setData(double x, double z, int radiusX, int radiusZ, Boolean shapeRound)
|
|
||||||
{
|
|
||||||
setData(x, z, radiusX, radiusZ, shapeRound, false);
|
|
||||||
}
|
|
||||||
public final void setData(double x, double z, int radius, Boolean shapeRound)
|
|
||||||
{
|
|
||||||
setData(x, z, radius, radius, shapeRound, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BorderData copy()
|
|
||||||
{
|
|
||||||
return new BorderData(x, z, radiusX, radiusZ, shapeRound, wrapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getX()
|
|
||||||
{
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
public void setX(double x)
|
|
||||||
{
|
|
||||||
this.x = x;
|
|
||||||
this.maxX = x + radiusX;
|
|
||||||
this.minX = x - radiusX;
|
|
||||||
}
|
|
||||||
public double getZ()
|
|
||||||
{
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
public void setZ(double z)
|
|
||||||
{
|
|
||||||
this.z = z;
|
|
||||||
this.maxZ = z + radiusZ;
|
|
||||||
this.minZ = z - radiusZ;
|
|
||||||
}
|
|
||||||
public int getRadiusX()
|
|
||||||
{
|
|
||||||
return radiusX;
|
|
||||||
}
|
|
||||||
public int getRadiusZ()
|
|
||||||
{
|
|
||||||
return radiusZ;
|
|
||||||
}
|
|
||||||
public void setRadiusX(int radiusX)
|
|
||||||
{
|
|
||||||
this.radiusX = radiusX;
|
|
||||||
this.maxX = x + radiusX;
|
|
||||||
this.minX = x - radiusX;
|
|
||||||
this.radiusXSquared = (double)radiusX * (double)radiusX;
|
|
||||||
this.radiusSquaredQuotient = this.radiusXSquared / this.radiusZSquared;
|
|
||||||
this.DefiniteRectangleX = Math.sqrt(.5 * this.radiusXSquared);
|
|
||||||
}
|
|
||||||
public void setRadiusZ(int radiusZ)
|
|
||||||
{
|
|
||||||
this.radiusZ = radiusZ;
|
|
||||||
this.maxZ = z + radiusZ;
|
|
||||||
this.minZ = z - radiusZ;
|
|
||||||
this.radiusZSquared = (double)radiusZ * (double)radiusZ;
|
|
||||||
this.radiusSquaredQuotient = this.radiusXSquared / this.radiusZSquared;
|
|
||||||
this.DefiniteRectangleZ = Math.sqrt(.5 * this.radiusZSquared);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// backwards-compatible methods from before elliptical/rectangular shapes were supported
|
public class BorderData {
|
||||||
/**
|
//these material IDs are acceptable for places to teleport player; breathable blocks and water
|
||||||
* @deprecated Replaced by {@link #getRadiusX()} and {@link #getRadiusZ()};
|
public static final EnumSet<Material> safeOpenBlocks = EnumSet.noneOf(Material.class);
|
||||||
* this method now returns an average of those two values and is thus imprecise
|
//these material IDs are ones we don't want to drop the player onto, like cactus or lava or fire or activated Ender portal
|
||||||
*/
|
public static final EnumSet<Material> painfulBlocks = EnumSet.noneOf(Material.class);
|
||||||
public int getRadius()
|
private static final int limBot = 0;
|
||||||
{
|
|
||||||
return (radiusX + radiusZ) / 2; // average radius; not great, but probably best for backwards compatibility
|
static {
|
||||||
}
|
safeOpenBlocks.add(Material.AIR);
|
||||||
public void setRadius(int radius)
|
safeOpenBlocks.add(Material.CAVE_AIR);
|
||||||
{
|
safeOpenBlocks.add(Material.OAK_SAPLING);
|
||||||
setRadiusX(radius);
|
safeOpenBlocks.add(Material.SPRUCE_SAPLING);
|
||||||
setRadiusZ(radius);
|
safeOpenBlocks.add(Material.BIRCH_SAPLING);
|
||||||
}
|
safeOpenBlocks.add(Material.JUNGLE_SAPLING);
|
||||||
|
safeOpenBlocks.add(Material.ACACIA_SAPLING);
|
||||||
|
safeOpenBlocks.add(Material.DARK_OAK_SAPLING);
|
||||||
|
safeOpenBlocks.add(Material.WATER);
|
||||||
|
safeOpenBlocks.add(Material.RAIL);
|
||||||
|
safeOpenBlocks.add(Material.POWERED_RAIL);
|
||||||
|
safeOpenBlocks.add(Material.DETECTOR_RAIL);
|
||||||
|
safeOpenBlocks.add(Material.ACTIVATOR_RAIL);
|
||||||
|
safeOpenBlocks.add(Material.COBWEB);
|
||||||
|
safeOpenBlocks.add(Material.GRASS);
|
||||||
|
safeOpenBlocks.add(Material.FERN);
|
||||||
|
safeOpenBlocks.add(Material.DEAD_BUSH);
|
||||||
|
safeOpenBlocks.add(Material.DANDELION);
|
||||||
|
safeOpenBlocks.add(Material.POPPY);
|
||||||
|
safeOpenBlocks.add(Material.BLUE_ORCHID);
|
||||||
|
safeOpenBlocks.add(Material.ALLIUM);
|
||||||
|
safeOpenBlocks.add(Material.AZURE_BLUET);
|
||||||
|
safeOpenBlocks.add(Material.RED_TULIP);
|
||||||
|
safeOpenBlocks.add(Material.ORANGE_TULIP);
|
||||||
|
safeOpenBlocks.add(Material.WHITE_TULIP);
|
||||||
|
safeOpenBlocks.add(Material.PINK_TULIP);
|
||||||
|
safeOpenBlocks.add(Material.OXEYE_DAISY);
|
||||||
|
safeOpenBlocks.add(Material.BROWN_MUSHROOM);
|
||||||
|
safeOpenBlocks.add(Material.RED_MUSHROOM);
|
||||||
|
safeOpenBlocks.add(Material.TORCH);
|
||||||
|
safeOpenBlocks.add(Material.WALL_TORCH);
|
||||||
|
safeOpenBlocks.add(Material.REDSTONE_WIRE);
|
||||||
|
safeOpenBlocks.add(Material.WHEAT);
|
||||||
|
safeOpenBlocks.add(Material.LADDER);
|
||||||
|
safeOpenBlocks.add(Material.LEVER);
|
||||||
|
safeOpenBlocks.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE);
|
||||||
|
safeOpenBlocks.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE);
|
||||||
|
safeOpenBlocks.add(Material.STONE_PRESSURE_PLATE);
|
||||||
|
safeOpenBlocks.add(Material.OAK_PRESSURE_PLATE);
|
||||||
|
safeOpenBlocks.add(Material.SPRUCE_PRESSURE_PLATE);
|
||||||
|
safeOpenBlocks.add(Material.BIRCH_PRESSURE_PLATE);
|
||||||
|
safeOpenBlocks.add(Material.JUNGLE_PRESSURE_PLATE);
|
||||||
|
safeOpenBlocks.add(Material.ACACIA_PRESSURE_PLATE);
|
||||||
|
safeOpenBlocks.add(Material.DARK_OAK_PRESSURE_PLATE);
|
||||||
|
safeOpenBlocks.add(Material.REDSTONE_TORCH);
|
||||||
|
safeOpenBlocks.add(Material.REDSTONE_WALL_TORCH);
|
||||||
|
safeOpenBlocks.add(Material.STONE_BUTTON);
|
||||||
|
safeOpenBlocks.add(Material.SNOW);
|
||||||
|
safeOpenBlocks.add(Material.SUGAR_CANE);
|
||||||
|
safeOpenBlocks.add(Material.REPEATER);
|
||||||
|
safeOpenBlocks.add(Material.COMPARATOR);
|
||||||
|
safeOpenBlocks.add(Material.OAK_TRAPDOOR);
|
||||||
|
safeOpenBlocks.add(Material.SPRUCE_TRAPDOOR);
|
||||||
|
safeOpenBlocks.add(Material.BIRCH_TRAPDOOR);
|
||||||
|
safeOpenBlocks.add(Material.JUNGLE_TRAPDOOR);
|
||||||
|
safeOpenBlocks.add(Material.ACACIA_TRAPDOOR);
|
||||||
|
safeOpenBlocks.add(Material.DARK_OAK_TRAPDOOR);
|
||||||
|
safeOpenBlocks.add(Material.MELON_STEM);
|
||||||
|
safeOpenBlocks.add(Material.ATTACHED_MELON_STEM);
|
||||||
|
safeOpenBlocks.add(Material.PUMPKIN_STEM);
|
||||||
|
safeOpenBlocks.add(Material.ATTACHED_PUMPKIN_STEM);
|
||||||
|
safeOpenBlocks.add(Material.VINE);
|
||||||
|
safeOpenBlocks.add(Material.NETHER_WART);
|
||||||
|
safeOpenBlocks.add(Material.TRIPWIRE);
|
||||||
|
safeOpenBlocks.add(Material.TRIPWIRE_HOOK);
|
||||||
|
safeOpenBlocks.add(Material.CARROTS);
|
||||||
|
safeOpenBlocks.add(Material.POTATOES);
|
||||||
|
safeOpenBlocks.add(Material.OAK_BUTTON);
|
||||||
|
safeOpenBlocks.add(Material.SPRUCE_BUTTON);
|
||||||
|
safeOpenBlocks.add(Material.BIRCH_BUTTON);
|
||||||
|
safeOpenBlocks.add(Material.JUNGLE_BUTTON);
|
||||||
|
safeOpenBlocks.add(Material.ACACIA_BUTTON);
|
||||||
|
safeOpenBlocks.add(Material.DARK_OAK_BUTTON);
|
||||||
|
safeOpenBlocks.add(Material.SUNFLOWER);
|
||||||
|
safeOpenBlocks.add(Material.LILAC);
|
||||||
|
safeOpenBlocks.add(Material.ROSE_BUSH);
|
||||||
|
safeOpenBlocks.add(Material.PEONY);
|
||||||
|
safeOpenBlocks.add(Material.TALL_GRASS);
|
||||||
|
safeOpenBlocks.add(Material.LARGE_FERN);
|
||||||
|
safeOpenBlocks.add(Material.BEETROOTS);
|
||||||
|
try { // signs in 1.14 can be different wood types
|
||||||
|
safeOpenBlocks.add(Material.ACACIA_SIGN);
|
||||||
|
safeOpenBlocks.add(Material.ACACIA_WALL_SIGN);
|
||||||
|
safeOpenBlocks.add(Material.BIRCH_SIGN);
|
||||||
|
safeOpenBlocks.add(Material.BIRCH_WALL_SIGN);
|
||||||
|
safeOpenBlocks.add(Material.DARK_OAK_SIGN);
|
||||||
|
safeOpenBlocks.add(Material.DARK_OAK_WALL_SIGN);
|
||||||
|
safeOpenBlocks.add(Material.JUNGLE_SIGN);
|
||||||
|
safeOpenBlocks.add(Material.JUNGLE_WALL_SIGN);
|
||||||
|
safeOpenBlocks.add(Material.OAK_SIGN);
|
||||||
|
safeOpenBlocks.add(Material.OAK_WALL_SIGN);
|
||||||
|
safeOpenBlocks.add(Material.SPRUCE_SIGN);
|
||||||
|
safeOpenBlocks.add(Material.SPRUCE_WALL_SIGN);
|
||||||
|
} catch (NoSuchFieldError ex) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
painfulBlocks.add(Material.LAVA);
|
||||||
|
painfulBlocks.add(Material.FIRE);
|
||||||
|
painfulBlocks.add(Material.CACTUS);
|
||||||
|
painfulBlocks.add(Material.END_PORTAL);
|
||||||
|
painfulBlocks.add(Material.MAGMA_BLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the main data interacted with
|
||||||
|
private double x = 0;
|
||||||
|
private double z = 0;
|
||||||
|
private int radiusX = 0;
|
||||||
|
private int radiusZ = 0;
|
||||||
|
private Boolean shapeRound = null;
|
||||||
|
private boolean wrapping = false;
|
||||||
|
// some extra data kept handy for faster border checks
|
||||||
|
private double maxX;
|
||||||
|
private double minX;
|
||||||
|
private double maxZ;
|
||||||
|
private double minZ;
|
||||||
|
private double radiusXSquared;
|
||||||
|
private double radiusZSquared;
|
||||||
|
private double DefiniteRectangleX;
|
||||||
|
private double DefiniteRectangleZ;
|
||||||
|
private double radiusSquaredQuotient;
|
||||||
|
|
||||||
|
public BorderData(double x, double z, int radiusX, int radiusZ, Boolean shapeRound, boolean wrap) {
|
||||||
|
setData(x, z, radiusX, radiusZ, shapeRound, wrap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BorderData(double x, double z, int radiusX, int radiusZ) {
|
||||||
|
setData(x, z, radiusX, radiusZ, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BorderData(double x, double z, int radiusX, int radiusZ, Boolean shapeRound) {
|
||||||
|
setData(x, z, radiusX, radiusZ, shapeRound);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BorderData(double x, double z, int radius) {
|
||||||
|
setData(x, z, radius, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BorderData(double x, double z, int radius, Boolean shapeRound) {
|
||||||
|
setData(x, z, radius, shapeRound);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setData(double x, double z, int radiusX, int radiusZ, Boolean shapeRound, boolean wrap) {
|
||||||
|
this.x = x;
|
||||||
|
this.z = z;
|
||||||
|
this.shapeRound = shapeRound;
|
||||||
|
this.wrapping = wrap;
|
||||||
|
this.setRadiusX(radiusX);
|
||||||
|
this.setRadiusZ(radiusZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setData(double x, double z, int radiusX, int radiusZ, Boolean shapeRound) {
|
||||||
|
setData(x, z, radiusX, radiusZ, shapeRound, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setData(double x, double z, int radius, Boolean shapeRound) {
|
||||||
|
setData(x, z, radius, radius, shapeRound, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BorderData copy() {
|
||||||
|
return new BorderData(x, z, radiusX, radiusZ, shapeRound, wrapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setX(double x) {
|
||||||
|
this.x = x;
|
||||||
|
this.maxX = x + radiusX;
|
||||||
|
this.minX = x - radiusX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getZ() {
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public Boolean getShape()
|
// backwards-compatible methods from before elliptical/rectangular shapes were supported
|
||||||
{
|
|
||||||
return shapeRound;
|
public void setZ(double z) {
|
||||||
}
|
this.z = z;
|
||||||
public void setShape(Boolean shapeRound)
|
this.maxZ = z + radiusZ;
|
||||||
{
|
this.minZ = z - radiusZ;
|
||||||
this.shapeRound = shapeRound;
|
}
|
||||||
}
|
|
||||||
|
public int getRadiusX() {
|
||||||
|
return radiusX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRadiusX(int radiusX) {
|
||||||
|
this.radiusX = radiusX;
|
||||||
|
this.maxX = x + radiusX;
|
||||||
|
this.minX = x - radiusX;
|
||||||
|
this.radiusXSquared = (double) radiusX * (double) radiusX;
|
||||||
|
this.radiusSquaredQuotient = this.radiusXSquared / this.radiusZSquared;
|
||||||
|
this.DefiniteRectangleX = Math.sqrt(.5 * this.radiusXSquared);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRadiusZ() {
|
||||||
|
return radiusZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRadiusZ(int radiusZ) {
|
||||||
|
this.radiusZ = radiusZ;
|
||||||
|
this.maxZ = z + radiusZ;
|
||||||
|
this.minZ = z - radiusZ;
|
||||||
|
this.radiusZSquared = (double) radiusZ * (double) radiusZ;
|
||||||
|
this.radiusSquaredQuotient = this.radiusXSquared / this.radiusZSquared;
|
||||||
|
this.DefiniteRectangleZ = Math.sqrt(.5 * this.radiusZSquared);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Replaced by {@link #getRadiusX()} and {@link #getRadiusZ()};
|
||||||
|
* this method now returns an average of those two values and is thus imprecise
|
||||||
|
*/
|
||||||
|
public int getRadius() {
|
||||||
|
return (radiusX + radiusZ) / 2; // average radius; not great, but probably best for backwards compatibility
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRadius(int radius) {
|
||||||
|
setRadiusX(radius);
|
||||||
|
setRadiusZ(radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getShape() {
|
||||||
|
return shapeRound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShape(Boolean shapeRound) {
|
||||||
|
this.shapeRound = shapeRound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getWrapping() {
|
||||||
|
return wrapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWrapping(boolean wrap) {
|
||||||
|
this.wrapping = wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "radius " + ((radiusX == radiusZ) ? radiusX : radiusX + "x" + radiusZ) + " at X: " + Config.coord.format(x) + " Z: " + Config.coord.format(z) + (shapeRound != null ? (" (shape override: " + Config.ShapeName(shapeRound.booleanValue()) + ")") : "") + (wrapping ? (" (wrapping)") : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// This algorithm of course needs to be fast, since it will be run very frequently
|
||||||
|
public boolean insideBorder(double xLoc, double zLoc, boolean round) {
|
||||||
|
// if this border has a shape override set, use it
|
||||||
|
if (shapeRound != null)
|
||||||
|
round = shapeRound.booleanValue();
|
||||||
|
|
||||||
|
// square border
|
||||||
|
if (!round)
|
||||||
|
return !(xLoc < minX || xLoc > maxX || zLoc < minZ || zLoc > maxZ);
|
||||||
|
|
||||||
|
// round border
|
||||||
|
else {
|
||||||
|
// elegant round border checking algorithm is from rBorder by Reil with almost no changes, all credit to him for it
|
||||||
|
double X = Math.abs(x - xLoc);
|
||||||
|
double Z = Math.abs(z - zLoc);
|
||||||
|
|
||||||
|
if (X < DefiniteRectangleX && Z < DefiniteRectangleZ)
|
||||||
|
return true; // Definitely inside
|
||||||
|
else if (X >= radiusX || Z >= radiusZ)
|
||||||
|
return false; // Definitely outside
|
||||||
|
else if (X * X + Z * Z * radiusSquaredQuotient < radiusXSquared)
|
||||||
|
return true; // After further calculation, inside
|
||||||
|
else
|
||||||
|
return false; // Apparently outside, then
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean insideBorder(double xLoc, double zLoc) {
|
||||||
|
return insideBorder(xLoc, zLoc, Config.ShapeRound());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean insideBorder(Location loc) {
|
||||||
|
return insideBorder(loc.getX(), loc.getZ(), Config.ShapeRound());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean insideBorder(CoordXZ coord, boolean round) {
|
||||||
|
return insideBorder(coord.x, coord.z, round);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean insideBorder(CoordXZ coord) {
|
||||||
|
return insideBorder(coord.x, coord.z, Config.ShapeRound());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location correctedPosition(Location loc, boolean round, boolean flying) {
|
||||||
|
// if this border has a shape override set, use it
|
||||||
|
if (shapeRound != null)
|
||||||
|
round = shapeRound.booleanValue();
|
||||||
|
|
||||||
|
double xLoc = loc.getX();
|
||||||
|
double zLoc = loc.getZ();
|
||||||
|
double yLoc = loc.getY();
|
||||||
|
|
||||||
|
// square border
|
||||||
|
if (!round) {
|
||||||
|
if (wrapping) {
|
||||||
|
if (xLoc <= minX)
|
||||||
|
xLoc = maxX - Config.KnockBack();
|
||||||
|
else if (xLoc >= maxX)
|
||||||
|
xLoc = minX + Config.KnockBack();
|
||||||
|
if (zLoc <= minZ)
|
||||||
|
zLoc = maxZ - Config.KnockBack();
|
||||||
|
else if (zLoc >= maxZ)
|
||||||
|
zLoc = minZ + Config.KnockBack();
|
||||||
|
} else {
|
||||||
|
if (xLoc <= minX)
|
||||||
|
xLoc = minX + Config.KnockBack();
|
||||||
|
else if (xLoc >= maxX)
|
||||||
|
xLoc = maxX - Config.KnockBack();
|
||||||
|
if (zLoc <= minZ)
|
||||||
|
zLoc = minZ + Config.KnockBack();
|
||||||
|
else if (zLoc >= maxZ)
|
||||||
|
zLoc = maxZ - Config.KnockBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// round border
|
||||||
|
else {
|
||||||
|
// algorithm originally from: http://stackoverflow.com/questions/300871/best-way-to-find-a-point-on-a-circle-closest-to-a-given-point
|
||||||
|
// modified by Lang Lukas to support elliptical border shape
|
||||||
|
|
||||||
|
//Transform the ellipse to a circle with radius 1 (we need to transform the point the same way)
|
||||||
|
double dX = xLoc - x;
|
||||||
|
double dZ = zLoc - z;
|
||||||
|
double dU = Math.sqrt(dX * dX + dZ * dZ); //distance of the untransformed point from the center
|
||||||
|
double dT = Math.sqrt(dX * dX / radiusXSquared + dZ * dZ / radiusZSquared); //distance of the transformed point from the center
|
||||||
|
double f = (1 / dT - Config.KnockBack() / dU); //"correction" factor for the distances
|
||||||
|
if (wrapping) {
|
||||||
|
xLoc = x - dX * f;
|
||||||
|
zLoc = z - dZ * f;
|
||||||
|
} else {
|
||||||
|
xLoc = x + dX * f;
|
||||||
|
zLoc = z + dZ * f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ixLoc = Location.locToBlock(xLoc);
|
||||||
|
int izLoc = Location.locToBlock(zLoc);
|
||||||
|
|
||||||
|
// Make sure the chunk we're checking in is actually loaded
|
||||||
|
Chunk tChunk = loc.getWorld().getChunkAt(CoordXZ.blockToChunk(ixLoc), CoordXZ.blockToChunk(izLoc));
|
||||||
|
if (!tChunk.isLoaded())
|
||||||
|
tChunk.load();
|
||||||
|
|
||||||
|
yLoc = getSafeY(loc.getWorld(), ixLoc, Location.locToBlock(yLoc), izLoc, flying);
|
||||||
|
if (yLoc == -1)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new Location(loc.getWorld(), Math.floor(xLoc) + 0.5, yLoc, Math.floor(zLoc) + 0.5, loc.getYaw(), loc.getPitch());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location correctedPosition(Location loc, boolean round) {
|
||||||
|
return correctedPosition(loc, round, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location correctedPosition(Location loc) {
|
||||||
|
return correctedPosition(loc, Config.ShapeRound(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if a particular spot consists of 2 breathable blocks over something relatively solid
|
||||||
|
private boolean isSafeSpot(World world, int X, int Y, int Z, boolean flying) {
|
||||||
|
boolean safe = safeOpenBlocks.contains(world.getBlockAt(X, Y, Z).getType()) // target block open and safe
|
||||||
|
&& safeOpenBlocks.contains(world.getBlockAt(X, Y + 1, Z).getType()); // above target block open and safe
|
||||||
|
if (!safe || flying)
|
||||||
|
return safe;
|
||||||
|
|
||||||
|
Material below = world.getBlockAt(X, Y - 1, Z).getType();
|
||||||
|
return (safe
|
||||||
|
&& (!safeOpenBlocks.contains(below) || below == Material.WATER) // below target block not open/breathable (so presumably solid), or is water
|
||||||
|
&& !painfulBlocks.contains(below) // below target block not painful
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// find closest safe Y position from the starting position
|
||||||
|
private double getSafeY(World world, int X, int Y, int Z, boolean flying) {
|
||||||
|
// artificial height limit of 127 added for Nether worlds since CraftBukkit still incorrectly returns 255 for their max height, leading to players sent to the "roof" of the Nether
|
||||||
|
final boolean isNether = world.getEnvironment() == World.Environment.NETHER;
|
||||||
|
int limTop = isNether ? 125 : world.getMaxHeight() - 2;
|
||||||
|
final int highestBlockBoundary = Math.min(world.getHighestBlockYAt(X, Z) + 1, limTop);
|
||||||
|
|
||||||
|
// if Y is larger than the world can be and user can fly, return Y - Unless we are in the Nether, we might not want players on the roof
|
||||||
|
if (flying && Y > limTop && !isNether)
|
||||||
|
return (double) Y;
|
||||||
|
|
||||||
|
// make sure Y values are within the boundaries of the world.
|
||||||
|
if (Y > limTop) {
|
||||||
|
if (isNether)
|
||||||
|
Y = limTop; // because of the roof, the nether can not rely on highestBlockBoundary, so limTop has to be used
|
||||||
|
else {
|
||||||
|
if (flying)
|
||||||
|
Y = limTop;
|
||||||
|
else
|
||||||
|
Y = highestBlockBoundary; // there will never be a save block to stand on for Y values > highestBlockBoundary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Y < limBot)
|
||||||
|
Y = limBot;
|
||||||
|
|
||||||
|
// for non Nether worlds we don't need to check upwards to the world-limit, it is enough to check up to the highestBlockBoundary, unless player is flying
|
||||||
|
if (!isNether && !flying)
|
||||||
|
limTop = highestBlockBoundary;
|
||||||
|
// Expanding Y search method adapted from Acru's code in the Nether plugin
|
||||||
|
|
||||||
|
for (int y1 = Y, y2 = Y; (y1 > limBot) || (y2 < limTop); y1--, y2++) {
|
||||||
|
// Look below.
|
||||||
|
if (y1 > limBot) {
|
||||||
|
if (isSafeSpot(world, X, y1, Z, flying))
|
||||||
|
return (double) y1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look above.
|
||||||
|
if (y2 < limTop && y2 != y1) {
|
||||||
|
if (isSafeSpot(world, X, y2, Z, flying))
|
||||||
|
return (double) y2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1.0; // no safe Y location?!?!? Must be a rare spot in a Nether world or something
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean getWrapping()
|
@Override
|
||||||
{
|
public boolean equals(Object obj) {
|
||||||
return wrapping;
|
if (this == obj)
|
||||||
}
|
return true;
|
||||||
public void setWrapping(boolean wrap)
|
else if (obj == null || obj.getClass() != this.getClass())
|
||||||
{
|
return false;
|
||||||
this.wrapping = wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
BorderData test = (BorderData) obj;
|
||||||
|
return test.x == this.x && test.z == this.z && test.radiusX == this.radiusX && test.radiusZ == this.radiusZ;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public int hashCode() {
|
||||||
{
|
return (((int) (this.x * 10) << 4) + (int) this.z + (this.radiusX << 2) + (this.radiusZ << 3));
|
||||||
return "radius " + ((radiusX == radiusZ) ? radiusX : radiusX + "x" + radiusZ) + " at X: " + Config.coord.format(x) + " Z: " + Config.coord.format(z) + (shapeRound != null ? (" (shape override: " + Config.ShapeName(shapeRound.booleanValue()) + ")") : "") + (wrapping ? (" (wrapping)") : "");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// This algorithm of course needs to be fast, since it will be run very frequently
|
|
||||||
public boolean insideBorder(double xLoc, double zLoc, boolean round)
|
|
||||||
{
|
|
||||||
// if this border has a shape override set, use it
|
|
||||||
if (shapeRound != null)
|
|
||||||
round = shapeRound.booleanValue();
|
|
||||||
|
|
||||||
// square border
|
|
||||||
if (!round)
|
|
||||||
return !(xLoc < minX || xLoc > maxX || zLoc < minZ || zLoc > maxZ);
|
|
||||||
|
|
||||||
// round border
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// elegant round border checking algorithm is from rBorder by Reil with almost no changes, all credit to him for it
|
|
||||||
double X = Math.abs(x - xLoc);
|
|
||||||
double Z = Math.abs(z - zLoc);
|
|
||||||
|
|
||||||
if (X < DefiniteRectangleX && Z < DefiniteRectangleZ)
|
|
||||||
return true; // Definitely inside
|
|
||||||
else if (X >= radiusX || Z >= radiusZ)
|
|
||||||
return false; // Definitely outside
|
|
||||||
else if (X * X + Z * Z * radiusSquaredQuotient < radiusXSquared)
|
|
||||||
return true; // After further calculation, inside
|
|
||||||
else
|
|
||||||
return false; // Apparently outside, then
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public boolean insideBorder(double xLoc, double zLoc)
|
|
||||||
{
|
|
||||||
return insideBorder(xLoc, zLoc, Config.ShapeRound());
|
|
||||||
}
|
|
||||||
public boolean insideBorder(Location loc)
|
|
||||||
{
|
|
||||||
return insideBorder(loc.getX(), loc.getZ(), Config.ShapeRound());
|
|
||||||
}
|
|
||||||
public boolean insideBorder(CoordXZ coord, boolean round)
|
|
||||||
{
|
|
||||||
return insideBorder(coord.x, coord.z, round);
|
|
||||||
}
|
|
||||||
public boolean insideBorder(CoordXZ coord)
|
|
||||||
{
|
|
||||||
return insideBorder(coord.x, coord.z, Config.ShapeRound());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Location correctedPosition(Location loc, boolean round, boolean flying)
|
|
||||||
{
|
|
||||||
// if this border has a shape override set, use it
|
|
||||||
if (shapeRound != null)
|
|
||||||
round = shapeRound.booleanValue();
|
|
||||||
|
|
||||||
double xLoc = loc.getX();
|
|
||||||
double zLoc = loc.getZ();
|
|
||||||
double yLoc = loc.getY();
|
|
||||||
|
|
||||||
// square border
|
|
||||||
if (!round)
|
|
||||||
{
|
|
||||||
if (wrapping)
|
|
||||||
{
|
|
||||||
if (xLoc <= minX)
|
|
||||||
xLoc = maxX - Config.KnockBack();
|
|
||||||
else if (xLoc >= maxX)
|
|
||||||
xLoc = minX + Config.KnockBack();
|
|
||||||
if (zLoc <= minZ)
|
|
||||||
zLoc = maxZ - Config.KnockBack();
|
|
||||||
else if (zLoc >= maxZ)
|
|
||||||
zLoc = minZ + Config.KnockBack();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (xLoc <= minX)
|
|
||||||
xLoc = minX + Config.KnockBack();
|
|
||||||
else if (xLoc >= maxX)
|
|
||||||
xLoc = maxX - Config.KnockBack();
|
|
||||||
if (zLoc <= minZ)
|
|
||||||
zLoc = minZ + Config.KnockBack();
|
|
||||||
else if (zLoc >= maxZ)
|
|
||||||
zLoc = maxZ - Config.KnockBack();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// round border
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// algorithm originally from: http://stackoverflow.com/questions/300871/best-way-to-find-a-point-on-a-circle-closest-to-a-given-point
|
|
||||||
// modified by Lang Lukas to support elliptical border shape
|
|
||||||
|
|
||||||
//Transform the ellipse to a circle with radius 1 (we need to transform the point the same way)
|
|
||||||
double dX = xLoc - x;
|
|
||||||
double dZ = zLoc - z;
|
|
||||||
double dU = Math.sqrt(dX *dX + dZ * dZ); //distance of the untransformed point from the center
|
|
||||||
double dT = Math.sqrt(dX *dX / radiusXSquared + dZ * dZ / radiusZSquared); //distance of the transformed point from the center
|
|
||||||
double f = (1 / dT - Config.KnockBack() / dU); //"correction" factor for the distances
|
|
||||||
if (wrapping)
|
|
||||||
{
|
|
||||||
xLoc = x - dX * f;
|
|
||||||
zLoc = z - dZ * f;
|
|
||||||
} else {
|
|
||||||
xLoc = x + dX * f;
|
|
||||||
zLoc = z + dZ * f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int ixLoc = Location.locToBlock(xLoc);
|
|
||||||
int izLoc = Location.locToBlock(zLoc);
|
|
||||||
|
|
||||||
// Make sure the chunk we're checking in is actually loaded
|
|
||||||
Chunk tChunk = loc.getWorld().getChunkAt(CoordXZ.blockToChunk(ixLoc), CoordXZ.blockToChunk(izLoc));
|
|
||||||
if (!tChunk.isLoaded())
|
|
||||||
tChunk.load();
|
|
||||||
|
|
||||||
yLoc = getSafeY(loc.getWorld(), ixLoc, Location.locToBlock(yLoc), izLoc, flying);
|
|
||||||
if (yLoc == -1)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return new Location(loc.getWorld(), Math.floor(xLoc) + 0.5, yLoc, Math.floor(zLoc) + 0.5, loc.getYaw(), loc.getPitch());
|
|
||||||
}
|
|
||||||
public Location correctedPosition(Location loc, boolean round)
|
|
||||||
{
|
|
||||||
return correctedPosition(loc, round, false);
|
|
||||||
}
|
|
||||||
public Location correctedPosition(Location loc)
|
|
||||||
{
|
|
||||||
return correctedPosition(loc, Config.ShapeRound(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
//these material IDs are acceptable for places to teleport player; breathable blocks and water
|
|
||||||
public static final EnumSet<Material> safeOpenBlocks = EnumSet.noneOf(Material.class);
|
|
||||||
static
|
|
||||||
{
|
|
||||||
safeOpenBlocks.add(Material.AIR);
|
|
||||||
safeOpenBlocks.add(Material.CAVE_AIR);
|
|
||||||
safeOpenBlocks.add(Material.OAK_SAPLING);
|
|
||||||
safeOpenBlocks.add(Material.SPRUCE_SAPLING);
|
|
||||||
safeOpenBlocks.add(Material.BIRCH_SAPLING);
|
|
||||||
safeOpenBlocks.add(Material.JUNGLE_SAPLING);
|
|
||||||
safeOpenBlocks.add(Material.ACACIA_SAPLING);
|
|
||||||
safeOpenBlocks.add(Material.DARK_OAK_SAPLING);
|
|
||||||
safeOpenBlocks.add(Material.WATER);
|
|
||||||
safeOpenBlocks.add(Material.RAIL);
|
|
||||||
safeOpenBlocks.add(Material.POWERED_RAIL);
|
|
||||||
safeOpenBlocks.add(Material.DETECTOR_RAIL);
|
|
||||||
safeOpenBlocks.add(Material.ACTIVATOR_RAIL);
|
|
||||||
safeOpenBlocks.add(Material.COBWEB);
|
|
||||||
safeOpenBlocks.add(Material.GRASS);
|
|
||||||
safeOpenBlocks.add(Material.FERN);
|
|
||||||
safeOpenBlocks.add(Material.DEAD_BUSH);
|
|
||||||
safeOpenBlocks.add(Material.DANDELION);
|
|
||||||
safeOpenBlocks.add(Material.POPPY);
|
|
||||||
safeOpenBlocks.add(Material.BLUE_ORCHID);
|
|
||||||
safeOpenBlocks.add(Material.ALLIUM);
|
|
||||||
safeOpenBlocks.add(Material.AZURE_BLUET);
|
|
||||||
safeOpenBlocks.add(Material.RED_TULIP);
|
|
||||||
safeOpenBlocks.add(Material.ORANGE_TULIP);
|
|
||||||
safeOpenBlocks.add(Material.WHITE_TULIP);
|
|
||||||
safeOpenBlocks.add(Material.PINK_TULIP);
|
|
||||||
safeOpenBlocks.add(Material.OXEYE_DAISY);
|
|
||||||
safeOpenBlocks.add(Material.BROWN_MUSHROOM);
|
|
||||||
safeOpenBlocks.add(Material.RED_MUSHROOM);
|
|
||||||
safeOpenBlocks.add(Material.TORCH);
|
|
||||||
safeOpenBlocks.add(Material.WALL_TORCH);
|
|
||||||
safeOpenBlocks.add(Material.REDSTONE_WIRE);
|
|
||||||
safeOpenBlocks.add(Material.WHEAT);
|
|
||||||
safeOpenBlocks.add(Material.LADDER);
|
|
||||||
safeOpenBlocks.add(Material.LEVER);
|
|
||||||
safeOpenBlocks.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE);
|
|
||||||
safeOpenBlocks.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE);
|
|
||||||
safeOpenBlocks.add(Material.STONE_PRESSURE_PLATE);
|
|
||||||
safeOpenBlocks.add(Material.OAK_PRESSURE_PLATE);
|
|
||||||
safeOpenBlocks.add(Material.SPRUCE_PRESSURE_PLATE);
|
|
||||||
safeOpenBlocks.add(Material.BIRCH_PRESSURE_PLATE);
|
|
||||||
safeOpenBlocks.add(Material.JUNGLE_PRESSURE_PLATE);
|
|
||||||
safeOpenBlocks.add(Material.ACACIA_PRESSURE_PLATE);
|
|
||||||
safeOpenBlocks.add(Material.DARK_OAK_PRESSURE_PLATE);
|
|
||||||
safeOpenBlocks.add(Material.REDSTONE_TORCH);
|
|
||||||
safeOpenBlocks.add(Material.REDSTONE_WALL_TORCH);
|
|
||||||
safeOpenBlocks.add(Material.STONE_BUTTON);
|
|
||||||
safeOpenBlocks.add(Material.SNOW);
|
|
||||||
safeOpenBlocks.add(Material.SUGAR_CANE);
|
|
||||||
safeOpenBlocks.add(Material.REPEATER);
|
|
||||||
safeOpenBlocks.add(Material.COMPARATOR);
|
|
||||||
safeOpenBlocks.add(Material.OAK_TRAPDOOR);
|
|
||||||
safeOpenBlocks.add(Material.SPRUCE_TRAPDOOR);
|
|
||||||
safeOpenBlocks.add(Material.BIRCH_TRAPDOOR);
|
|
||||||
safeOpenBlocks.add(Material.JUNGLE_TRAPDOOR);
|
|
||||||
safeOpenBlocks.add(Material.ACACIA_TRAPDOOR);
|
|
||||||
safeOpenBlocks.add(Material.DARK_OAK_TRAPDOOR);
|
|
||||||
safeOpenBlocks.add(Material.MELON_STEM);
|
|
||||||
safeOpenBlocks.add(Material.ATTACHED_MELON_STEM);
|
|
||||||
safeOpenBlocks.add(Material.PUMPKIN_STEM);
|
|
||||||
safeOpenBlocks.add(Material.ATTACHED_PUMPKIN_STEM);
|
|
||||||
safeOpenBlocks.add(Material.VINE);
|
|
||||||
safeOpenBlocks.add(Material.NETHER_WART);
|
|
||||||
safeOpenBlocks.add(Material.TRIPWIRE);
|
|
||||||
safeOpenBlocks.add(Material.TRIPWIRE_HOOK);
|
|
||||||
safeOpenBlocks.add(Material.CARROTS);
|
|
||||||
safeOpenBlocks.add(Material.POTATOES);
|
|
||||||
safeOpenBlocks.add(Material.OAK_BUTTON);
|
|
||||||
safeOpenBlocks.add(Material.SPRUCE_BUTTON);
|
|
||||||
safeOpenBlocks.add(Material.BIRCH_BUTTON);
|
|
||||||
safeOpenBlocks.add(Material.JUNGLE_BUTTON);
|
|
||||||
safeOpenBlocks.add(Material.ACACIA_BUTTON);
|
|
||||||
safeOpenBlocks.add(Material.DARK_OAK_BUTTON);
|
|
||||||
safeOpenBlocks.add(Material.SUNFLOWER);
|
|
||||||
safeOpenBlocks.add(Material.LILAC);
|
|
||||||
safeOpenBlocks.add(Material.ROSE_BUSH);
|
|
||||||
safeOpenBlocks.add(Material.PEONY);
|
|
||||||
safeOpenBlocks.add(Material.TALL_GRASS);
|
|
||||||
safeOpenBlocks.add(Material.LARGE_FERN);
|
|
||||||
safeOpenBlocks.add(Material.BEETROOTS);
|
|
||||||
try
|
|
||||||
{ // signs in 1.14 can be different wood types
|
|
||||||
safeOpenBlocks.add(Material.ACACIA_SIGN);
|
|
||||||
safeOpenBlocks.add(Material.ACACIA_WALL_SIGN);
|
|
||||||
safeOpenBlocks.add(Material.BIRCH_SIGN);
|
|
||||||
safeOpenBlocks.add(Material.BIRCH_WALL_SIGN);
|
|
||||||
safeOpenBlocks.add(Material.DARK_OAK_SIGN);
|
|
||||||
safeOpenBlocks.add(Material.DARK_OAK_WALL_SIGN);
|
|
||||||
safeOpenBlocks.add(Material.JUNGLE_SIGN);
|
|
||||||
safeOpenBlocks.add(Material.JUNGLE_WALL_SIGN);
|
|
||||||
safeOpenBlocks.add(Material.OAK_SIGN);
|
|
||||||
safeOpenBlocks.add(Material.OAK_WALL_SIGN);
|
|
||||||
safeOpenBlocks.add(Material.SPRUCE_SIGN);
|
|
||||||
safeOpenBlocks.add(Material.SPRUCE_WALL_SIGN);
|
|
||||||
}
|
|
||||||
catch (NoSuchFieldError ex) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
//these material IDs are ones we don't want to drop the player onto, like cactus or lava or fire or activated Ender portal
|
|
||||||
public static final EnumSet<Material> painfulBlocks = EnumSet.noneOf(Material.class);
|
|
||||||
static
|
|
||||||
{
|
|
||||||
painfulBlocks.add(Material.LAVA);
|
|
||||||
painfulBlocks.add(Material.FIRE);
|
|
||||||
painfulBlocks.add(Material.CACTUS);
|
|
||||||
painfulBlocks.add(Material.END_PORTAL);
|
|
||||||
painfulBlocks.add(Material.MAGMA_BLOCK);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if a particular spot consists of 2 breathable blocks over something relatively solid
|
|
||||||
private boolean isSafeSpot(World world, int X, int Y, int Z, boolean flying)
|
|
||||||
{
|
|
||||||
boolean safe = safeOpenBlocks.contains(world.getBlockAt(X, Y, Z).getType()) // target block open and safe
|
|
||||||
&& safeOpenBlocks.contains(world.getBlockAt(X, Y + 1, Z).getType()); // above target block open and safe
|
|
||||||
if (!safe || flying)
|
|
||||||
return safe;
|
|
||||||
|
|
||||||
Material below = world.getBlockAt(X, Y - 1, Z).getType();
|
|
||||||
return (safe
|
|
||||||
&& (!safeOpenBlocks.contains(below) || below == Material.WATER) // below target block not open/breathable (so presumably solid), or is water
|
|
||||||
&& !painfulBlocks.contains(below) // below target block not painful
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int limBot = 0;
|
|
||||||
|
|
||||||
// find closest safe Y position from the starting position
|
|
||||||
private double getSafeY(World world, int X, int Y, int Z, boolean flying)
|
|
||||||
{
|
|
||||||
// artificial height limit of 127 added for Nether worlds since CraftBukkit still incorrectly returns 255 for their max height, leading to players sent to the "roof" of the Nether
|
|
||||||
final boolean isNether = world.getEnvironment() == World.Environment.NETHER;
|
|
||||||
int limTop = isNether ? 125 : world.getMaxHeight() - 2;
|
|
||||||
final int highestBlockBoundary = Math.min(world.getHighestBlockYAt(X, Z) + 1, limTop);
|
|
||||||
|
|
||||||
// if Y is larger than the world can be and user can fly, return Y - Unless we are in the Nether, we might not want players on the roof
|
|
||||||
if (flying && Y > limTop && !isNether)
|
|
||||||
return (double) Y;
|
|
||||||
|
|
||||||
// make sure Y values are within the boundaries of the world.
|
|
||||||
if (Y > limTop)
|
|
||||||
{
|
|
||||||
if (isNether)
|
|
||||||
Y = limTop; // because of the roof, the nether can not rely on highestBlockBoundary, so limTop has to be used
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (flying)
|
|
||||||
Y = limTop;
|
|
||||||
else
|
|
||||||
Y = highestBlockBoundary; // there will never be a save block to stand on for Y values > highestBlockBoundary
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Y < limBot)
|
|
||||||
Y = limBot;
|
|
||||||
|
|
||||||
// for non Nether worlds we don't need to check upwards to the world-limit, it is enough to check up to the highestBlockBoundary, unless player is flying
|
|
||||||
if (!isNether && !flying)
|
|
||||||
limTop = highestBlockBoundary;
|
|
||||||
// Expanding Y search method adapted from Acru's code in the Nether plugin
|
|
||||||
|
|
||||||
for(int y1 = Y, y2 = Y; (y1 > limBot) || (y2 < limTop); y1--, y2++){
|
|
||||||
// Look below.
|
|
||||||
if(y1 > limBot)
|
|
||||||
{
|
|
||||||
if (isSafeSpot(world, X, y1, Z, flying))
|
|
||||||
return (double)y1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look above.
|
|
||||||
if(y2 < limTop && y2 != y1)
|
|
||||||
{
|
|
||||||
if (isSafeSpot(world, X, y2, Z, flying))
|
|
||||||
return (double)y2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1.0; // no safe Y location?!?!? Must be a rare spot in a Nether world or something
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj)
|
|
||||||
{
|
|
||||||
if (this == obj)
|
|
||||||
return true;
|
|
||||||
else if (obj == null || obj.getClass() != this.getClass())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
BorderData test = (BorderData)obj;
|
|
||||||
return test.x == this.x && test.z == this.z && test.radiusX == this.radiusX && test.radiusZ == this.radiusZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return (((int)(this.x * 10) << 4) + (int)this.z + (this.radiusX << 2) + (this.radiusZ << 3));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2,58 +2,54 @@ package com.wimbli.WorldBorder;
|
|||||||
|
|
||||||
|
|
||||||
// simple storage class for chunk x/z values
|
// simple storage class for chunk x/z values
|
||||||
public class CoordXZ
|
public class CoordXZ {
|
||||||
{
|
public int x, z;
|
||||||
public int x, z;
|
|
||||||
public CoordXZ(int x, int z)
|
|
||||||
{
|
|
||||||
this.x = x;
|
|
||||||
this.z = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
// transform values between block, chunk, and region
|
public CoordXZ(int x, int z) {
|
||||||
// bit-shifting is used because it's mucho rapido
|
this.x = x;
|
||||||
public static int blockToChunk(int blockVal)
|
this.z = z;
|
||||||
{ // 1 chunk is 16x16 blocks
|
}
|
||||||
return blockVal >> 4; // ">>4" == "/16"
|
|
||||||
}
|
// transform values between block, chunk, and region
|
||||||
public static int blockToRegion(int blockVal)
|
// bit-shifting is used because it's mucho rapido
|
||||||
{ // 1 region is 512x512 blocks
|
public static int blockToChunk(int blockVal) { // 1 chunk is 16x16 blocks
|
||||||
return blockVal >> 9; // ">>9" == "/512"
|
return blockVal >> 4; // ">>4" == "/16"
|
||||||
}
|
}
|
||||||
public static int chunkToRegion(int chunkVal)
|
|
||||||
{ // 1 region is 32x32 chunks
|
public static int blockToRegion(int blockVal) { // 1 region is 512x512 blocks
|
||||||
return chunkVal >> 5; // ">>5" == "/32"
|
return blockVal >> 9; // ">>9" == "/512"
|
||||||
}
|
}
|
||||||
public static int chunkToBlock(int chunkVal)
|
|
||||||
{
|
public static int chunkToRegion(int chunkVal) { // 1 region is 32x32 chunks
|
||||||
return chunkVal << 4; // "<<4" == "*16"
|
return chunkVal >> 5; // ">>5" == "/32"
|
||||||
}
|
}
|
||||||
public static int regionToBlock(int regionVal)
|
|
||||||
{
|
public static int chunkToBlock(int chunkVal) {
|
||||||
return regionVal << 9; // "<<9" == "*512"
|
return chunkVal << 4; // "<<4" == "*16"
|
||||||
}
|
}
|
||||||
public static int regionToChunk(int regionVal)
|
|
||||||
{
|
public static int regionToBlock(int regionVal) {
|
||||||
return regionVal << 5; // "<<5" == "*32"
|
return regionVal << 9; // "<<9" == "*512"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int regionToChunk(int regionVal) {
|
||||||
|
return regionVal << 5; // "<<5" == "*32"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj)
|
public boolean equals(Object obj) {
|
||||||
{
|
if (this == obj)
|
||||||
if (this == obj)
|
return true;
|
||||||
return true;
|
else if (obj == null || obj.getClass() != this.getClass())
|
||||||
else if (obj == null || obj.getClass() != this.getClass())
|
return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
CoordXZ test = (CoordXZ)obj;
|
CoordXZ test = (CoordXZ) obj;
|
||||||
return test.x == this.x && test.z == this.z;
|
return test.x == this.x && test.z == this.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode()
|
public int hashCode() {
|
||||||
{
|
return (this.x << 9) + this.z;
|
||||||
return (this.x << 9) + this.z;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,251 +1,217 @@
|
|||||||
package com.wimbli.WorldBorder;
|
package com.wimbli.WorldBorder;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.dynmap.DynmapAPI;
|
import org.dynmap.DynmapAPI;
|
||||||
import org.dynmap.markers.AreaMarker;
|
import org.dynmap.markers.AreaMarker;
|
||||||
import org.dynmap.markers.CircleMarker;
|
import org.dynmap.markers.CircleMarker;
|
||||||
import org.dynmap.markers.MarkerAPI;
|
import org.dynmap.markers.MarkerAPI;
|
||||||
import org.dynmap.markers.MarkerSet;
|
import org.dynmap.markers.MarkerSet;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
public class DynMapFeatures
|
import java.util.List;
|
||||||
{
|
import java.util.Map;
|
||||||
private static DynmapAPI api;
|
import java.util.Map.Entry;
|
||||||
private static MarkerAPI markApi;
|
|
||||||
private static MarkerSet markSet;
|
|
||||||
private static int lineWeight = 3;
|
|
||||||
private static double lineOpacity = 1.0;
|
|
||||||
private static int lineColor = 0xFF0000;
|
|
||||||
|
|
||||||
// Whether re-rendering functionality is available
|
|
||||||
public static boolean renderEnabled()
|
|
||||||
{
|
|
||||||
return api != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Whether circular border markers are available
|
|
||||||
public static boolean borderEnabled()
|
|
||||||
{
|
|
||||||
return markApi != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setup()
|
|
||||||
{
|
|
||||||
Plugin test = Bukkit.getServer().getPluginManager().getPlugin("dynmap");
|
|
||||||
if (test == null || !test.isEnabled()) return;
|
|
||||||
|
|
||||||
api = (DynmapAPI)test;
|
|
||||||
|
|
||||||
// make sure DynMap version is new enough to include circular markers
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Class.forName("org.dynmap.markers.CircleMarker");
|
|
||||||
|
|
||||||
// for version 0.35 of DynMap, CircleMarkers had just been introduced and were bugged (center position always 0,0)
|
|
||||||
if (api.getDynmapVersion().startsWith("0.35-"))
|
|
||||||
throw new ClassNotFoundException();
|
|
||||||
}
|
|
||||||
catch (ClassNotFoundException ex)
|
|
||||||
{
|
|
||||||
Config.logConfig("DynMap is available, but border display is currently disabled: you need DynMap v0.36 or newer.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (NullPointerException ex)
|
|
||||||
{
|
|
||||||
Config.logConfig("DynMap is present, but an NPE (type 1) was encountered while trying to integrate. Border display disabled.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
markApi = api.getMarkerAPI();
|
|
||||||
if (markApi == null) return;
|
|
||||||
}
|
|
||||||
catch (NullPointerException ex)
|
|
||||||
{
|
|
||||||
Config.logConfig("DynMap is present, but an NPE (type 2) was encountered while trying to integrate. Border display disabled.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// go ahead and show borders for all worlds
|
|
||||||
showAllBorders();
|
|
||||||
|
|
||||||
Config.logConfig("Successfully hooked into DynMap for the ability to display borders.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
public class DynMapFeatures {
|
||||||
* Re-rendering methods, used for updating trimmed chunks to show them as gone
|
private static DynmapAPI api;
|
||||||
* Sadly, not currently working. Might not even be possible to make it work.
|
private static MarkerAPI markApi;
|
||||||
*/
|
private static MarkerSet markSet;
|
||||||
|
private static int lineWeight = 3;
|
||||||
public static void renderRegion(String worldName, CoordXZ coord)
|
private static double lineOpacity = 1.0;
|
||||||
{
|
private static int lineColor = 0xFF0000;
|
||||||
if (!renderEnabled()) return;
|
|
||||||
|
|
||||||
World world = Bukkit.getWorld(worldName);
|
|
||||||
int y = (world != null) ? world.getMaxHeight() : 255;
|
|
||||||
int x = CoordXZ.regionToBlock(coord.x);
|
|
||||||
int z = CoordXZ.regionToBlock(coord.z);
|
|
||||||
api.triggerRenderOfVolume(worldName, x, 0, z, x+511, y, z+511);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void renderChunks(String worldName, List<CoordXZ> coords)
|
|
||||||
{
|
|
||||||
if (!renderEnabled()) return;
|
|
||||||
|
|
||||||
World world = Bukkit.getWorld(worldName);
|
|
||||||
int y = (world != null) ? world.getMaxHeight() : 255;
|
|
||||||
|
|
||||||
for (CoordXZ coord : coords)
|
|
||||||
{
|
|
||||||
renderChunk(worldName, coord, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void renderChunk(String worldName, CoordXZ coord, int maxY)
|
|
||||||
{
|
|
||||||
if (!renderEnabled()) return;
|
|
||||||
|
|
||||||
int x = CoordXZ.chunkToBlock(coord.x);
|
|
||||||
int z = CoordXZ.chunkToBlock(coord.z);
|
|
||||||
api.triggerRenderOfVolume(worldName, x, 0, z, x+15, maxY, z+15);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Methods for displaying our borders on DynMap's world maps
|
|
||||||
*/
|
|
||||||
|
|
||||||
private static Map<String, CircleMarker> roundBorders = new HashMap<String, CircleMarker>();
|
private static Map<String, CircleMarker> roundBorders = new HashMap<String, CircleMarker>();
|
||||||
private static Map<String, AreaMarker> squareBorders = new HashMap<String, AreaMarker>();
|
private static Map<String, AreaMarker> squareBorders = new HashMap<String, AreaMarker>();
|
||||||
|
|
||||||
public static void showAllBorders()
|
// Whether re-rendering functionality is available
|
||||||
{
|
public static boolean renderEnabled() {
|
||||||
if (!borderEnabled()) return;
|
return api != null;
|
||||||
|
}
|
||||||
|
|
||||||
// in case any borders are already shown
|
|
||||||
removeAllBorders();
|
|
||||||
|
|
||||||
if (!Config.DynmapBorderEnabled())
|
/*
|
||||||
{
|
* Re-rendering methods, used for updating trimmed chunks to show them as gone
|
||||||
// don't want to show the marker set in DynMap if our integration is disabled
|
* Sadly, not currently working. Might not even be possible to make it work.
|
||||||
if (markSet != null)
|
*/
|
||||||
markSet.deleteMarkerSet();
|
|
||||||
markSet = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure the marker set is initialized
|
// Whether circular border markers are available
|
||||||
markSet = markApi.getMarkerSet("worldborder.markerset");
|
public static boolean borderEnabled() {
|
||||||
if(markSet == null)
|
return markApi != null;
|
||||||
markSet = markApi.createMarkerSet("worldborder.markerset", "WorldBorder", null, false);
|
}
|
||||||
else
|
|
||||||
markSet.setMarkerSetLabel("WorldBorder");
|
|
||||||
markSet.setLayerPriority(Config.DynmapPriority());
|
|
||||||
markSet.setHideByDefault(Config.DynmapHideByDefault());
|
|
||||||
Map<String, BorderData> borders = Config.getBorders();
|
|
||||||
for(Entry<String, BorderData> stringBorderDataEntry : borders.entrySet())
|
|
||||||
{
|
|
||||||
String worldName = stringBorderDataEntry.getKey();
|
|
||||||
BorderData border = stringBorderDataEntry.getValue();
|
|
||||||
showBorder(worldName, border);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void showBorder(String worldName, BorderData border)
|
public static void setup() {
|
||||||
{
|
Plugin test = Bukkit.getServer().getPluginManager().getPlugin("dynmap");
|
||||||
if (!borderEnabled()) return;
|
if (test == null || !test.isEnabled()) return;
|
||||||
|
|
||||||
if (!Config.DynmapBorderEnabled()) return;
|
api = (DynmapAPI) test;
|
||||||
|
|
||||||
if ((border.getShape() == null) ? Config.ShapeRound() : border.getShape())
|
// make sure DynMap version is new enough to include circular markers
|
||||||
showRoundBorder(worldName, border);
|
try {
|
||||||
else
|
Class.forName("org.dynmap.markers.CircleMarker");
|
||||||
showSquareBorder(worldName, border);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void showRoundBorder(String worldName, BorderData border)
|
// for version 0.35 of DynMap, CircleMarkers had just been introduced and were bugged (center position always 0,0)
|
||||||
{
|
if (api.getDynmapVersion().startsWith("0.35-"))
|
||||||
if (squareBorders.containsKey(worldName))
|
throw new ClassNotFoundException();
|
||||||
removeBorder(worldName);
|
} catch (ClassNotFoundException ex) {
|
||||||
|
Config.logConfig("DynMap is available, but border display is currently disabled: you need DynMap v0.36 or newer.");
|
||||||
|
return;
|
||||||
|
} catch (NullPointerException ex) {
|
||||||
|
Config.logConfig("DynMap is present, but an NPE (type 1) was encountered while trying to integrate. Border display disabled.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
World world = Bukkit.getWorld(worldName);
|
try {
|
||||||
int y = (world != null) ? world.getMaxHeight() : 255;
|
markApi = api.getMarkerAPI();
|
||||||
|
if (markApi == null) return;
|
||||||
|
} catch (NullPointerException ex) {
|
||||||
|
Config.logConfig("DynMap is present, but an NPE (type 2) was encountered while trying to integrate. Border display disabled.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CircleMarker marker = roundBorders.get(worldName);
|
// go ahead and show borders for all worlds
|
||||||
if (marker == null)
|
showAllBorders();
|
||||||
{
|
|
||||||
marker = markSet.createCircleMarker("worldborder_"+worldName, Config.DynmapMessage(), false, worldName, border.getX(), y, border.getZ(), border.getRadiusX(), border.getRadiusZ(), true);
|
|
||||||
marker.setLineStyle(lineWeight, lineOpacity, lineColor);
|
|
||||||
marker.setFillStyle(0.0, 0x000000);
|
|
||||||
roundBorders.put(worldName, marker);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
marker.setCenter(worldName, border.getX(), y, border.getZ());
|
|
||||||
marker.setRadius(border.getRadiusX(), border.getRadiusZ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void showSquareBorder(String worldName, BorderData border)
|
Config.logConfig("Successfully hooked into DynMap for the ability to display borders.");
|
||||||
{
|
}
|
||||||
if (roundBorders.containsKey(worldName))
|
|
||||||
removeBorder(worldName);
|
|
||||||
|
|
||||||
// corners of the square border
|
public static void renderRegion(String worldName, CoordXZ coord) {
|
||||||
double[] xVals = {border.getX() - border.getRadiusX(), border.getX() + border.getRadiusX()};
|
if (!renderEnabled()) return;
|
||||||
double[] zVals = {border.getZ() - border.getRadiusZ(), border.getZ() + border.getRadiusZ()};
|
|
||||||
|
|
||||||
AreaMarker marker = squareBorders.get(worldName);
|
World world = Bukkit.getWorld(worldName);
|
||||||
if (marker == null)
|
int y = (world != null) ? world.getMaxHeight() : 255;
|
||||||
{
|
int x = CoordXZ.regionToBlock(coord.x);
|
||||||
marker = markSet.createAreaMarker("worldborder_"+worldName, Config.DynmapMessage(), false, worldName, xVals, zVals, true);
|
int z = CoordXZ.regionToBlock(coord.z);
|
||||||
marker.setLineStyle(3, 1.0, 0xFF0000);
|
api.triggerRenderOfVolume(worldName, x, 0, z, x + 511, y, z + 511);
|
||||||
marker.setFillStyle(0.0, 0x000000);
|
}
|
||||||
squareBorders.put(worldName, marker);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
marker.setCornerLocations(xVals, zVals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void removeAllBorders()
|
|
||||||
{
|
|
||||||
if (!borderEnabled()) return;
|
|
||||||
|
|
||||||
for(CircleMarker marker : roundBorders.values())
|
/*
|
||||||
{
|
* Methods for displaying our borders on DynMap's world maps
|
||||||
marker.deleteMarker();
|
*/
|
||||||
}
|
|
||||||
roundBorders.clear();
|
|
||||||
|
|
||||||
for(AreaMarker marker : squareBorders.values())
|
public static void renderChunks(String worldName, List<CoordXZ> coords) {
|
||||||
{
|
if (!renderEnabled()) return;
|
||||||
marker.deleteMarker();
|
|
||||||
}
|
|
||||||
squareBorders.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void removeBorder(String worldName)
|
World world = Bukkit.getWorld(worldName);
|
||||||
{
|
int y = (world != null) ? world.getMaxHeight() : 255;
|
||||||
if (!borderEnabled()) return;
|
|
||||||
|
|
||||||
CircleMarker marker = roundBorders.remove(worldName);
|
for (CoordXZ coord : coords) {
|
||||||
if (marker != null)
|
renderChunk(worldName, coord, y);
|
||||||
marker.deleteMarker();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AreaMarker marker2 = squareBorders.remove(worldName);
|
public static void renderChunk(String worldName, CoordXZ coord, int maxY) {
|
||||||
if (marker2 != null)
|
if (!renderEnabled()) return;
|
||||||
marker2.deleteMarker();
|
|
||||||
}
|
int x = CoordXZ.chunkToBlock(coord.x);
|
||||||
|
int z = CoordXZ.chunkToBlock(coord.z);
|
||||||
|
api.triggerRenderOfVolume(worldName, x, 0, z, x + 15, maxY, z + 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showAllBorders() {
|
||||||
|
if (!borderEnabled()) return;
|
||||||
|
|
||||||
|
// in case any borders are already shown
|
||||||
|
removeAllBorders();
|
||||||
|
|
||||||
|
if (!Config.DynmapBorderEnabled()) {
|
||||||
|
// don't want to show the marker set in DynMap if our integration is disabled
|
||||||
|
if (markSet != null)
|
||||||
|
markSet.deleteMarkerSet();
|
||||||
|
markSet = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure the marker set is initialized
|
||||||
|
markSet = markApi.getMarkerSet("worldborder.markerset");
|
||||||
|
if (markSet == null)
|
||||||
|
markSet = markApi.createMarkerSet("worldborder.markerset", "WorldBorder", null, false);
|
||||||
|
else
|
||||||
|
markSet.setMarkerSetLabel("WorldBorder");
|
||||||
|
markSet.setLayerPriority(Config.DynmapPriority());
|
||||||
|
markSet.setHideByDefault(Config.DynmapHideByDefault());
|
||||||
|
Map<String, BorderData> borders = Config.getBorders();
|
||||||
|
for (Entry<String, BorderData> stringBorderDataEntry : borders.entrySet()) {
|
||||||
|
String worldName = stringBorderDataEntry.getKey();
|
||||||
|
BorderData border = stringBorderDataEntry.getValue();
|
||||||
|
showBorder(worldName, border);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showBorder(String worldName, BorderData border) {
|
||||||
|
if (!borderEnabled()) return;
|
||||||
|
|
||||||
|
if (!Config.DynmapBorderEnabled()) return;
|
||||||
|
|
||||||
|
if ((border.getShape() == null) ? Config.ShapeRound() : border.getShape())
|
||||||
|
showRoundBorder(worldName, border);
|
||||||
|
else
|
||||||
|
showSquareBorder(worldName, border);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void showRoundBorder(String worldName, BorderData border) {
|
||||||
|
if (squareBorders.containsKey(worldName))
|
||||||
|
removeBorder(worldName);
|
||||||
|
|
||||||
|
World world = Bukkit.getWorld(worldName);
|
||||||
|
int y = (world != null) ? world.getMaxHeight() : 255;
|
||||||
|
|
||||||
|
CircleMarker marker = roundBorders.get(worldName);
|
||||||
|
if (marker == null) {
|
||||||
|
marker = markSet.createCircleMarker("worldborder_" + worldName, Config.DynmapMessage(), false, worldName, border.getX(), y, border.getZ(), border.getRadiusX(), border.getRadiusZ(), true);
|
||||||
|
marker.setLineStyle(lineWeight, lineOpacity, lineColor);
|
||||||
|
marker.setFillStyle(0.0, 0x000000);
|
||||||
|
roundBorders.put(worldName, marker);
|
||||||
|
} else {
|
||||||
|
marker.setCenter(worldName, border.getX(), y, border.getZ());
|
||||||
|
marker.setRadius(border.getRadiusX(), border.getRadiusZ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void showSquareBorder(String worldName, BorderData border) {
|
||||||
|
if (roundBorders.containsKey(worldName))
|
||||||
|
removeBorder(worldName);
|
||||||
|
|
||||||
|
// corners of the square border
|
||||||
|
double[] xVals = {border.getX() - border.getRadiusX(), border.getX() + border.getRadiusX()};
|
||||||
|
double[] zVals = {border.getZ() - border.getRadiusZ(), border.getZ() + border.getRadiusZ()};
|
||||||
|
|
||||||
|
AreaMarker marker = squareBorders.get(worldName);
|
||||||
|
if (marker == null) {
|
||||||
|
marker = markSet.createAreaMarker("worldborder_" + worldName, Config.DynmapMessage(), false, worldName, xVals, zVals, true);
|
||||||
|
marker.setLineStyle(3, 1.0, 0xFF0000);
|
||||||
|
marker.setFillStyle(0.0, 0x000000);
|
||||||
|
squareBorders.put(worldName, marker);
|
||||||
|
} else {
|
||||||
|
marker.setCornerLocations(xVals, zVals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeAllBorders() {
|
||||||
|
if (!borderEnabled()) return;
|
||||||
|
|
||||||
|
for (CircleMarker marker : roundBorders.values()) {
|
||||||
|
marker.deleteMarker();
|
||||||
|
}
|
||||||
|
roundBorders.clear();
|
||||||
|
|
||||||
|
for (AreaMarker marker : squareBorders.values()) {
|
||||||
|
marker.deleteMarker();
|
||||||
|
}
|
||||||
|
squareBorders.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeBorder(String worldName) {
|
||||||
|
if (!borderEnabled()) return;
|
||||||
|
|
||||||
|
CircleMarker marker = roundBorders.remove(worldName);
|
||||||
|
if (marker != null)
|
||||||
|
marker.deleteMarker();
|
||||||
|
|
||||||
|
AreaMarker marker2 = squareBorders.remove(worldName);
|
||||||
|
if (marker2 != null)
|
||||||
|
marker2.deleteMarker();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,42 +1,36 @@
|
|||||||
package com.wimbli.WorldBorder.Events;
|
package com.wimbli.WorldBorder.Events;
|
||||||
|
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.bukkit.World;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by timafh on 04.09.2015.
|
* Created by timafh on 04.09.2015.
|
||||||
*/
|
*/
|
||||||
public class WorldBorderFillFinishedEvent extends Event
|
public class WorldBorderFillFinishedEvent extends Event {
|
||||||
{
|
private static final HandlerList handlers = new HandlerList();
|
||||||
private static final HandlerList handlers = new HandlerList();
|
private World world;
|
||||||
private World world;
|
private long totalChunks;
|
||||||
private long totalChunks;
|
|
||||||
|
|
||||||
public WorldBorderFillFinishedEvent(World world, long totalChunks)
|
public WorldBorderFillFinishedEvent(World world, long totalChunks) {
|
||||||
{
|
this.world = world;
|
||||||
this.world = world;
|
this.totalChunks = totalChunks;
|
||||||
this.totalChunks = totalChunks;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public static HandlerList getHandlerList() {
|
||||||
public HandlerList getHandlers()
|
return handlers;
|
||||||
{
|
}
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HandlerList getHandlerList()
|
@Override
|
||||||
{
|
public HandlerList getHandlers() {
|
||||||
return handlers;
|
return handlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public World getWorld()
|
public World getWorld() {
|
||||||
{
|
return world;
|
||||||
return world;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public long getTotalChunks()
|
public long getTotalChunks() {
|
||||||
{
|
return totalChunks;
|
||||||
return totalChunks;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,36 +1,31 @@
|
|||||||
package com.wimbli.WorldBorder.Events;
|
package com.wimbli.WorldBorder.Events;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.WorldFillTask;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.WorldFillTask;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Maximvdw on 12.01.2016.
|
* Created by Maximvdw on 12.01.2016.
|
||||||
*/
|
*/
|
||||||
public class WorldBorderFillStartEvent extends Event
|
public class WorldBorderFillStartEvent extends Event {
|
||||||
{
|
private static final HandlerList handlers = new HandlerList();
|
||||||
private static final HandlerList handlers = new HandlerList();
|
private WorldFillTask fillTask;
|
||||||
private WorldFillTask fillTask;
|
|
||||||
|
|
||||||
public WorldBorderFillStartEvent(WorldFillTask worldFillTask)
|
public WorldBorderFillStartEvent(WorldFillTask worldFillTask) {
|
||||||
{
|
this.fillTask = worldFillTask;
|
||||||
this.fillTask = worldFillTask;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public static HandlerList getHandlerList() {
|
||||||
public HandlerList getHandlers()
|
return handlers;
|
||||||
{
|
}
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HandlerList getHandlerList()
|
@Override
|
||||||
{
|
public HandlerList getHandlers() {
|
||||||
return handlers;
|
return handlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorldFillTask getFillTask(){
|
public WorldFillTask getFillTask() {
|
||||||
return this.fillTask;
|
return this.fillTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,42 +1,36 @@
|
|||||||
package com.wimbli.WorldBorder.Events;
|
package com.wimbli.WorldBorder.Events;
|
||||||
|
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.bukkit.World;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by timafh on 04.09.2015.
|
* Created by timafh on 04.09.2015.
|
||||||
*/
|
*/
|
||||||
public class WorldBorderTrimFinishedEvent extends Event
|
public class WorldBorderTrimFinishedEvent extends Event {
|
||||||
{
|
private static final HandlerList handlers = new HandlerList();
|
||||||
private static final HandlerList handlers = new HandlerList();
|
private World world;
|
||||||
private World world;
|
private long totalChunks;
|
||||||
private long totalChunks;
|
|
||||||
|
|
||||||
public WorldBorderTrimFinishedEvent(World world, long totalChunks)
|
public WorldBorderTrimFinishedEvent(World world, long totalChunks) {
|
||||||
{
|
this.world = world;
|
||||||
this.world = world;
|
this.totalChunks = totalChunks;
|
||||||
this.totalChunks = totalChunks;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public static HandlerList getHandlerList() {
|
||||||
public HandlerList getHandlers()
|
return handlers;
|
||||||
{
|
}
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HandlerList getHandlerList()
|
@Override
|
||||||
{
|
public HandlerList getHandlers() {
|
||||||
return handlers;
|
return handlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public World getWorld()
|
public World getWorld() {
|
||||||
{
|
return world;
|
||||||
return world;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public long getTotalChunks()
|
public long getTotalChunks() {
|
||||||
{
|
return totalChunks;
|
||||||
return totalChunks;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,36 +1,31 @@
|
|||||||
package com.wimbli.WorldBorder.Events;
|
package com.wimbli.WorldBorder.Events;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.WorldTrimTask;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.WorldTrimTask;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Maximvdw on 12.01.2016.
|
* Created by Maximvdw on 12.01.2016.
|
||||||
*/
|
*/
|
||||||
public class WorldBorderTrimStartEvent extends Event
|
public class WorldBorderTrimStartEvent extends Event {
|
||||||
{
|
private static final HandlerList handlers = new HandlerList();
|
||||||
private static final HandlerList handlers = new HandlerList();
|
private WorldTrimTask trimTask;
|
||||||
private WorldTrimTask trimTask;
|
|
||||||
|
|
||||||
public WorldBorderTrimStartEvent(WorldTrimTask trimTask)
|
public WorldBorderTrimStartEvent(WorldTrimTask trimTask) {
|
||||||
{
|
this.trimTask = trimTask;
|
||||||
this.trimTask = trimTask;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public static HandlerList getHandlerList() {
|
||||||
public HandlerList getHandlers()
|
return handlers;
|
||||||
{
|
}
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HandlerList getHandlerList()
|
@Override
|
||||||
{
|
public HandlerList getHandlers() {
|
||||||
return handlers;
|
return handlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorldTrimTask getTrimTask(){
|
public WorldTrimTask getTrimTask() {
|
||||||
return this.trimTask;
|
return this.trimTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,27 +9,23 @@ import org.bukkit.event.Listener;
|
|||||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
|
|
||||||
|
|
||||||
public class MobSpawnListener implements Listener
|
public class MobSpawnListener implements Listener {
|
||||||
{
|
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
public void onCreatureSpawn(CreatureSpawnEvent event) {
|
||||||
public void onCreatureSpawn(CreatureSpawnEvent event)
|
Location loc = event.getEntity().getLocation();
|
||||||
{
|
if (loc == null) return;
|
||||||
Location loc = event.getEntity().getLocation();
|
|
||||||
if (loc == null) return;
|
|
||||||
|
|
||||||
World world = loc.getWorld();
|
World world = loc.getWorld();
|
||||||
if (world == null) return;
|
if (world == null) return;
|
||||||
BorderData border = Config.Border(world.getName());
|
BorderData border = Config.Border(world.getName());
|
||||||
if (border == null) return;
|
if (border == null) return;
|
||||||
|
|
||||||
if (!border.insideBorder(loc.getX(), loc.getZ(), Config.ShapeRound()))
|
if (!border.insideBorder(loc.getX(), loc.getZ(), Config.ShapeRound())) {
|
||||||
{
|
event.setCancelled(true);
|
||||||
event.setCancelled(true);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void unregister()
|
public void unregister() {
|
||||||
{
|
HandlerList.unregisterAll(this);
|
||||||
HandlerList.unregisterAll(this);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
package com.wimbli.WorldBorder.UUID;
|
package com.wimbli.WorldBorder.UUID;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
@ -16,134 +19,127 @@ import java.util.concurrent.ExecutorService;
|
|||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
|
|
||||||
|
|
||||||
public class UUIDFetcher {
|
public class UUIDFetcher {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Date when name changes were introduced
|
* Date when name changes were introduced
|
||||||
* @see UUIDFetcher#getUUIDAt(String, long)
|
*
|
||||||
*/
|
* @see UUIDFetcher#getUUIDAt(String, long)
|
||||||
public static final long FEBRUARY_2015 = 1422748800000L;
|
*/
|
||||||
|
public static final long FEBRUARY_2015 = 1422748800000L;
|
||||||
|
private static final String UUID_URL = "https://api.mojang.com/users/profiles/minecraft/%s?at=%d";
|
||||||
|
private static final String NAME_URL = "https://api.mojang.com/user/profiles/%s/names";
|
||||||
|
private static Gson gson = new GsonBuilder().registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create();
|
||||||
|
private static Map<String, UUID> uuidCache = new HashMap<String, UUID>();
|
||||||
|
private static Map<UUID, String> nameCache = new HashMap<UUID, String>();
|
||||||
|
|
||||||
|
private static ExecutorService pool = Executors.newCachedThreadPool();
|
||||||
|
|
||||||
private static Gson gson = new GsonBuilder().registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create();
|
private String name;
|
||||||
|
private UUID id;
|
||||||
|
|
||||||
private static final String UUID_URL = "https://api.mojang.com/users/profiles/minecraft/%s?at=%d";
|
/**
|
||||||
private static final String NAME_URL = "https://api.mojang.com/user/profiles/%s/names";
|
* Fetches the uuid asynchronously and passes it to the consumer
|
||||||
|
*
|
||||||
|
* @param name The name
|
||||||
|
* @param action Do what you want to do with the uuid her
|
||||||
|
*/
|
||||||
|
public static void getUUID(String name, Consumer<UUID> action) {
|
||||||
|
pool.execute(() -> action.accept(getUUID(name)));
|
||||||
|
}
|
||||||
|
|
||||||
private static Map<String, UUID> uuidCache = new HashMap<String, UUID>();
|
/**
|
||||||
private static Map<UUID, String> nameCache = new HashMap<UUID, String>();
|
* Fetches the uuid synchronously and returns it
|
||||||
|
*
|
||||||
|
* @param name The name
|
||||||
|
* @return The uuid
|
||||||
|
*/
|
||||||
|
public static UUID getUUID(String name) {
|
||||||
|
return getUUIDAt(name, System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
private static ExecutorService pool = Executors.newCachedThreadPool();
|
/**
|
||||||
|
* Fetches the uuid synchronously for a specified name and time and passes the result to the consumer
|
||||||
|
*
|
||||||
|
* @param name The name
|
||||||
|
* @param timestamp Time when the player had this name in milliseconds
|
||||||
|
* @param action Do what you want to do with the uuid her
|
||||||
|
*/
|
||||||
|
public static void getUUIDAt(String name, long timestamp, Consumer<UUID> action) {
|
||||||
|
pool.execute(() -> action.accept(getUUIDAt(name, timestamp)));
|
||||||
|
}
|
||||||
|
|
||||||
private String name;
|
/**
|
||||||
private UUID id;
|
* Fetches the uuid synchronously for a specified name and time
|
||||||
|
*
|
||||||
|
* @param name The name
|
||||||
|
* @param timestamp Time when the player had this name in milliseconds
|
||||||
|
* @see UUIDFetcher#FEBRUARY_2015
|
||||||
|
*/
|
||||||
|
public static UUID getUUIDAt(String name, long timestamp) {
|
||||||
|
name = name.toLowerCase();
|
||||||
|
if (uuidCache.containsKey(name)) {
|
||||||
|
return uuidCache.get(name);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) new URL(String.format(UUID_URL, name, timestamp / 1000)).openConnection();
|
||||||
|
connection.setReadTimeout(5000);
|
||||||
|
UUIDFetcher data = gson.fromJson(new BufferedReader(new InputStreamReader(connection.getInputStream())), UUIDFetcher.class);
|
||||||
|
|
||||||
/**
|
uuidCache.put(name, data.id);
|
||||||
* Fetches the uuid asynchronously and passes it to the consumer
|
nameCache.put(data.id, data.name);
|
||||||
*
|
|
||||||
* @param name The name
|
|
||||||
* @param action Do what you want to do with the uuid her
|
|
||||||
*/
|
|
||||||
public static void getUUID(String name, Consumer<UUID> action) {
|
|
||||||
pool.execute(() -> action.accept(getUUID(name)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
return data.id;
|
||||||
* Fetches the uuid synchronously and returns it
|
} catch (Exception e) {
|
||||||
*
|
e.printStackTrace();
|
||||||
* @param name The name
|
}
|
||||||
* @return The uuid
|
|
||||||
*/
|
|
||||||
public static UUID getUUID(String name) {
|
|
||||||
return getUUIDAt(name, System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
return null;
|
||||||
* Fetches the uuid synchronously for a specified name and time and passes the result to the consumer
|
}
|
||||||
*
|
|
||||||
* @param name The name
|
|
||||||
* @param timestamp Time when the player had this name in milliseconds
|
|
||||||
* @param action Do what you want to do with the uuid her
|
|
||||||
*/
|
|
||||||
public static void getUUIDAt(String name, long timestamp, Consumer<UUID> action) {
|
|
||||||
pool.execute(() -> action.accept(getUUIDAt(name, timestamp)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the uuid synchronously for a specified name and time
|
* Fetches the name asynchronously and passes it to the consumer
|
||||||
*
|
*
|
||||||
* @param name The name
|
* @param uuid The uuid
|
||||||
* @param timestamp Time when the player had this name in milliseconds
|
* @param action Do what you want to do with the name her
|
||||||
* @see UUIDFetcher#FEBRUARY_2015
|
*/
|
||||||
*/
|
public static void getName(UUID uuid, Consumer<String> action) {
|
||||||
public static UUID getUUIDAt(String name, long timestamp) {
|
pool.execute(() -> action.accept(getName(uuid)));
|
||||||
name = name.toLowerCase();
|
}
|
||||||
if (uuidCache.containsKey(name)) {
|
|
||||||
return uuidCache.get(name);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
HttpURLConnection connection = (HttpURLConnection) new URL(String.format(UUID_URL, name, timestamp/1000)).openConnection();
|
|
||||||
connection.setReadTimeout(5000);
|
|
||||||
UUIDFetcher data = gson.fromJson(new BufferedReader(new InputStreamReader(connection.getInputStream())), UUIDFetcher.class);
|
|
||||||
|
|
||||||
uuidCache.put(name, data.id);
|
/**
|
||||||
nameCache.put(data.id, data.name);
|
* Fetches the name synchronously and returns it
|
||||||
|
*
|
||||||
|
* @param uuid The uuid
|
||||||
|
* @return The name
|
||||||
|
*/
|
||||||
|
public static String getName(UUID uuid) {
|
||||||
|
if (nameCache.containsKey(uuid)) {
|
||||||
|
return nameCache.get(uuid);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) new URL(String.format(NAME_URL, UUIDTypeAdapter.fromUUID(uuid))).openConnection();
|
||||||
|
connection.setReadTimeout(5000);
|
||||||
|
UUIDFetcher[] nameHistory = gson.fromJson(new BufferedReader(new InputStreamReader(connection.getInputStream())), UUIDFetcher[].class);
|
||||||
|
UUIDFetcher currentNameData = nameHistory[nameHistory.length - 1];
|
||||||
|
|
||||||
return data.id;
|
uuidCache.put(currentNameData.name.toLowerCase(), uuid);
|
||||||
} catch (Exception e) {
|
nameCache.put(uuid, currentNameData.name);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return currentNameData.name;
|
||||||
}
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
return null;
|
||||||
* Fetches the name asynchronously and passes it to the consumer
|
}
|
||||||
*
|
|
||||||
* @param uuid The uuid
|
|
||||||
* @param action Do what you want to do with the name her
|
|
||||||
*/
|
|
||||||
public static void getName(UUID uuid, Consumer<String> action) {
|
|
||||||
pool.execute(() -> action.accept(getName(uuid)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public static Map<UUID, String> getNameList(ArrayList<UUID> uuids) {
|
||||||
* Fetches the name synchronously and returns it
|
Map<UUID, String> uuidStringMap = new HashMap<>();
|
||||||
*
|
for (UUID uuid : uuids) {
|
||||||
* @param uuid The uuid
|
uuidStringMap.put(uuid, getName(uuid));
|
||||||
* @return The name
|
}
|
||||||
*/
|
return uuidStringMap;
|
||||||
public static String getName(UUID uuid) {
|
}
|
||||||
if (nameCache.containsKey(uuid)) {
|
|
||||||
return nameCache.get(uuid);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
HttpURLConnection connection = (HttpURLConnection) new URL(String.format(NAME_URL, UUIDTypeAdapter.fromUUID(uuid))).openConnection();
|
|
||||||
connection.setReadTimeout(5000);
|
|
||||||
UUIDFetcher[] nameHistory = gson.fromJson(new BufferedReader(new InputStreamReader(connection.getInputStream())), UUIDFetcher[].class);
|
|
||||||
UUIDFetcher currentNameData = nameHistory[nameHistory.length - 1];
|
|
||||||
|
|
||||||
uuidCache.put(currentNameData.name.toLowerCase(), uuid);
|
|
||||||
nameCache.put(uuid, currentNameData.name);
|
|
||||||
|
|
||||||
return currentNameData.name;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map<UUID, String> getNameList(ArrayList<UUID> uuids) {
|
|
||||||
Map<UUID, String> uuidStringMap = new HashMap<>();
|
|
||||||
for (UUID uuid: uuids)
|
|
||||||
{
|
|
||||||
uuidStringMap.put(uuid, getName(uuid));
|
|
||||||
}
|
|
||||||
return uuidStringMap;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,29 +4,29 @@
|
|||||||
|
|
||||||
package com.wimbli.WorldBorder.UUID;
|
package com.wimbli.WorldBorder.UUID;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import com.google.gson.TypeAdapter;
|
import com.google.gson.TypeAdapter;
|
||||||
import com.google.gson.stream.JsonReader;
|
import com.google.gson.stream.JsonReader;
|
||||||
import com.google.gson.stream.JsonWriter;
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
||||||
public class UUIDTypeAdapter extends TypeAdapter<UUID> {
|
public class UUIDTypeAdapter extends TypeAdapter<UUID> {
|
||||||
public void write(JsonWriter out, UUID value) throws IOException {
|
public static String fromUUID(UUID value) {
|
||||||
out.value(fromUUID(value));
|
return value.toString().replace("-", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID read(JsonReader in) throws IOException {
|
public static UUID fromString(String input) {
|
||||||
return fromString(in.nextString());
|
return UUID.fromString(input.replaceFirst(
|
||||||
}
|
"(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5"));
|
||||||
|
}
|
||||||
|
|
||||||
public static String fromUUID(UUID value) {
|
public void write(JsonWriter out, UUID value) throws IOException {
|
||||||
return value.toString().replace("-", "");
|
out.value(fromUUID(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UUID fromString(String input) {
|
public UUID read(JsonReader in) throws IOException {
|
||||||
return UUID.fromString(input.replaceFirst(
|
return fromString(in.nextString());
|
||||||
"(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5"));
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,213 +1,184 @@
|
|||||||
package com.wimbli.WorldBorder;
|
package com.wimbli.WorldBorder;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import com.wimbli.WorldBorder.cmd.*;
|
||||||
import java.util.Arrays;
|
import org.bukkit.command.Command;
|
||||||
import java.util.Iterator;
|
import org.bukkit.command.CommandExecutor;
|
||||||
import java.util.LinkedHashMap;
|
import org.bukkit.command.CommandSender;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.cmd.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
|
||||||
public class WBCommand implements CommandExecutor
|
public class WBCommand implements CommandExecutor {
|
||||||
{
|
// map of all sub-commands with the command name (string) for quick reference
|
||||||
// map of all sub-commands with the command name (string) for quick reference
|
public Map<String, WBCmd> subCommands = new LinkedHashMap<String, WBCmd>();
|
||||||
public Map<String, WBCmd> subCommands = new LinkedHashMap<String, WBCmd>();
|
// ref. list of the commands which can have a world name in front of the command itself (ex. /wb _world_ radius 100)
|
||||||
// ref. list of the commands which can have a world name in front of the command itself (ex. /wb _world_ radius 100)
|
private Set<String> subCommandsWithWorldNames = new LinkedHashSet<String>();
|
||||||
private Set<String> subCommandsWithWorldNames = new LinkedHashSet<String>();
|
private boolean wasWorldQuotation = false;
|
||||||
|
|
||||||
// constructor
|
|
||||||
public WBCommand ()
|
|
||||||
{
|
|
||||||
addCmd(new CmdHelp()); // 1 example
|
|
||||||
addCmd(new CmdSet()); // 4 examples for player, 3 for console
|
|
||||||
addCmd(new CmdSetcorners()); // 1
|
|
||||||
addCmd(new CmdRadius()); // 1
|
|
||||||
addCmd(new CmdList()); // 1
|
|
||||||
//----- 8 per page of examples
|
|
||||||
addCmd(new CmdShape()); // 2
|
|
||||||
addCmd(new CmdClear()); // 2
|
|
||||||
addCmd(new CmdFill()); // 1
|
|
||||||
addCmd(new CmdTrim()); // 1
|
|
||||||
addCmd(new CmdBypass()); // 1
|
|
||||||
addCmd(new CmdBypasslist()); // 1
|
|
||||||
//-----
|
|
||||||
addCmd(new CmdKnockback()); // 1
|
|
||||||
addCmd(new CmdWrap()); // 1
|
|
||||||
addCmd(new CmdWhoosh()); // 1
|
|
||||||
addCmd(new CmdGetmsg()); // 1
|
|
||||||
addCmd(new CmdSetmsg()); // 1
|
|
||||||
addCmd(new CmdWshape()); // 3
|
|
||||||
//-----
|
|
||||||
addCmd(new CmdPreventPlace()); // 1
|
|
||||||
addCmd(new CmdPreventSpawn()); // 1
|
|
||||||
addCmd(new CmdDelay()); // 1
|
|
||||||
addCmd(new CmdDynmap()); // 1
|
|
||||||
addCmd(new CmdDynmapmsg()); // 1
|
|
||||||
addCmd(new CmdRemount()); // 1
|
|
||||||
addCmd(new CmdFillautosave()); // 1
|
|
||||||
addCmd(new CmdPortal()); // 1
|
|
||||||
//-----
|
|
||||||
addCmd(new CmdDenypearl()); // 1
|
|
||||||
addCmd(new CmdReload()); // 1
|
|
||||||
addCmd(new CmdDebug()); // 1
|
|
||||||
|
|
||||||
// this is the default command, which shows command example pages; should be last just in case
|
|
||||||
addCmd(new CmdCommands());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void addCmd(WBCmd cmd)
|
// constructor
|
||||||
{
|
public WBCommand() {
|
||||||
subCommands.put(cmd.name, cmd);
|
addCmd(new CmdHelp()); // 1 example
|
||||||
if (cmd.hasWorldNameInput)
|
addCmd(new CmdSet()); // 4 examples for player, 3 for console
|
||||||
subCommandsWithWorldNames.add(cmd.name);
|
addCmd(new CmdSetcorners()); // 1
|
||||||
}
|
addCmd(new CmdRadius()); // 1
|
||||||
|
addCmd(new CmdList()); // 1
|
||||||
|
//----- 8 per page of examples
|
||||||
|
addCmd(new CmdShape()); // 2
|
||||||
|
addCmd(new CmdClear()); // 2
|
||||||
|
addCmd(new CmdFill()); // 1
|
||||||
|
addCmd(new CmdTrim()); // 1
|
||||||
|
addCmd(new CmdBypass()); // 1
|
||||||
|
addCmd(new CmdBypasslist()); // 1
|
||||||
|
//-----
|
||||||
|
addCmd(new CmdKnockback()); // 1
|
||||||
|
addCmd(new CmdWrap()); // 1
|
||||||
|
addCmd(new CmdWhoosh()); // 1
|
||||||
|
addCmd(new CmdGetmsg()); // 1
|
||||||
|
addCmd(new CmdSetmsg()); // 1
|
||||||
|
addCmd(new CmdWshape()); // 3
|
||||||
|
//-----
|
||||||
|
addCmd(new CmdPreventPlace()); // 1
|
||||||
|
addCmd(new CmdPreventSpawn()); // 1
|
||||||
|
addCmd(new CmdDelay()); // 1
|
||||||
|
addCmd(new CmdDynmap()); // 1
|
||||||
|
addCmd(new CmdDynmapmsg()); // 1
|
||||||
|
addCmd(new CmdRemount()); // 1
|
||||||
|
addCmd(new CmdFillautosave()); // 1
|
||||||
|
addCmd(new CmdPortal()); // 1
|
||||||
|
//-----
|
||||||
|
addCmd(new CmdDenypearl()); // 1
|
||||||
|
addCmd(new CmdReload()); // 1
|
||||||
|
addCmd(new CmdDebug()); // 1
|
||||||
|
|
||||||
|
// this is the default command, which shows command example pages; should be last just in case
|
||||||
|
addCmd(new CmdCommands());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCmd(WBCmd cmd) {
|
||||||
|
subCommands.put(cmd.name, cmd);
|
||||||
|
if (cmd.hasWorldNameInput)
|
||||||
|
subCommandsWithWorldNames.add(cmd.name);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] split)
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] split) {
|
||||||
{
|
Player player = (sender instanceof Player) ? (Player) sender : null;
|
||||||
Player player = (sender instanceof Player) ? (Player)sender : null;
|
|
||||||
|
|
||||||
// if world name is passed inside quotation marks, handle that, and get List<String> instead of String[]
|
// if world name is passed inside quotation marks, handle that, and get List<String> instead of String[]
|
||||||
List<String> params = concatenateQuotedWorldName(split);
|
List<String> params = concatenateQuotedWorldName(split);
|
||||||
|
|
||||||
String worldName = null;
|
String worldName = null;
|
||||||
// is second parameter the command and first parameter a world name? definitely world name if it was in quotation marks
|
// is second parameter the command and first parameter a world name? definitely world name if it was in quotation marks
|
||||||
if (wasWorldQuotation || (params.size() > 1 && !subCommands.containsKey(params.get(0)) && subCommandsWithWorldNames.contains(params.get(1))))
|
if (wasWorldQuotation || (params.size() > 1 && !subCommands.containsKey(params.get(0)) && subCommandsWithWorldNames.contains(params.get(1))))
|
||||||
worldName = params.get(0);
|
worldName = params.get(0);
|
||||||
|
|
||||||
// no command specified? show command examples / help
|
// no command specified? show command examples / help
|
||||||
if (params.isEmpty())
|
if (params.isEmpty())
|
||||||
params.add(0, "commands");
|
params.add(0, "commands");
|
||||||
|
|
||||||
// determined the command name
|
// determined the command name
|
||||||
String cmdName = (worldName == null) ? params.get(0).toLowerCase() : params.get(1).toLowerCase();
|
String cmdName = (worldName == null) ? params.get(0).toLowerCase() : params.get(1).toLowerCase();
|
||||||
|
|
||||||
// remove command name and (if there) world name from front of param array
|
// remove command name and (if there) world name from front of param array
|
||||||
params.remove(0);
|
params.remove(0);
|
||||||
if (worldName != null)
|
if (worldName != null)
|
||||||
params.remove(0);
|
params.remove(0);
|
||||||
|
|
||||||
// make sure command is recognized, default to showing command examples / help if not; also check for specified page number
|
// make sure command is recognized, default to showing command examples / help if not; also check for specified page number
|
||||||
if (!subCommands.containsKey(cmdName))
|
if (!subCommands.containsKey(cmdName)) {
|
||||||
{
|
int page = (player == null) ? 0 : 1;
|
||||||
int page = (player == null) ? 0 : 1;
|
try {
|
||||||
try
|
page = Integer.parseInt(cmdName);
|
||||||
{
|
} catch (NumberFormatException ignored) {
|
||||||
page = Integer.parseInt(cmdName);
|
sender.sendMessage(WBCmd.C_ERR + "Command not recognized. Showing command list.");
|
||||||
}
|
}
|
||||||
catch(NumberFormatException ignored)
|
cmdName = "commands";
|
||||||
{
|
params.add(0, Integer.toString(page));
|
||||||
sender.sendMessage(WBCmd.C_ERR + "Command not recognized. Showing command list.");
|
}
|
||||||
}
|
|
||||||
cmdName = "commands";
|
|
||||||
params.add(0, Integer.toString(page));
|
|
||||||
}
|
|
||||||
|
|
||||||
WBCmd subCommand = subCommands.get(cmdName);
|
WBCmd subCommand = subCommands.get(cmdName);
|
||||||
|
|
||||||
// check permission
|
// check permission
|
||||||
if (!Config.HasPermission(player, subCommand.permission))
|
if (!Config.HasPermission(player, subCommand.permission))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// if command requires world name when run by console, make sure that's in place
|
// if command requires world name when run by console, make sure that's in place
|
||||||
if (player == null && subCommand.hasWorldNameInput && subCommand.consoleRequiresWorldName && worldName == null)
|
if (player == null && subCommand.hasWorldNameInput && subCommand.consoleRequiresWorldName && worldName == null) {
|
||||||
{
|
sender.sendMessage(WBCmd.C_ERR + "This command requires a world to be specified if run by the console.");
|
||||||
sender.sendMessage(WBCmd.C_ERR + "This command requires a world to be specified if run by the console.");
|
subCommand.sendCmdHelp(sender);
|
||||||
subCommand.sendCmdHelp(sender);
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// make sure valid number of parameters has been provided
|
// make sure valid number of parameters has been provided
|
||||||
if (params.size() < subCommand.minParams || params.size() > subCommand.maxParams)
|
if (params.size() < subCommand.minParams || params.size() > subCommand.maxParams) {
|
||||||
{
|
if (subCommand.maxParams == 0)
|
||||||
if (subCommand.maxParams == 0)
|
sender.sendMessage(WBCmd.C_ERR + "This command does not accept any parameters.");
|
||||||
sender.sendMessage(WBCmd.C_ERR + "This command does not accept any parameters.");
|
else
|
||||||
else
|
sender.sendMessage(WBCmd.C_ERR + "You have not provided a valid number of parameters.");
|
||||||
sender.sendMessage(WBCmd.C_ERR + "You have not provided a valid number of parameters.");
|
subCommand.sendCmdHelp(sender);
|
||||||
subCommand.sendCmdHelp(sender);
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// execute command
|
// execute command
|
||||||
subCommand.execute(sender, player, params, worldName);
|
subCommand.execute(sender, player, params, worldName);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if world name is surrounded by quotation marks, combine it down and flag wasWorldQuotation if it's first param.
|
||||||
|
// also return List<String> instead of input primitive String[]
|
||||||
|
private List<String> concatenateQuotedWorldName(String[] split) {
|
||||||
|
wasWorldQuotation = false;
|
||||||
|
List<String> args = new ArrayList<String>(Arrays.asList(split));
|
||||||
|
|
||||||
private boolean wasWorldQuotation = false;
|
int startIndex = -1;
|
||||||
|
for (int i = 0; i < args.size(); i++) {
|
||||||
|
if (args.get(i).startsWith("\"")) {
|
||||||
|
startIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (startIndex == -1)
|
||||||
|
return args;
|
||||||
|
|
||||||
// if world name is surrounded by quotation marks, combine it down and flag wasWorldQuotation if it's first param.
|
if (args.get(startIndex).endsWith("\"")) {
|
||||||
// also return List<String> instead of input primitive String[]
|
args.set(startIndex, args.get(startIndex).substring(1, args.get(startIndex).length() - 1));
|
||||||
private List<String> concatenateQuotedWorldName(String[] split)
|
if (startIndex == 0)
|
||||||
{
|
wasWorldQuotation = true;
|
||||||
wasWorldQuotation = false;
|
} else {
|
||||||
List<String> args = new ArrayList<String>(Arrays.asList(split));
|
List<String> concat = new ArrayList<String>(args);
|
||||||
|
Iterator<String> concatI = concat.iterator();
|
||||||
|
|
||||||
int startIndex = -1;
|
// skip past any parameters in front of the one we're starting on
|
||||||
for (int i = 0; i < args.size(); i++)
|
for (int i = 1; i < startIndex + 1; i++) {
|
||||||
{
|
concatI.next();
|
||||||
if (args.get(i).startsWith("\""))
|
}
|
||||||
{
|
|
||||||
startIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (startIndex == -1)
|
|
||||||
return args;
|
|
||||||
|
|
||||||
if (args.get(startIndex).endsWith("\""))
|
StringBuilder quote = new StringBuilder(concatI.next());
|
||||||
{
|
while (concatI.hasNext()) {
|
||||||
args.set(startIndex, args.get(startIndex).substring(1, args.get(startIndex).length() - 1));
|
String next = concatI.next();
|
||||||
if (startIndex == 0)
|
concatI.remove();
|
||||||
wasWorldQuotation = true;
|
quote.append(" ");
|
||||||
}
|
quote.append(next);
|
||||||
else
|
if (next.endsWith("\"")) {
|
||||||
{
|
concat.set(startIndex, quote.substring(1, quote.length() - 1));
|
||||||
List<String> concat = new ArrayList<String>(args);
|
args = concat;
|
||||||
Iterator<String> concatI = concat.iterator();
|
if (startIndex == 0)
|
||||||
|
wasWorldQuotation = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
// skip past any parameters in front of the one we're starting on
|
public Set<String> getCommandNames() {
|
||||||
for (int i = 1; i < startIndex + 1; i++)
|
// using TreeSet to sort alphabetically
|
||||||
{
|
Set<String> commands = new TreeSet<>(subCommands.keySet());
|
||||||
concatI.next();
|
// removing default "commands" command as it's not normally shown or run like other commands
|
||||||
}
|
commands.remove("commands");
|
||||||
|
return commands;
|
||||||
StringBuilder quote = new StringBuilder(concatI.next());
|
}
|
||||||
while (concatI.hasNext())
|
|
||||||
{
|
|
||||||
String next = concatI.next();
|
|
||||||
concatI.remove();
|
|
||||||
quote.append(" ");
|
|
||||||
quote.append(next);
|
|
||||||
if (next.endsWith("\""))
|
|
||||||
{
|
|
||||||
concat.set(startIndex, quote.substring(1, quote.length() - 1));
|
|
||||||
args = concat;
|
|
||||||
if (startIndex == 0)
|
|
||||||
wasWorldQuotation = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getCommandNames()
|
|
||||||
{
|
|
||||||
// using TreeSet to sort alphabetically
|
|
||||||
Set<String> commands = new TreeSet<>(subCommands.keySet());
|
|
||||||
// removing default "commands" command as it's not normally shown or run like other commands
|
|
||||||
commands.remove("commands");
|
|
||||||
return commands;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,56 +1,50 @@
|
|||||||
package com.wimbli.WorldBorder;
|
package com.wimbli.WorldBorder;
|
||||||
|
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.Location;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
|
||||||
import org.bukkit.event.player.PlayerPortalEvent;
|
import org.bukkit.event.player.PlayerPortalEvent;
|
||||||
|
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||||
import org.bukkit.event.world.ChunkLoadEvent;
|
import org.bukkit.event.world.ChunkLoadEvent;
|
||||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||||
import org.bukkit.Location;
|
|
||||||
|
|
||||||
|
|
||||||
public class WBListener implements Listener
|
public class WBListener implements Listener {
|
||||||
{
|
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
public void onPlayerTeleport(PlayerTeleportEvent event) {
|
||||||
public void onPlayerTeleport(PlayerTeleportEvent event)
|
// if knockback is set to 0, simply return
|
||||||
{
|
if (Config.KnockBack() == 0.0)
|
||||||
// if knockback is set to 0, simply return
|
return;
|
||||||
if (Config.KnockBack() == 0.0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (Config.Debug())
|
if (Config.Debug())
|
||||||
Config.log("Teleport cause: " + event.getCause().toString());
|
Config.log("Teleport cause: " + event.getCause().toString());
|
||||||
|
|
||||||
Location newLoc = BorderCheckTask.checkPlayer(event.getPlayer(), event.getTo(), true, true);
|
Location newLoc = BorderCheckTask.checkPlayer(event.getPlayer(), event.getTo(), true, true);
|
||||||
if (newLoc != null)
|
if (newLoc != null) {
|
||||||
{
|
if (event.getCause() == PlayerTeleportEvent.TeleportCause.ENDER_PEARL && Config.getDenyEnderpearl()) {
|
||||||
if(event.getCause() == PlayerTeleportEvent.TeleportCause.ENDER_PEARL && Config.getDenyEnderpearl())
|
event.setCancelled(true);
|
||||||
{
|
return;
|
||||||
event.setCancelled(true);
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
event.setTo(newLoc);
|
event.setTo(newLoc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||||
public void onPlayerPortal(PlayerPortalEvent event)
|
public void onPlayerPortal(PlayerPortalEvent event) {
|
||||||
{
|
// if knockback is set to 0, or portal redirection is disabled, simply return
|
||||||
// if knockback is set to 0, or portal redirection is disabled, simply return
|
if (Config.KnockBack() == 0.0 || !Config.portalRedirection())
|
||||||
if (Config.KnockBack() == 0.0 || !Config.portalRedirection())
|
return;
|
||||||
return;
|
|
||||||
|
|
||||||
Location newLoc = BorderCheckTask.checkPlayer(event.getPlayer(), event.getTo(), true, false);
|
Location newLoc = BorderCheckTask.checkPlayer(event.getPlayer(), event.getTo(), true, false);
|
||||||
if (newLoc != null)
|
if (newLoc != null)
|
||||||
event.setTo(newLoc);
|
event.setTo(newLoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR)
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
public void onChunkLoad(ChunkLoadEvent event)
|
public void onChunkLoad(ChunkLoadEvent event) {
|
||||||
{
|
|
||||||
/* // tested, found to spam pretty rapidly as client repeatedly requests the same chunks since they're not being sent
|
/* // tested, found to spam pretty rapidly as client repeatedly requests the same chunks since they're not being sent
|
||||||
// definitely too spammy at only 16 blocks outside border
|
// definitely too spammy at only 16 blocks outside border
|
||||||
// potentially useful at standard 208 block padding as it was triggering only occasionally while trying to get out all along edge of round border, though sometimes up to 3 triggers within a second corresponding to 3 adjacent chunks
|
// potentially useful at standard 208 block padding as it was triggering only occasionally while trying to get out all along edge of round border, though sometimes up to 3 triggers within a second corresponding to 3 adjacent chunks
|
||||||
@ -64,30 +58,29 @@ public class WBListener implements Listener
|
|||||||
Config.logWarn("New chunk generation has been prevented at X " + chunk.getX() + ", Z " + chunk.getZ());
|
Config.logWarn("New chunk generation has been prevented at X " + chunk.getX() + ", Z " + chunk.getZ());
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
// make sure our border monitoring task is still running like it should
|
// make sure our border monitoring task is still running like it should
|
||||||
if (Config.isBorderTimerRunning()) return;
|
if (Config.isBorderTimerRunning()) return;
|
||||||
|
|
||||||
Config.logWarn("Border-checking task was not running! Something on your server apparently killed it. It will now be restarted.");
|
Config.logWarn("Border-checking task was not running! Something on your server apparently killed it. It will now be restarted.");
|
||||||
Config.StartBorderTimer();
|
Config.StartBorderTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if there is a fill task running, and if yes, if it's for the
|
* Check if there is a fill task running, and if yes, if it's for the
|
||||||
* world that the unload event refers to, set "force loaded" flag off
|
* world that the unload event refers to, set "force loaded" flag off
|
||||||
* and track if chunk was somehow on unload prevention list
|
* and track if chunk was somehow on unload prevention list
|
||||||
*/
|
*/
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onChunkUnload(ChunkUnloadEvent e)
|
public void onChunkUnload(ChunkUnloadEvent e) {
|
||||||
{
|
if (Config.fillTask == null)
|
||||||
if (Config.fillTask == null)
|
return;
|
||||||
return;
|
|
||||||
|
|
||||||
Chunk chunk = e.getChunk();
|
Chunk chunk = e.getChunk();
|
||||||
if (e.getWorld() != Config.fillTask.getWorld())
|
if (e.getWorld() != Config.fillTask.getWorld())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// just to be on the safe side, in case it's still set at this point somehow
|
// just to be on the safe side, in case it's still set at this point somehow
|
||||||
chunk.setForceLoaded(false);
|
chunk.setForceLoaded(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,81 +4,74 @@ import org.bukkit.Location;
|
|||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
|
||||||
public class WorldBorder extends JavaPlugin
|
public class WorldBorder extends JavaPlugin {
|
||||||
{
|
public static volatile WorldBorder plugin = null;
|
||||||
public static volatile WorldBorder plugin = null;
|
public static volatile WBCommand wbCommand = null;
|
||||||
public static volatile WBCommand wbCommand = null;
|
private BlockPlaceListener blockPlaceListener = null;
|
||||||
private BlockPlaceListener blockPlaceListener = null;
|
private MobSpawnListener mobSpawnListener = null;
|
||||||
private MobSpawnListener mobSpawnListener = null;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable()
|
public void onEnable() {
|
||||||
{
|
if (plugin == null)
|
||||||
if (plugin == null)
|
plugin = this;
|
||||||
plugin = this;
|
if (wbCommand == null)
|
||||||
if (wbCommand == null)
|
wbCommand = new WBCommand();
|
||||||
wbCommand = new WBCommand();
|
|
||||||
|
|
||||||
// Load (or create new) config file
|
// Load (or create new) config file
|
||||||
Config.load(this, false);
|
Config.load(this, false);
|
||||||
|
|
||||||
// our one real command, though it does also have aliases "wb" and "worldborder"
|
// our one real command, though it does also have aliases "wb" and "worldborder"
|
||||||
getCommand("wborder").setExecutor(wbCommand);
|
getCommand("wborder").setExecutor(wbCommand);
|
||||||
|
|
||||||
// keep an eye on teleports, to redirect them to a spot inside the border if necessary
|
// keep an eye on teleports, to redirect them to a spot inside the border if necessary
|
||||||
getServer().getPluginManager().registerEvents(new WBListener(), this);
|
getServer().getPluginManager().registerEvents(new WBListener(), this);
|
||||||
|
|
||||||
if (Config.preventBlockPlace())
|
if (Config.preventBlockPlace())
|
||||||
enableBlockPlaceListener(true);
|
enableBlockPlaceListener(true);
|
||||||
|
|
||||||
if (Config.preventMobSpawn())
|
if (Config.preventMobSpawn())
|
||||||
enableMobSpawnListener(true);
|
enableMobSpawnListener(true);
|
||||||
|
|
||||||
// integrate with DynMap if it's available
|
// integrate with DynMap if it's available
|
||||||
DynMapFeatures.setup();
|
DynMapFeatures.setup();
|
||||||
|
|
||||||
// Well I for one find this info useful, so...
|
// Well I for one find this info useful, so...
|
||||||
Location spawn = getServer().getWorlds().get(0).getSpawnLocation();
|
Location spawn = getServer().getWorlds().get(0).getSpawnLocation();
|
||||||
Config.log("For reference, the main world's spawn location is at X: " + Config.coord.format(spawn.getX()) + " Y: " + Config.coord.format(spawn.getY()) + " Z: " + Config.coord.format(spawn.getZ()));
|
Config.log("For reference, the main world's spawn location is at X: " + Config.coord.format(spawn.getX()) + " Y: " + Config.coord.format(spawn.getY()) + " Z: " + Config.coord.format(spawn.getZ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable()
|
public void onDisable() {
|
||||||
{
|
DynMapFeatures.removeAllBorders();
|
||||||
DynMapFeatures.removeAllBorders();
|
Config.StopBorderTimer();
|
||||||
Config.StopBorderTimer();
|
Config.StoreFillTask();
|
||||||
Config.StoreFillTask();
|
Config.StopFillTask();
|
||||||
Config.StopFillTask();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// for other plugins to hook into
|
// for other plugins to hook into
|
||||||
public BorderData getWorldBorder(String worldName)
|
public BorderData getWorldBorder(String worldName) {
|
||||||
{
|
return Config.Border(worldName);
|
||||||
return Config.Border(worldName);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Replaced by {@link #getWorldBorder(String worldName)};
|
* @deprecated Replaced by {@link #getWorldBorder(String worldName)};
|
||||||
* this method name starts with an uppercase letter, which it shouldn't
|
* this method name starts with an uppercase letter, which it shouldn't
|
||||||
*/
|
*/
|
||||||
public BorderData GetWorldBorder(String worldName)
|
public BorderData GetWorldBorder(String worldName) {
|
||||||
{
|
return getWorldBorder(worldName);
|
||||||
return getWorldBorder(worldName);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void enableBlockPlaceListener(boolean enable)
|
public void enableBlockPlaceListener(boolean enable) {
|
||||||
{
|
if (enable)
|
||||||
if (enable)
|
getServer().getPluginManager().registerEvents(this.blockPlaceListener = new BlockPlaceListener(), this);
|
||||||
getServer().getPluginManager().registerEvents(this.blockPlaceListener = new BlockPlaceListener(), this);
|
else if (blockPlaceListener != null)
|
||||||
else if (blockPlaceListener != null)
|
blockPlaceListener.unregister();
|
||||||
blockPlaceListener.unregister();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void enableMobSpawnListener(boolean enable)
|
public void enableMobSpawnListener(boolean enable) {
|
||||||
{
|
if (enable)
|
||||||
if (enable)
|
getServer().getPluginManager().registerEvents(this.mobSpawnListener = new MobSpawnListener(), this);
|
||||||
getServer().getPluginManager().registerEvents(this.mobSpawnListener = new MobSpawnListener(), this);
|
else if (mobSpawnListener != null)
|
||||||
else if (mobSpawnListener != null)
|
mobSpawnListener.unregister();
|
||||||
mobSpawnListener.unregister();
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,311 +1,264 @@
|
|||||||
package com.wimbli.WorldBorder;
|
package com.wimbli.WorldBorder;
|
||||||
|
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.*;
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.World;
|
|
||||||
|
|
||||||
// image output stuff, for debugging method at bottom of this file
|
// image output stuff, for debugging method at bottom of this file
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.image.*;
|
|
||||||
import javax.imageio.*;
|
|
||||||
|
|
||||||
|
|
||||||
// by the way, this region file handler was created based on the divulged region file format: http://mojang.com/2011/02/16/minecraft-save-file-format-in-beta-1-3/
|
// by the way, this region file handler was created based on the divulged region file format: http://mojang.com/2011/02/16/minecraft-save-file-format-in-beta-1-3/
|
||||||
|
|
||||||
public class WorldFileData
|
public class WorldFileData {
|
||||||
{
|
private transient World world;
|
||||||
private transient World world;
|
private transient File regionFolder = null;
|
||||||
private transient File regionFolder = null;
|
private transient File[] regionFiles = null;
|
||||||
private transient File[] regionFiles = null;
|
private transient Player notifyPlayer = null;
|
||||||
private transient Player notifyPlayer = null;
|
private transient Map<CoordXZ, List<Boolean>> regionChunkExistence = Collections.synchronizedMap(new HashMap<CoordXZ, List<Boolean>>());
|
||||||
private transient Map<CoordXZ, List<Boolean>> regionChunkExistence = Collections.synchronizedMap(new HashMap<CoordXZ, List<Boolean>>());
|
|
||||||
|
|
||||||
// Use this static method to create a new instance of this class. If null is returned, there was a problem so any process relying on this should be cancelled.
|
// the constructor is private; use create() method above to create an instance of this class.
|
||||||
public static WorldFileData create(World world, Player notifyPlayer)
|
private WorldFileData(World world, Player notifyPlayer) {
|
||||||
{
|
this.world = world;
|
||||||
WorldFileData newData = new WorldFileData(world, notifyPlayer);
|
this.notifyPlayer = notifyPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
newData.regionFolder = new File(newData.world.getWorldFolder(), "region");
|
// Use this static method to create a new instance of this class. If null is returned, there was a problem so any process relying on this should be cancelled.
|
||||||
if (!newData.regionFolder.exists() || !newData.regionFolder.isDirectory())
|
public static WorldFileData create(World world, Player notifyPlayer) {
|
||||||
{
|
WorldFileData newData = new WorldFileData(world, notifyPlayer);
|
||||||
// check for region folder inside a DIM* folder (DIM-1 for nether, DIM1 for end, DIMwhatever for custom world types)
|
|
||||||
File[] possibleDimFolders = newData.world.getWorldFolder().listFiles(new DimFolderFileFilter());
|
|
||||||
for (File possibleDimFolder : possibleDimFolders)
|
|
||||||
{
|
|
||||||
File possible = new File(newData.world.getWorldFolder(), possibleDimFolder.getName() + File.separator + "region");
|
|
||||||
if (possible.exists() && possible.isDirectory())
|
|
||||||
{
|
|
||||||
newData.regionFolder = possible;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!newData.regionFolder.exists() || !newData.regionFolder.isDirectory())
|
|
||||||
{
|
|
||||||
newData.sendMessage("Could not validate folder for world's region files. Looked in "+newData.world.getWorldFolder().getPath()+" for valid DIM* folder with a region folder in it.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accepted region file formats: MCR is from late beta versions through 1.1, MCA is from 1.2+
|
newData.regionFolder = new File(newData.world.getWorldFolder(), "region");
|
||||||
newData.regionFiles = newData.regionFolder.listFiles(new ExtFileFilter(".MCA"));
|
if (!newData.regionFolder.exists() || !newData.regionFolder.isDirectory()) {
|
||||||
if (newData.regionFiles == null || newData.regionFiles.length == 0)
|
// check for region folder inside a DIM* folder (DIM-1 for nether, DIM1 for end, DIMwhatever for custom world types)
|
||||||
{
|
File[] possibleDimFolders = newData.world.getWorldFolder().listFiles(new DimFolderFileFilter());
|
||||||
newData.regionFiles = newData.regionFolder.listFiles(new ExtFileFilter(".MCR"));
|
for (File possibleDimFolder : possibleDimFolders) {
|
||||||
if (newData.regionFiles == null || newData.regionFiles.length == 0)
|
File possible = new File(newData.world.getWorldFolder(), possibleDimFolder.getName() + File.separator + "region");
|
||||||
{
|
if (possible.exists() && possible.isDirectory()) {
|
||||||
newData.sendMessage("Could not find any region files. Looked in: "+newData.regionFolder.getPath());
|
newData.regionFolder = possible;
|
||||||
return null;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!newData.regionFolder.exists() || !newData.regionFolder.isDirectory()) {
|
||||||
|
newData.sendMessage("Could not validate folder for world's region files. Looked in " + newData.world.getWorldFolder().getPath() + " for valid DIM* folder with a region folder in it.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return newData;
|
// Accepted region file formats: MCR is from late beta versions through 1.1, MCA is from 1.2+
|
||||||
}
|
newData.regionFiles = newData.regionFolder.listFiles(new ExtFileFilter(".MCA"));
|
||||||
|
if (newData.regionFiles == null || newData.regionFiles.length == 0) {
|
||||||
|
newData.regionFiles = newData.regionFolder.listFiles(new ExtFileFilter(".MCR"));
|
||||||
|
if (newData.regionFiles == null || newData.regionFiles.length == 0) {
|
||||||
|
newData.sendMessage("Could not find any region files. Looked in: " + newData.regionFolder.getPath());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// the constructor is private; use create() method above to create an instance of this class.
|
return newData;
|
||||||
private WorldFileData(World world, Player notifyPlayer)
|
}
|
||||||
{
|
|
||||||
this.world = world;
|
// number of region files this world has
|
||||||
this.notifyPlayer = notifyPlayer;
|
public int regionFileCount() {
|
||||||
}
|
return regionFiles.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// folder where world's region files are located
|
||||||
|
public File regionFolder() {
|
||||||
|
return regionFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return entire list of region files
|
||||||
|
public File[] regionFiles() {
|
||||||
|
return regionFiles.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a region file by index
|
||||||
|
public File regionFile(int index) {
|
||||||
|
if (regionFiles.length < index)
|
||||||
|
return null;
|
||||||
|
return regionFiles[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the X and Z world coordinates of the region from the filename
|
||||||
|
public CoordXZ regionFileCoordinates(int index) {
|
||||||
|
File regionFile = this.regionFile(index);
|
||||||
|
String[] coords = regionFile.getName().split("\\.");
|
||||||
|
int x, z;
|
||||||
|
try {
|
||||||
|
x = Integer.parseInt(coords[1]);
|
||||||
|
z = Integer.parseInt(coords[2]);
|
||||||
|
return new CoordXZ(x, z);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
sendMessage("Error! Region file found with abnormal name: " + regionFile.getName());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// number of region files this world has
|
// Find out if the chunk at the given coordinates exists.
|
||||||
public int regionFileCount()
|
public boolean doesChunkExist(int x, int z) {
|
||||||
{
|
CoordXZ region = new CoordXZ(CoordXZ.chunkToRegion(x), CoordXZ.chunkToRegion(z));
|
||||||
return regionFiles.length;
|
List<Boolean> regionChunks = this.getRegionData(region);
|
||||||
}
|
|
||||||
|
|
||||||
// folder where world's region files are located
|
|
||||||
public File regionFolder()
|
|
||||||
{
|
|
||||||
return regionFolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return entire list of region files
|
|
||||||
public File[] regionFiles()
|
|
||||||
{
|
|
||||||
return regionFiles.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
// return a region file by index
|
|
||||||
public File regionFile(int index)
|
|
||||||
{
|
|
||||||
if (regionFiles.length < index)
|
|
||||||
return null;
|
|
||||||
return regionFiles[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the X and Z world coordinates of the region from the filename
|
|
||||||
public CoordXZ regionFileCoordinates(int index)
|
|
||||||
{
|
|
||||||
File regionFile = this.regionFile(index);
|
|
||||||
String[] coords = regionFile.getName().split("\\.");
|
|
||||||
int x, z;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
x = Integer.parseInt(coords[1]);
|
|
||||||
z = Integer.parseInt(coords[2]);
|
|
||||||
return new CoordXZ (x, z);
|
|
||||||
}
|
|
||||||
catch(Exception ex)
|
|
||||||
{
|
|
||||||
sendMessage("Error! Region file found with abnormal name: "+regionFile.getName());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Find out if the chunk at the given coordinates exists.
|
|
||||||
public boolean doesChunkExist(int x, int z)
|
|
||||||
{
|
|
||||||
CoordXZ region = new CoordXZ(CoordXZ.chunkToRegion(x), CoordXZ.chunkToRegion(z));
|
|
||||||
List<Boolean> regionChunks = this.getRegionData(region);
|
|
||||||
// Bukkit.getLogger().info("x: "+x+" z: "+z+" offset: "+coordToRegionOffset(x, z));
|
// Bukkit.getLogger().info("x: "+x+" z: "+z+" offset: "+coordToRegionOffset(x, z));
|
||||||
return regionChunks.get(coordToRegionOffset(x, z));
|
return regionChunks.get(coordToRegionOffset(x, z));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find out if the chunk at the given coordinates has been fully generated.
|
// Find out if the chunk at the given coordinates has been fully generated.
|
||||||
// Minecraft only fully generates a chunk when adjacent chunks are also loaded.
|
// Minecraft only fully generates a chunk when adjacent chunks are also loaded.
|
||||||
public boolean isChunkFullyGenerated(int x, int z)
|
public boolean isChunkFullyGenerated(int x, int z) { // if all adjacent chunks exist, it should be a safe enough bet that this one is fully generated
|
||||||
{ // if all adjacent chunks exist, it should be a safe enough bet that this one is fully generated
|
// For 1.13+, due to world gen changes, this is now effectively a 3 chunk radius requirement vs a 1 chunk radius
|
||||||
// For 1.13+, due to world gen changes, this is now effectively a 3 chunk radius requirement vs a 1 chunk radius
|
for (int xx = x - 3; xx <= x + 3; xx++) {
|
||||||
for (int xx = x-3; xx <= x+3; xx++)
|
for (int zz = z - 3; zz <= z + 3; zz++) {
|
||||||
{
|
if (!doesChunkExist(xx, zz))
|
||||||
for (int zz = z-3; zz <= z+3; zz++)
|
return false;
|
||||||
{
|
}
|
||||||
if (!doesChunkExist(xx, zz))
|
}
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to let us know a chunk has been generated, to update our region map.
|
// Method to let us know a chunk has been generated, to update our region map.
|
||||||
public void chunkExistsNow(int x, int z)
|
public void chunkExistsNow(int x, int z) {
|
||||||
{
|
CoordXZ region = new CoordXZ(CoordXZ.chunkToRegion(x), CoordXZ.chunkToRegion(z));
|
||||||
CoordXZ region = new CoordXZ(CoordXZ.chunkToRegion(x), CoordXZ.chunkToRegion(z));
|
List<Boolean> regionChunks = this.getRegionData(region);
|
||||||
List<Boolean> regionChunks = this.getRegionData(region);
|
regionChunks.set(coordToRegionOffset(x, z), true);
|
||||||
regionChunks.set(coordToRegionOffset(x, z), true);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
// region is 32 * 32 chunks; chunk pointers are stored in region file at position: x + z*32 (32 * 32 chunks = 1024)
|
||||||
|
// input x and z values can be world-based chunk coordinates or local-to-region chunk coordinates either one
|
||||||
|
private int coordToRegionOffset(int x, int z) {
|
||||||
|
// "%" modulus is used to convert potential world coordinates to definitely be local region coordinates
|
||||||
|
x = x % 32;
|
||||||
|
z = z % 32;
|
||||||
|
// similarly, for local coordinates, we need to wrap negative values around
|
||||||
|
if (x < 0) x += 32;
|
||||||
|
if (z < 0) z += 32;
|
||||||
|
// return offset position for the now definitely local x and z values
|
||||||
|
return (x + (z * 32));
|
||||||
|
}
|
||||||
|
|
||||||
// region is 32 * 32 chunks; chunk pointers are stored in region file at position: x + z*32 (32 * 32 chunks = 1024)
|
private List<Boolean> getRegionData(CoordXZ region) {
|
||||||
// input x and z values can be world-based chunk coordinates or local-to-region chunk coordinates either one
|
List<Boolean> data = regionChunkExistence.get(region);
|
||||||
private int coordToRegionOffset(int x, int z)
|
if (data != null)
|
||||||
{
|
return data;
|
||||||
// "%" modulus is used to convert potential world coordinates to definitely be local region coordinates
|
|
||||||
x = x % 32;
|
|
||||||
z = z % 32;
|
|
||||||
// similarly, for local coordinates, we need to wrap negative values around
|
|
||||||
if (x < 0) x += 32;
|
|
||||||
if (z < 0) z += 32;
|
|
||||||
// return offset position for the now definitely local x and z values
|
|
||||||
return (x + (z * 32));
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Boolean> getRegionData(CoordXZ region)
|
// data for the specified region isn't loaded yet, so init it as empty and try to find the file and load the data
|
||||||
{
|
data = new ArrayList<Boolean>(1024);
|
||||||
List<Boolean> data = regionChunkExistence.get(region);
|
for (int i = 0; i < 1024; i++) {
|
||||||
if (data != null)
|
data.add(Boolean.FALSE);
|
||||||
return data;
|
}
|
||||||
|
|
||||||
// data for the specified region isn't loaded yet, so init it as empty and try to find the file and load the data
|
for (int i = 0; i < regionFiles.length; i++) {
|
||||||
data = new ArrayList<Boolean>(1024);
|
CoordXZ coord = regionFileCoordinates(i);
|
||||||
for (int i = 0; i < 1024; i++)
|
// is this region file the one we're looking for?
|
||||||
{
|
if (!coord.equals(region))
|
||||||
data.add(Boolean.FALSE);
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < regionFiles.length; i++)
|
try {
|
||||||
{
|
RandomAccessFile regionData = new RandomAccessFile(this.regionFile(i), "r");
|
||||||
CoordXZ coord = regionFileCoordinates(i);
|
|
||||||
// is this region file the one we're looking for?
|
|
||||||
if ( ! coord.equals(region))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
try
|
// Use of ByteBuffer+IntBuffer for reading file headers to improve performance, as suggested by aikar, reference:
|
||||||
{
|
// https://github.com/PaperMC/Paper/blob/b62dfa0bf95ac27ba0fbb3fae18c064e4bb61d50/Spigot-Server-Patches/0086-Reduce-IO-ops-opening-a-new-region-file.patch
|
||||||
RandomAccessFile regionData = new RandomAccessFile(this.regionFile(i), "r");
|
ByteBuffer header = ByteBuffer.allocate(8192);
|
||||||
|
while (header.hasRemaining()) {
|
||||||
|
if (regionData.getChannel().read(header) == -1)
|
||||||
|
throw new EOFException();
|
||||||
|
}
|
||||||
|
header.clear();
|
||||||
|
IntBuffer headerAsInts = header.asIntBuffer();
|
||||||
|
|
||||||
// Use of ByteBuffer+IntBuffer for reading file headers to improve performance, as suggested by aikar, reference:
|
// first 4096 bytes of region file consists of 4-byte int pointers to chunk data in the file (32*32 chunks = 1024; 1024 chunks * 4 bytes each = 4096)
|
||||||
// https://github.com/PaperMC/Paper/blob/b62dfa0bf95ac27ba0fbb3fae18c064e4bb61d50/Spigot-Server-Patches/0086-Reduce-IO-ops-opening-a-new-region-file.patch
|
for (int j = 0; j < 1024; j++) {
|
||||||
ByteBuffer header = ByteBuffer.allocate(8192);
|
// if chunk pointer data is 0, chunk doesn't exist yet; otherwise, it does
|
||||||
while (header.hasRemaining())
|
if (headerAsInts.get() != 0)
|
||||||
{
|
data.set(j, true);
|
||||||
if (regionData.getChannel().read(header) == -1)
|
}
|
||||||
throw new EOFException();
|
// Read timestamps
|
||||||
}
|
for (int j = 0; j < 1024; j++) {
|
||||||
header.clear();
|
// if timestamp is zero, it is protochunk (ignore it)
|
||||||
IntBuffer headerAsInts = header.asIntBuffer();
|
if ((headerAsInts.get() == 0) && data.get(j))
|
||||||
|
data.set(j, false);
|
||||||
// first 4096 bytes of region file consists of 4-byte int pointers to chunk data in the file (32*32 chunks = 1024; 1024 chunks * 4 bytes each = 4096)
|
}
|
||||||
for (int j = 0; j < 1024; j++)
|
regionData.close();
|
||||||
{
|
} catch (FileNotFoundException ex) {
|
||||||
// if chunk pointer data is 0, chunk doesn't exist yet; otherwise, it does
|
sendMessage("Error! Could not open region file to find generated chunks: " + this.regionFile(i).getName());
|
||||||
if (headerAsInts.get() != 0)
|
} catch (IOException ex) {
|
||||||
data.set(j, true);
|
sendMessage("Error! Could not read region file to find generated chunks: " + this.regionFile(i).getName());
|
||||||
}
|
}
|
||||||
// Read timestamps
|
}
|
||||||
for (int j = 0; j < 1024; j++)
|
regionChunkExistence.put(region, data);
|
||||||
{
|
|
||||||
// if timestamp is zero, it is protochunk (ignore it)
|
|
||||||
if ((headerAsInts.get() == 0) && data.get(j))
|
|
||||||
data.set(j, false);
|
|
||||||
}
|
|
||||||
regionData.close();
|
|
||||||
}
|
|
||||||
catch (FileNotFoundException ex)
|
|
||||||
{
|
|
||||||
sendMessage("Error! Could not open region file to find generated chunks: "+this.regionFile(i).getName());
|
|
||||||
}
|
|
||||||
catch (IOException ex)
|
|
||||||
{
|
|
||||||
sendMessage("Error! Could not read region file to find generated chunks: "+this.regionFile(i).getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
regionChunkExistence.put(region, data);
|
|
||||||
// testImage(region, data);
|
// testImage(region, data);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send a message to the server console/log and possibly to an in-game player
|
// send a message to the server console/log and possibly to an in-game player
|
||||||
private void sendMessage(String text)
|
private void sendMessage(String text) {
|
||||||
{
|
Config.log("[WorldData] " + text);
|
||||||
Config.log("[WorldData] " + text);
|
if (notifyPlayer != null && notifyPlayer.isOnline())
|
||||||
if (notifyPlayer != null && notifyPlayer.isOnline())
|
notifyPlayer.sendMessage("[WorldData] " + text);
|
||||||
notifyPlayer.sendMessage("[WorldData] " + text);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// file filter used for region files
|
// crude chunk map PNG image output, for debugging
|
||||||
private static class ExtFileFilter implements FileFilter
|
private void testImage(CoordXZ region, List<Boolean> data) {
|
||||||
{
|
int width = 32;
|
||||||
String ext;
|
int height = 32;
|
||||||
public ExtFileFilter(String extension)
|
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||||
{
|
Graphics2D g2 = bi.createGraphics();
|
||||||
this.ext = extension.toLowerCase();
|
int current = 0;
|
||||||
}
|
g2.setColor(Color.BLACK);
|
||||||
|
|
||||||
@Override
|
for (int x = 0; x < 32; x++) {
|
||||||
public boolean accept(File file)
|
for (int z = 0; z < 32; z++) {
|
||||||
{
|
if (data.get(current).booleanValue())
|
||||||
return (
|
g2.fillRect(x, z, x + 1, z + 1);
|
||||||
file.exists()
|
current++;
|
||||||
&& file.isFile()
|
}
|
||||||
&& file.getName().toLowerCase().endsWith(ext)
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// file filter used for DIM* folders (for nether, End, and custom world types)
|
File f = new File("region_" + region.x + "_" + region.z + "_.png");
|
||||||
private static class DimFolderFileFilter implements FileFilter
|
Config.log(f.getAbsolutePath());
|
||||||
{
|
try {
|
||||||
@Override
|
// png is an image format (like gif or jpg)
|
||||||
public boolean accept(File file)
|
ImageIO.write(bi, "png", f);
|
||||||
{
|
} catch (IOException ex) {
|
||||||
return (
|
Config.log("[SEVERE]" + ex.getLocalizedMessage());
|
||||||
file.exists()
|
}
|
||||||
&& file.isDirectory()
|
}
|
||||||
&& file.getName().toLowerCase().startsWith("dim")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// file filter used for region files
|
||||||
|
private static class ExtFileFilter implements FileFilter {
|
||||||
|
String ext;
|
||||||
|
|
||||||
// crude chunk map PNG image output, for debugging
|
public ExtFileFilter(String extension) {
|
||||||
private void testImage(CoordXZ region, List<Boolean> data) {
|
this.ext = extension.toLowerCase();
|
||||||
int width = 32;
|
}
|
||||||
int height = 32;
|
|
||||||
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
|
||||||
Graphics2D g2 = bi.createGraphics();
|
|
||||||
int current = 0;
|
|
||||||
g2.setColor(Color.BLACK);
|
|
||||||
|
|
||||||
for (int x = 0; x < 32; x++)
|
@Override
|
||||||
{
|
public boolean accept(File file) {
|
||||||
for (int z = 0; z < 32; z++)
|
return (
|
||||||
{
|
file.exists()
|
||||||
if (data.get(current).booleanValue())
|
&& file.isFile()
|
||||||
g2.fillRect(x,z, x+1, z+1);
|
&& file.getName().toLowerCase().endsWith(ext)
|
||||||
current++;
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File f = new File("region_"+region.x+"_"+region.z+"_.png");
|
// file filter used for DIM* folders (for nether, End, and custom world types)
|
||||||
Config.log(f.getAbsolutePath());
|
private static class DimFolderFileFilter implements FileFilter {
|
||||||
try {
|
@Override
|
||||||
// png is an image format (like gif or jpg)
|
public boolean accept(File file) {
|
||||||
ImageIO.write(bi, "png", f);
|
return (
|
||||||
} catch (IOException ex) {
|
file.exists()
|
||||||
Config.log("[SEVERE]" + ex.getLocalizedMessage());
|
&& file.isDirectory()
|
||||||
}
|
&& file.getName().toLowerCase().startsWith("dim")
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,12 @@
|
|||||||
package com.wimbli.WorldBorder;
|
package com.wimbli.WorldBorder;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Events.WorldBorderTrimFinishedEvent;
|
||||||
|
import com.wimbli.WorldBorder.Events.WorldBorderTrimStartEvent;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Server;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -7,430 +14,374 @@ import java.io.RandomAccessFile;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.Server;
|
|
||||||
import org.bukkit.World;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.Events.WorldBorderTrimFinishedEvent;
|
public class WorldTrimTask implements Runnable {
|
||||||
import com.wimbli.WorldBorder.Events.WorldBorderTrimStartEvent;
|
// general task-related reference data
|
||||||
|
private transient Server server = null;
|
||||||
|
private transient World world = null;
|
||||||
|
private transient WorldFileData worldData = null;
|
||||||
|
private transient BorderData border = null;
|
||||||
|
private transient boolean readyToGo = false;
|
||||||
|
private transient boolean paused = false;
|
||||||
|
private transient int taskID = -1;
|
||||||
|
private transient Player notifyPlayer = null;
|
||||||
|
private transient int chunksPerRun = 1;
|
||||||
|
|
||||||
|
// values for what chunk in the current region we're at
|
||||||
|
private transient int currentRegion = -1; // region(file) we're at in regionFiles
|
||||||
|
private transient int regionX = 0; // X location value of the current region
|
||||||
|
private transient int regionZ = 0; // X location value of the current region
|
||||||
|
private transient int currentChunk = 0; // chunk we've reached in the current region (regionChunks)
|
||||||
|
private transient List<CoordXZ> regionChunks = new ArrayList<CoordXZ>(1024);
|
||||||
|
private transient List<CoordXZ> trimChunks = new ArrayList<CoordXZ>(1024);
|
||||||
|
private transient int counter = 0;
|
||||||
|
|
||||||
|
// for reporting progress back to user occasionally
|
||||||
|
private transient long lastReport = Config.Now();
|
||||||
|
private transient int reportTarget = 0;
|
||||||
|
private transient int reportTotal = 0;
|
||||||
|
private transient int reportTrimmedRegions = 0;
|
||||||
|
private transient int reportTrimmedChunks = 0;
|
||||||
|
|
||||||
|
|
||||||
public class WorldTrimTask implements Runnable
|
public WorldTrimTask(Server theServer, Player player, String worldName, int trimDistance, int chunksPerRun) {
|
||||||
{
|
this.server = theServer;
|
||||||
// general task-related reference data
|
this.notifyPlayer = player;
|
||||||
private transient Server server = null;
|
this.chunksPerRun = chunksPerRun;
|
||||||
private transient World world = null;
|
|
||||||
private transient WorldFileData worldData = null;
|
|
||||||
private transient BorderData border = null;
|
|
||||||
private transient boolean readyToGo = false;
|
|
||||||
private transient boolean paused = false;
|
|
||||||
private transient int taskID = -1;
|
|
||||||
private transient Player notifyPlayer = null;
|
|
||||||
private transient int chunksPerRun = 1;
|
|
||||||
|
|
||||||
// values for what chunk in the current region we're at
|
this.world = server.getWorld(worldName);
|
||||||
private transient int currentRegion = -1; // region(file) we're at in regionFiles
|
if (this.world == null) {
|
||||||
private transient int regionX = 0; // X location value of the current region
|
if (worldName.isEmpty())
|
||||||
private transient int regionZ = 0; // X location value of the current region
|
sendMessage("You must specify a world!");
|
||||||
private transient int currentChunk = 0; // chunk we've reached in the current region (regionChunks)
|
else
|
||||||
private transient List<CoordXZ> regionChunks = new ArrayList<CoordXZ>(1024);
|
sendMessage("World \"" + worldName + "\" not found!");
|
||||||
private transient List<CoordXZ> trimChunks = new ArrayList<CoordXZ>(1024);
|
this.stop();
|
||||||
private transient int counter = 0;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// for reporting progress back to user occasionally
|
this.border = (Config.Border(worldName) == null) ? null : Config.Border(worldName).copy();
|
||||||
private transient long lastReport = Config.Now();
|
if (this.border == null) {
|
||||||
private transient int reportTarget = 0;
|
sendMessage("No border found for world \"" + worldName + "\"!");
|
||||||
private transient int reportTotal = 0;
|
this.stop();
|
||||||
private transient int reportTrimmedRegions = 0;
|
return;
|
||||||
private transient int reportTrimmedChunks = 0;
|
}
|
||||||
|
|
||||||
|
this.border.setRadiusX(border.getRadiusX() + trimDistance);
|
||||||
|
this.border.setRadiusZ(border.getRadiusZ() + trimDistance);
|
||||||
|
|
||||||
|
worldData = WorldFileData.create(world, notifyPlayer);
|
||||||
|
if (worldData == null) {
|
||||||
|
this.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// each region file covers up to 1024 chunks; with all operations we might need to do, let's figure 3X that
|
||||||
|
this.reportTarget = worldData.regionFileCount() * 3072;
|
||||||
|
|
||||||
|
// queue up the first file
|
||||||
|
if (!nextFile())
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.readyToGo = true;
|
||||||
|
Bukkit.getServer().getPluginManager().callEvent(new WorldBorderTrimStartEvent(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTaskID(int ID) {
|
||||||
|
this.taskID = ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public WorldTrimTask(Server theServer, Player player, String worldName, int trimDistance, int chunksPerRun)
|
public void run() {
|
||||||
{
|
if (server == null || !readyToGo || paused)
|
||||||
this.server = theServer;
|
return;
|
||||||
this.notifyPlayer = player;
|
|
||||||
this.chunksPerRun = chunksPerRun;
|
|
||||||
|
|
||||||
this.world = server.getWorld(worldName);
|
// this is set so it only does one iteration at a time, no matter how frequently the timer fires
|
||||||
if (this.world == null)
|
readyToGo = false;
|
||||||
{
|
// and this is tracked to keep one iteration from dragging on too long and possibly choking the system if the user specified a really high frequency
|
||||||
if (worldName.isEmpty())
|
long loopStartTime = Config.Now();
|
||||||
sendMessage("You must specify a world!");
|
|
||||||
else
|
|
||||||
sendMessage("World \"" + worldName + "\" not found!");
|
|
||||||
this.stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.border = (Config.Border(worldName) == null) ? null : Config.Border(worldName).copy();
|
counter = 0;
|
||||||
if (this.border == null)
|
while (counter <= chunksPerRun) {
|
||||||
{
|
// in case the task has been paused while we're repeating...
|
||||||
sendMessage("No border found for world \"" + worldName + "\"!");
|
if (paused)
|
||||||
this.stop();
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.border.setRadiusX(border.getRadiusX() + trimDistance);
|
long now = Config.Now();
|
||||||
this.border.setRadiusZ(border.getRadiusZ() + trimDistance);
|
|
||||||
|
|
||||||
worldData = WorldFileData.create(world, notifyPlayer);
|
// every 5 seconds or so, give basic progress report to let user know how it's going
|
||||||
if (worldData == null)
|
if (now > lastReport + 5000)
|
||||||
{
|
reportProgress();
|
||||||
this.stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// each region file covers up to 1024 chunks; with all operations we might need to do, let's figure 3X that
|
// if this iteration has been running for 45ms (almost 1 tick) or more, stop to take a breather; shouldn't normally be possible with Trim, but just in case
|
||||||
this.reportTarget = worldData.regionFileCount() * 3072;
|
if (now > loopStartTime + 45) {
|
||||||
|
readyToGo = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// queue up the first file
|
if (regionChunks.isEmpty())
|
||||||
if (!nextFile())
|
addCornerChunks();
|
||||||
return;
|
else if (currentChunk == 4) { // determine if region is completely _inside_ border based on corner chunks
|
||||||
|
if (trimChunks.isEmpty()) { // it is, so skip it and move on to next file
|
||||||
this.readyToGo = true;
|
counter += 4;
|
||||||
Bukkit.getServer().getPluginManager().callEvent(new WorldBorderTrimStartEvent(this));
|
nextFile();
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
public void setTaskID(int ID)
|
addEdgeChunks();
|
||||||
{
|
addInnerChunks();
|
||||||
this.taskID = ID;
|
} else if (currentChunk == 124 && trimChunks.size() == 124) { // region is completely _outside_ border based on edge chunks, so delete file and move on to next
|
||||||
}
|
counter += 16;
|
||||||
|
trimChunks = regionChunks;
|
||||||
|
unloadChunks();
|
||||||
public void run()
|
reportTrimmedRegions++;
|
||||||
{
|
File regionFile = worldData.regionFile(currentRegion);
|
||||||
if (server == null || !readyToGo || paused)
|
if (!regionFile.delete()) {
|
||||||
return;
|
sendMessage("Error! Region file which is outside the border could not be deleted: " + regionFile.getName());
|
||||||
|
wipeChunks();
|
||||||
// this is set so it only does one iteration at a time, no matter how frequently the timer fires
|
} else {
|
||||||
readyToGo = false;
|
// if DynMap is installed, re-render the trimmed region ... disabled since it's not currently working, oh well
|
||||||
// and this is tracked to keep one iteration from dragging on too long and possibly choking the system if the user specified a really high frequency
|
|
||||||
long loopStartTime = Config.Now();
|
|
||||||
|
|
||||||
counter = 0;
|
|
||||||
while (counter <= chunksPerRun)
|
|
||||||
{
|
|
||||||
// in case the task has been paused while we're repeating...
|
|
||||||
if (paused)
|
|
||||||
return;
|
|
||||||
|
|
||||||
long now = Config.Now();
|
|
||||||
|
|
||||||
// every 5 seconds or so, give basic progress report to let user know how it's going
|
|
||||||
if (now > lastReport + 5000)
|
|
||||||
reportProgress();
|
|
||||||
|
|
||||||
// if this iteration has been running for 45ms (almost 1 tick) or more, stop to take a breather; shouldn't normally be possible with Trim, but just in case
|
|
||||||
if (now > loopStartTime + 45)
|
|
||||||
{
|
|
||||||
readyToGo = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (regionChunks.isEmpty())
|
|
||||||
addCornerChunks();
|
|
||||||
else if (currentChunk == 4)
|
|
||||||
{ // determine if region is completely _inside_ border based on corner chunks
|
|
||||||
if (trimChunks.isEmpty())
|
|
||||||
{ // it is, so skip it and move on to next file
|
|
||||||
counter += 4;
|
|
||||||
nextFile();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
addEdgeChunks();
|
|
||||||
addInnerChunks();
|
|
||||||
}
|
|
||||||
else if (currentChunk == 124 && trimChunks.size() == 124)
|
|
||||||
{ // region is completely _outside_ border based on edge chunks, so delete file and move on to next
|
|
||||||
counter += 16;
|
|
||||||
trimChunks = regionChunks;
|
|
||||||
unloadChunks();
|
|
||||||
reportTrimmedRegions++;
|
|
||||||
File regionFile = worldData.regionFile(currentRegion);
|
|
||||||
if (!regionFile.delete())
|
|
||||||
{
|
|
||||||
sendMessage("Error! Region file which is outside the border could not be deleted: "+regionFile.getName());
|
|
||||||
wipeChunks();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// if DynMap is installed, re-render the trimmed region ... disabled since it's not currently working, oh well
|
|
||||||
// DynMapFeatures.renderRegion(world.getName(), new CoordXZ(regionX, regionZ));
|
// DynMapFeatures.renderRegion(world.getName(), new CoordXZ(regionX, regionZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
nextFile();
|
nextFile();
|
||||||
continue;
|
continue;
|
||||||
}
|
} else if (currentChunk == 1024) { // last chunk of the region has been checked, time to wipe out whichever chunks are outside the border
|
||||||
else if (currentChunk == 1024)
|
counter += 32;
|
||||||
{ // last chunk of the region has been checked, time to wipe out whichever chunks are outside the border
|
unloadChunks();
|
||||||
counter += 32;
|
wipeChunks();
|
||||||
unloadChunks();
|
nextFile();
|
||||||
wipeChunks();
|
continue;
|
||||||
nextFile();
|
}
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check whether chunk is inside the border or not, add it to the "trim" list if not
|
// check whether chunk is inside the border or not, add it to the "trim" list if not
|
||||||
CoordXZ chunk = regionChunks.get(currentChunk);
|
CoordXZ chunk = regionChunks.get(currentChunk);
|
||||||
if (!isChunkInsideBorder(chunk))
|
if (!isChunkInsideBorder(chunk))
|
||||||
trimChunks.add(chunk);
|
trimChunks.add(chunk);
|
||||||
|
|
||||||
currentChunk++;
|
currentChunk++;
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
reportTotal += counter;
|
reportTotal += counter;
|
||||||
|
|
||||||
// ready for the next iteration to run
|
// ready for the next iteration to run
|
||||||
readyToGo = true;
|
readyToGo = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advance to the next region file. Returns true if successful, false if the next file isn't accessible for any reason
|
// Advance to the next region file. Returns true if successful, false if the next file isn't accessible for any reason
|
||||||
private boolean nextFile()
|
private boolean nextFile() {
|
||||||
{
|
reportTotal = currentRegion * 3072;
|
||||||
reportTotal = currentRegion * 3072;
|
currentRegion++;
|
||||||
currentRegion++;
|
regionX = regionZ = currentChunk = 0;
|
||||||
regionX = regionZ = currentChunk = 0;
|
regionChunks = new ArrayList<CoordXZ>(1024);
|
||||||
regionChunks = new ArrayList<CoordXZ>(1024);
|
trimChunks = new ArrayList<CoordXZ>(1024);
|
||||||
trimChunks = new ArrayList<CoordXZ>(1024);
|
|
||||||
|
|
||||||
// have we already handled all region files?
|
// have we already handled all region files?
|
||||||
if (currentRegion >= worldData.regionFileCount())
|
if (currentRegion >= worldData.regionFileCount()) { // hey, we're done
|
||||||
{ // hey, we're done
|
paused = true;
|
||||||
paused = true;
|
readyToGo = false;
|
||||||
readyToGo = false;
|
finish();
|
||||||
finish();
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
counter += 16;
|
counter += 16;
|
||||||
|
|
||||||
// get the X and Z coordinates of the current region
|
// get the X and Z coordinates of the current region
|
||||||
CoordXZ coord = worldData.regionFileCoordinates(currentRegion);
|
CoordXZ coord = worldData.regionFileCoordinates(currentRegion);
|
||||||
if (coord == null)
|
if (coord == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
regionX = coord.x;
|
regionX = coord.x;
|
||||||
regionZ = coord.z;
|
regionZ = coord.z;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add just the 4 corner chunks of the region; can determine if entire region is _inside_ the border
|
// add just the 4 corner chunks of the region; can determine if entire region is _inside_ the border
|
||||||
private void addCornerChunks()
|
private void addCornerChunks() {
|
||||||
{
|
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX), CoordXZ.regionToChunk(regionZ)));
|
||||||
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX), CoordXZ.regionToChunk(regionZ)));
|
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX) + 31, CoordXZ.regionToChunk(regionZ)));
|
||||||
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX) + 31, CoordXZ.regionToChunk(regionZ)));
|
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX), CoordXZ.regionToChunk(regionZ) + 31));
|
||||||
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX), CoordXZ.regionToChunk(regionZ) + 31));
|
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX) + 31, CoordXZ.regionToChunk(regionZ) + 31));
|
||||||
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX) + 31, CoordXZ.regionToChunk(regionZ) + 31));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// add all chunks along the 4 edges of the region (minus the corners); can determine if entire region is _outside_ the border
|
// add all chunks along the 4 edges of the region (minus the corners); can determine if entire region is _outside_ the border
|
||||||
private void addEdgeChunks()
|
private void addEdgeChunks() {
|
||||||
{
|
int chunkX = 0, chunkZ;
|
||||||
int chunkX = 0, chunkZ;
|
|
||||||
|
|
||||||
for (chunkZ = 1; chunkZ < 31; chunkZ++)
|
for (chunkZ = 1; chunkZ < 31; chunkZ++) {
|
||||||
{
|
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX) + chunkX, CoordXZ.regionToChunk(regionZ) + chunkZ));
|
||||||
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX)+chunkX, CoordXZ.regionToChunk(regionZ)+chunkZ));
|
}
|
||||||
}
|
chunkX = 31;
|
||||||
chunkX = 31;
|
for (chunkZ = 1; chunkZ < 31; chunkZ++) {
|
||||||
for (chunkZ = 1; chunkZ < 31; chunkZ++)
|
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX) + chunkX, CoordXZ.regionToChunk(regionZ) + chunkZ));
|
||||||
{
|
}
|
||||||
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX)+chunkX, CoordXZ.regionToChunk(regionZ)+chunkZ));
|
chunkZ = 0;
|
||||||
}
|
for (chunkX = 1; chunkX < 31; chunkX++) {
|
||||||
chunkZ = 0;
|
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX) + chunkX, CoordXZ.regionToChunk(regionZ) + chunkZ));
|
||||||
for (chunkX = 1; chunkX < 31; chunkX++)
|
}
|
||||||
{
|
chunkZ = 31;
|
||||||
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX)+chunkX, CoordXZ.regionToChunk(regionZ)+chunkZ));
|
for (chunkX = 1; chunkX < 31; chunkX++) {
|
||||||
}
|
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX) + chunkX, CoordXZ.regionToChunk(regionZ) + chunkZ));
|
||||||
chunkZ = 31;
|
}
|
||||||
for (chunkX = 1; chunkX < 31; chunkX++)
|
counter += 4;
|
||||||
{
|
}
|
||||||
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX)+chunkX, CoordXZ.regionToChunk(regionZ)+chunkZ));
|
|
||||||
}
|
|
||||||
counter += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the remaining interior chunks (after corners and edges)
|
// add the remaining interior chunks (after corners and edges)
|
||||||
private void addInnerChunks()
|
private void addInnerChunks() {
|
||||||
{
|
for (int chunkX = 1; chunkX < 31; chunkX++) {
|
||||||
for (int chunkX = 1; chunkX < 31; chunkX++)
|
for (int chunkZ = 1; chunkZ < 31; chunkZ++) {
|
||||||
{
|
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX) + chunkX, CoordXZ.regionToChunk(regionZ) + chunkZ));
|
||||||
for (int chunkZ = 1; chunkZ < 31; chunkZ++)
|
}
|
||||||
{
|
}
|
||||||
regionChunks.add(new CoordXZ(CoordXZ.regionToChunk(regionX)+chunkX, CoordXZ.regionToChunk(regionZ)+chunkZ));
|
counter += 32;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
counter += 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure chunks set to be trimmed are not currently loaded by the server
|
// make sure chunks set to be trimmed are not currently loaded by the server
|
||||||
private void unloadChunks()
|
private void unloadChunks() {
|
||||||
{
|
for (CoordXZ unload : trimChunks) {
|
||||||
for (CoordXZ unload : trimChunks)
|
if (world.isChunkLoaded(unload.x, unload.z))
|
||||||
{
|
world.unloadChunk(unload.x, unload.z, false);
|
||||||
if (world.isChunkLoaded(unload.x, unload.z))
|
}
|
||||||
world.unloadChunk(unload.x, unload.z, false);
|
counter += trimChunks.size();
|
||||||
}
|
}
|
||||||
counter += trimChunks.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
// edit region file to wipe all chunk pointers for chunks outside the border
|
// edit region file to wipe all chunk pointers for chunks outside the border
|
||||||
private void wipeChunks()
|
private void wipeChunks() {
|
||||||
{
|
File regionFile = worldData.regionFile(currentRegion);
|
||||||
File regionFile = worldData.regionFile(currentRegion);
|
if (!regionFile.canWrite()) {
|
||||||
if (!regionFile.canWrite())
|
if (!regionFile.setWritable(true))
|
||||||
{
|
throw new RuntimeException();
|
||||||
if (!regionFile.setWritable(true))
|
|
||||||
throw new RuntimeException();
|
|
||||||
|
|
||||||
if (!regionFile.canWrite())
|
if (!regionFile.canWrite()) {
|
||||||
{
|
sendMessage("Error! region file is locked and can't be trimmed: " + regionFile.getName());
|
||||||
sendMessage("Error! region file is locked and can't be trimmed: "+regionFile.getName());
|
return;
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// since our stored chunk positions are based on world, we need to offset those to positions in the region file
|
// since our stored chunk positions are based on world, we need to offset those to positions in the region file
|
||||||
int offsetX = CoordXZ.regionToChunk(regionX);
|
int offsetX = CoordXZ.regionToChunk(regionX);
|
||||||
int offsetZ = CoordXZ.regionToChunk(regionZ);
|
int offsetZ = CoordXZ.regionToChunk(regionZ);
|
||||||
long wipePos = 0;
|
long wipePos = 0;
|
||||||
int chunkCount = 0;
|
int chunkCount = 0;
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
RandomAccessFile unChunk = new RandomAccessFile(regionFile, "rwd");
|
||||||
RandomAccessFile unChunk = new RandomAccessFile(regionFile, "rwd");
|
for (CoordXZ wipe : trimChunks) {
|
||||||
for (CoordXZ wipe : trimChunks)
|
// if the chunk pointer is empty (chunk doesn't technically exist), no need to wipe the already empty pointer
|
||||||
{
|
if (!worldData.doesChunkExist(wipe.x, wipe.z))
|
||||||
// if the chunk pointer is empty (chunk doesn't technically exist), no need to wipe the already empty pointer
|
continue;
|
||||||
if (!worldData.doesChunkExist(wipe.x, wipe.z))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// wipe this extraneous chunk's pointer... note that this method isn't perfect since the actual chunk data is left orphaned,
|
// wipe this extraneous chunk's pointer... note that this method isn't perfect since the actual chunk data is left orphaned,
|
||||||
// but Minecraft will overwrite the orphaned data sector if/when another chunk is created in the region, so it's not so bad
|
// but Minecraft will overwrite the orphaned data sector if/when another chunk is created in the region, so it's not so bad
|
||||||
wipePos = 4 * ((wipe.x - offsetX) + ((wipe.z - offsetZ) * 32));
|
wipePos = 4 * ((wipe.x - offsetX) + ((wipe.z - offsetZ) * 32));
|
||||||
unChunk.seek(wipePos);
|
unChunk.seek(wipePos);
|
||||||
unChunk.writeInt(0);
|
unChunk.writeInt(0);
|
||||||
chunkCount++;
|
chunkCount++;
|
||||||
}
|
}
|
||||||
unChunk.close();
|
unChunk.close();
|
||||||
|
|
||||||
// if DynMap is installed, re-render the trimmed chunks ... disabled since it's not currently working, oh well
|
// if DynMap is installed, re-render the trimmed chunks ... disabled since it's not currently working, oh well
|
||||||
// DynMapFeatures.renderChunks(world.getName(), trimChunks);
|
// DynMapFeatures.renderChunks(world.getName(), trimChunks);
|
||||||
|
|
||||||
reportTrimmedChunks += chunkCount;
|
reportTrimmedChunks += chunkCount;
|
||||||
}
|
} catch (FileNotFoundException ex) {
|
||||||
catch (FileNotFoundException ex)
|
sendMessage("Error! Could not open region file to wipe individual chunks: " + regionFile.getName());
|
||||||
{
|
} catch (IOException ex) {
|
||||||
sendMessage("Error! Could not open region file to wipe individual chunks: "+regionFile.getName());
|
sendMessage("Error! Could not modify region file to wipe individual chunks: " + regionFile.getName());
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
counter += trimChunks.size();
|
||||||
{
|
}
|
||||||
sendMessage("Error! Could not modify region file to wipe individual chunks: "+regionFile.getName());
|
|
||||||
}
|
|
||||||
counter += trimChunks.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isChunkInsideBorder(CoordXZ chunk)
|
private boolean isChunkInsideBorder(CoordXZ chunk) {
|
||||||
{
|
return border.insideBorder(CoordXZ.chunkToBlock(chunk.x) + 8, CoordXZ.chunkToBlock(chunk.z) + 8);
|
||||||
return border.insideBorder(CoordXZ.chunkToBlock(chunk.x) + 8, CoordXZ.chunkToBlock(chunk.z) + 8);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// for successful completion
|
// for successful completion
|
||||||
public void finish()
|
public void finish() {
|
||||||
{
|
reportTotal = reportTarget;
|
||||||
reportTotal = reportTarget;
|
reportProgress();
|
||||||
reportProgress();
|
Bukkit.getServer().getPluginManager().callEvent(new WorldBorderTrimFinishedEvent(world, reportTotal));
|
||||||
Bukkit.getServer().getPluginManager().callEvent(new WorldBorderTrimFinishedEvent(world, reportTotal));
|
sendMessage("task successfully completed!");
|
||||||
sendMessage("task successfully completed!");
|
this.stop();
|
||||||
this.stop();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// for cancelling prematurely
|
// for cancelling prematurely
|
||||||
public void cancel()
|
public void cancel() {
|
||||||
{
|
this.stop();
|
||||||
this.stop();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// we're done, whether finished or cancelled
|
// we're done, whether finished or cancelled
|
||||||
private void stop()
|
private void stop() {
|
||||||
{
|
if (server == null)
|
||||||
if (server == null)
|
return;
|
||||||
return;
|
|
||||||
|
|
||||||
readyToGo = false;
|
readyToGo = false;
|
||||||
if (taskID != -1)
|
if (taskID != -1)
|
||||||
server.getScheduler().cancelTask(taskID);
|
server.getScheduler().cancelTask(taskID);
|
||||||
server = null;
|
server = null;
|
||||||
|
|
||||||
sendMessage("NOTICE: it is recommended that you restart your server after a Trim, to be on the safe side.");
|
sendMessage("NOTICE: it is recommended that you restart your server after a Trim, to be on the safe side.");
|
||||||
if (DynMapFeatures.renderEnabled())
|
if (DynMapFeatures.renderEnabled())
|
||||||
sendMessage("This especially true with DynMap. You should also run a fullrender in DynMap for the trimmed world after restarting, so trimmed chunks are updated on the map.");
|
sendMessage("This especially true with DynMap. You should also run a fullrender in DynMap for the trimmed world after restarting, so trimmed chunks are updated on the map.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// is this task still valid/workable?
|
// is this task still valid/workable?
|
||||||
public boolean valid()
|
public boolean valid() {
|
||||||
{
|
return this.server != null;
|
||||||
return this.server != null;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// handle pausing/unpausing the task
|
// handle pausing/unpausing the task
|
||||||
public void pause()
|
public void pause() {
|
||||||
{
|
pause(!this.paused);
|
||||||
pause(!this.paused);
|
}
|
||||||
}
|
|
||||||
public void pause(boolean pause)
|
|
||||||
{
|
|
||||||
this.paused = pause;
|
|
||||||
if (pause)
|
|
||||||
reportProgress();
|
|
||||||
}
|
|
||||||
public boolean isPaused()
|
|
||||||
{
|
|
||||||
return this.paused;
|
|
||||||
}
|
|
||||||
|
|
||||||
// let the user know how things are coming along
|
public void pause(boolean pause) {
|
||||||
private void reportProgress()
|
this.paused = pause;
|
||||||
{
|
if (pause)
|
||||||
lastReport = Config.Now();
|
reportProgress();
|
||||||
double perc = getPercentageCompleted();
|
}
|
||||||
sendMessage(reportTrimmedRegions + " entire region(s) and " + reportTrimmedChunks + " individual chunk(s) trimmed so far (" + Config.coord.format(perc) + "% done" + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
// send a message to the server console/log and possibly to an in-game player
|
public boolean isPaused() {
|
||||||
private void sendMessage(String text)
|
return this.paused;
|
||||||
{
|
}
|
||||||
Config.log("[Trim] " + text);
|
|
||||||
if (notifyPlayer != null)
|
|
||||||
notifyPlayer.sendMessage("[Trim] " + text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// let the user know how things are coming along
|
||||||
* Get the percentage completed for the trim task.
|
private void reportProgress() {
|
||||||
*
|
lastReport = Config.Now();
|
||||||
* @return Percentage
|
double perc = getPercentageCompleted();
|
||||||
*/
|
sendMessage(reportTrimmedRegions + " entire region(s) and " + reportTrimmedChunks + " individual chunk(s) trimmed so far (" + Config.coord.format(perc) + "% done" + ")");
|
||||||
public double getPercentageCompleted() {
|
}
|
||||||
return ((double) (reportTotal) / (double) reportTarget) * 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// send a message to the server console/log and possibly to an in-game player
|
||||||
* Amount of chunks completed for the trim task.
|
private void sendMessage(String text) {
|
||||||
*
|
Config.log("[Trim] " + text);
|
||||||
* @return Number of chunks processed.
|
if (notifyPlayer != null)
|
||||||
*/
|
notifyPlayer.sendMessage("[Trim] " + text);
|
||||||
public int getChunksCompleted() {
|
}
|
||||||
return reportTotal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Total amount of chunks that need to be trimmed for the trim task.
|
* Get the percentage completed for the trim task.
|
||||||
*
|
*
|
||||||
* @return Number of chunks that need to be processed.
|
* @return Percentage
|
||||||
*/
|
*/
|
||||||
public int getChunksTotal() {
|
public double getPercentageCompleted() {
|
||||||
return reportTarget;
|
return ((double) (reportTotal) / (double) reportTarget) * 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Amount of chunks completed for the trim task.
|
||||||
|
*
|
||||||
|
* @return Number of chunks processed.
|
||||||
|
*/
|
||||||
|
public int getChunksCompleted() {
|
||||||
|
return reportTotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total amount of chunks that need to be trimmed for the trim task.
|
||||||
|
*
|
||||||
|
* @return Number of chunks that need to be processed.
|
||||||
|
*/
|
||||||
|
public int getChunksTotal() {
|
||||||
|
return reportTarget;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,100 +1,85 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import com.wimbli.WorldBorder.UUID.UUIDFetcher;
|
||||||
|
import com.wimbli.WorldBorder.WorldBorder;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdBypass extends WBCmd {
|
||||||
import com.wimbli.WorldBorder.UUID.UUIDFetcher;
|
public CmdBypass() {
|
||||||
|
name = permission = "bypass";
|
||||||
|
minParams = 0;
|
||||||
|
maxParams = 2;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "{player} [on|off] - let player go beyond border.");
|
||||||
|
helpText = "If [player] isn't specified, command sender is used. If [on|off] isn't specified, the value will " +
|
||||||
|
"be toggled. Once bypass is enabled, the player will not be stopped by any borders until bypass is " +
|
||||||
|
"disabled for them again. Use the " + commandEmphasized("bypasslist") + C_DESC + "command to list all " +
|
||||||
|
"players with bypass enabled.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdBypass extends WBCmd
|
@Override
|
||||||
{
|
public void cmdStatus(CommandSender sender) {
|
||||||
public CmdBypass()
|
if (!(sender instanceof Player))
|
||||||
{
|
return;
|
||||||
name = permission = "bypass";
|
|
||||||
minParams = 0;
|
|
||||||
maxParams = 2;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "{player} [on|off] - let player go beyond border.");
|
boolean bypass = Config.isPlayerBypassing(((Player) sender).getUniqueId());
|
||||||
helpText = "If [player] isn't specified, command sender is used. If [on|off] isn't specified, the value will " +
|
sender.sendMessage(C_HEAD + "Border bypass is currently " + enabledColored(bypass) + C_HEAD + " for you.");
|
||||||
"be toggled. Once bypass is enabled, the player will not be stopped by any borders until bypass is " +
|
}
|
||||||
"disabled for them again. Use the " + commandEmphasized("bypasslist") + C_DESC + "command to list all " +
|
|
||||||
"players with bypass enabled.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cmdStatus(CommandSender sender)
|
public void execute(final CommandSender sender, final Player player, final List<String> params, String worldName) {
|
||||||
{
|
if (player == null && params.isEmpty()) {
|
||||||
if (!(sender instanceof Player))
|
sendErrorAndHelp(sender, "When running this command from console, you must specify a player.");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
boolean bypass = Config.isPlayerBypassing(((Player)sender).getUniqueId());
|
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(WorldBorder.plugin, new Runnable() {
|
||||||
sender.sendMessage(C_HEAD + "Border bypass is currently " + enabledColored(bypass) + C_HEAD + " for you.");
|
@Override
|
||||||
}
|
public void run() {
|
||||||
|
final String sPlayer = (params.isEmpty()) ? player.getName() : params.get(0);
|
||||||
|
UUID uPlayer = (params.isEmpty()) ? player.getUniqueId() : null;
|
||||||
|
|
||||||
@Override
|
if (uPlayer == null) {
|
||||||
public void execute(final CommandSender sender, final Player player, final List<String> params, String worldName)
|
Player p = Bukkit.getPlayer(sPlayer);
|
||||||
{
|
if (p != null) {
|
||||||
if (player == null && params.isEmpty())
|
uPlayer = p.getUniqueId();
|
||||||
{
|
} else {
|
||||||
sendErrorAndHelp(sender, "When running this command from console, you must specify a player.");
|
// only do UUID lookup using Mojang server if specified player isn't online
|
||||||
return;
|
try {
|
||||||
}
|
uPlayer = UUIDFetcher.getUUID(sPlayer);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
sendErrorAndHelp(sender, "Failed to look up UUID for the player name you specified. " + ex.getLocalizedMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (uPlayer == null) {
|
||||||
|
sendErrorAndHelp(sender, "Failed to look up UUID for the player name you specified; null value returned.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(WorldBorder.plugin, new Runnable()
|
boolean bypassing = !Config.isPlayerBypassing(uPlayer);
|
||||||
{
|
if (params.size() > 1)
|
||||||
@Override
|
bypassing = strAsBool(params.get(1));
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
final String sPlayer = (params.isEmpty()) ? player.getName() : params.get(0);
|
|
||||||
UUID uPlayer = (params.isEmpty()) ? player.getUniqueId() : null;
|
|
||||||
|
|
||||||
if (uPlayer == null)
|
Config.setPlayerBypass(uPlayer, bypassing);
|
||||||
{
|
|
||||||
Player p = Bukkit.getPlayer(sPlayer);
|
|
||||||
if (p != null)
|
|
||||||
{
|
|
||||||
uPlayer = p.getUniqueId();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// only do UUID lookup using Mojang server if specified player isn't online
|
|
||||||
try
|
|
||||||
{
|
|
||||||
uPlayer = UUIDFetcher.getUUID(sPlayer);
|
|
||||||
}
|
|
||||||
catch(Exception ex)
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "Failed to look up UUID for the player name you specified. " + ex.getLocalizedMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (uPlayer == null)
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "Failed to look up UUID for the player name you specified; null value returned.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean bypassing = !Config.isPlayerBypassing(uPlayer);
|
Player target = Bukkit.getPlayer(sPlayer);
|
||||||
if (params.size() > 1)
|
if (target != null && target.isOnline())
|
||||||
bypassing = strAsBool(params.get(1));
|
target.sendMessage("Border bypass is now " + enabledColored(bypassing) + ".");
|
||||||
|
|
||||||
Config.setPlayerBypass(uPlayer, bypassing);
|
Config.log("Border bypass for player \"" + sPlayer + "\" is " + (bypassing ? "enabled" : "disabled") +
|
||||||
|
(player != null ? " at the command of player \"" + player.getName() + "\"" : "") + ".");
|
||||||
Player target = Bukkit.getPlayer(sPlayer);
|
if (player != null && player != target)
|
||||||
if (target != null && target.isOnline())
|
sender.sendMessage("Border bypass for player \"" + sPlayer + "\" is " + enabledColored(bypassing) + ".");
|
||||||
target.sendMessage("Border bypass is now " + enabledColored(bypassing) + ".");
|
}
|
||||||
|
});
|
||||||
Config.log("Border bypass for player \"" + sPlayer + "\" is " + (bypassing ? "enabled" : "disabled") +
|
}
|
||||||
(player != null ? " at the command of player \"" + player.getName() + "\"" : "") + ".");
|
|
||||||
if (player != null && player != target)
|
|
||||||
sender.sendMessage("Border bypass for player \"" + sPlayer + "\" is " + enabledColored(bypassing) + ".");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,58 +1,49 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import com.wimbli.WorldBorder.UUID.UUIDFetcher;
|
||||||
|
import com.wimbli.WorldBorder.WorldBorder;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdBypasslist extends WBCmd {
|
||||||
import com.wimbli.WorldBorder.UUID.UUIDFetcher;
|
public CmdBypasslist() {
|
||||||
|
name = permission = "bypasslist";
|
||||||
|
minParams = maxParams = 0;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "- list players with border bypass enabled.");
|
||||||
|
helpText = "The bypass list will persist between server restarts, and applies to all worlds. Use the " +
|
||||||
|
commandEmphasized("bypass") + C_DESC + "command to add or remove players.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdBypasslist extends WBCmd
|
@Override
|
||||||
{
|
public void execute(final CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
public CmdBypasslist()
|
final ArrayList<UUID> uuids = Config.getPlayerBypassList();
|
||||||
{
|
if (uuids == null || uuids.isEmpty()) {
|
||||||
name = permission = "bypasslist";
|
sender.sendMessage("Players with border bypass enabled: <none>");
|
||||||
minParams = maxParams = 0;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "- list players with border bypass enabled.");
|
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(WorldBorder.plugin, new Runnable() {
|
||||||
helpText = "The bypass list will persist between server restarts, and applies to all worlds. Use the " +
|
@Override
|
||||||
commandEmphasized("bypass") + C_DESC + "command to add or remove players.";
|
public void run() {
|
||||||
}
|
try {
|
||||||
|
Map<UUID, String> names = UUIDFetcher.getNameList(uuids);
|
||||||
|
String nameString = names.values().toString();
|
||||||
|
|
||||||
@Override
|
sender.sendMessage("Players with border bypass enabled: " + nameString.substring(1, nameString.length() - 1));
|
||||||
public void execute(final CommandSender sender, Player player, List<String> params, String worldName)
|
} catch (Exception ex) {
|
||||||
{
|
sendErrorAndHelp(sender, "Failed to look up names for the UUIDs in the border bypass list. " + ex.getLocalizedMessage());
|
||||||
final ArrayList<UUID> uuids = Config.getPlayerBypassList();
|
return;
|
||||||
if (uuids == null || uuids.isEmpty())
|
}
|
||||||
{
|
}
|
||||||
sender.sendMessage("Players with border bypass enabled: <none>");
|
});
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(WorldBorder.plugin, new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Map<UUID, String> names = UUIDFetcher.getNameList(uuids);
|
|
||||||
String nameString = names.values().toString();
|
|
||||||
|
|
||||||
sender.sendMessage("Players with border bypass enabled: " + nameString.substring(1, nameString.length() - 1));
|
|
||||||
}
|
|
||||||
catch(Exception ex)
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "Failed to look up names for the UUIDs in the border bypass list. " + ex.getLocalizedMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,68 +1,60 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.BorderData;
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdClear extends WBCmd {
|
||||||
|
public CmdClear() {
|
||||||
|
name = permission = "clear";
|
||||||
|
hasWorldNameInput = true;
|
||||||
|
consoleRequiresWorldName = false;
|
||||||
|
minParams = 0;
|
||||||
|
maxParams = 1;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasizedW() + "- remove border for this world.");
|
||||||
|
addCmdExample(nameEmphasized() + "^all - remove border for all worlds.");
|
||||||
|
helpText = "If run by an in-game player and [world] or \"all\" isn't specified, the world you are currently " +
|
||||||
|
"in is used.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdClear extends WBCmd
|
@Override
|
||||||
{
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
public CmdClear()
|
// handle "clear all" command separately
|
||||||
{
|
if (params.size() == 1 && params.get(0).equalsIgnoreCase("all")) {
|
||||||
name = permission = "clear";
|
if (worldName != null) {
|
||||||
hasWorldNameInput = true;
|
sendErrorAndHelp(sender, "You should not specify a world with \"clear all\".");
|
||||||
consoleRequiresWorldName = false;
|
return;
|
||||||
minParams = 0;
|
}
|
||||||
maxParams = 1;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasizedW() + "- remove border for this world.");
|
Config.removeAllBorders();
|
||||||
addCmdExample(nameEmphasized() + "^all - remove border for all worlds.");
|
|
||||||
helpText = "If run by an in-game player and [world] or \"all\" isn't specified, the world you are currently " +
|
|
||||||
"in is used.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (player != null)
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
sender.sendMessage("All borders have been cleared for all worlds.");
|
||||||
{
|
return;
|
||||||
// handle "clear all" command separately
|
}
|
||||||
if (params.size() == 1 && params.get(0).equalsIgnoreCase("all"))
|
|
||||||
{
|
|
||||||
if (worldName != null)
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "You should not specify a world with \"clear all\".");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Config.removeAllBorders();
|
if (worldName == null) {
|
||||||
|
if (player == null) {
|
||||||
|
sendErrorAndHelp(sender, "You must specify a world name from console if not using \"clear all\".");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
worldName = player.getWorld().getName();
|
||||||
|
}
|
||||||
|
|
||||||
if (player != null)
|
BorderData border = Config.Border(worldName);
|
||||||
sender.sendMessage("All borders have been cleared for all worlds.");
|
if (border == null) {
|
||||||
return;
|
sendErrorAndHelp(sender, "This world (\"" + worldName + "\") does not have a border set.");
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (worldName == null)
|
Config.removeBorder(worldName);
|
||||||
{
|
|
||||||
if (player == null)
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "You must specify a world name from console if not using \"clear all\".");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
worldName = player.getWorld().getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
BorderData border = Config.Border(worldName);
|
if (player != null)
|
||||||
if (border == null)
|
sender.sendMessage("Border cleared for world \"" + worldName + "\".");
|
||||||
{
|
}
|
||||||
sendErrorAndHelp(sender, "This world (\"" + worldName + "\") does not have a border set.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Config.removeBorder(worldName);
|
|
||||||
|
|
||||||
if (player != null)
|
|
||||||
sender.sendMessage("Border cleared for world \"" + worldName + "\".");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,74 +1,63 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.WorldBorder;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdCommands extends WBCmd {
|
||||||
|
private static int pageSize = 8; // examples to list per page; 10 lines available, 1 for header, 1 for footer
|
||||||
|
|
||||||
|
public CmdCommands() {
|
||||||
|
name = "commands";
|
||||||
|
permission = "help";
|
||||||
|
hasWorldNameInput = false;
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdCommands extends WBCmd
|
@Override
|
||||||
{
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
private static int pageSize = 8; // examples to list per page; 10 lines available, 1 for header, 1 for footer
|
// determine which page we're viewing
|
||||||
|
int page = (player == null) ? 0 : 1;
|
||||||
|
if (!params.isEmpty()) {
|
||||||
|
try {
|
||||||
|
page = Integer.parseInt(params.get(0));
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public CmdCommands()
|
// see whether we're showing examples to player or to console, and determine number of pages available
|
||||||
{
|
List<String> examples = (player == null) ? cmdExamplesConsole : cmdExamplesPlayer;
|
||||||
name = "commands";
|
int pageCount = (int) Math.ceil(examples.size() / (double) pageSize);
|
||||||
permission = "help";
|
|
||||||
hasWorldNameInput = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
// if specified page number is negative or higher than we have available, default back to first page
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
if (page < 0 || page > pageCount)
|
||||||
{
|
page = (player == null) ? 0 : 1;
|
||||||
// determine which page we're viewing
|
|
||||||
int page = (player == null) ? 0 : 1;
|
|
||||||
if (!params.isEmpty())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
page = Integer.parseInt(params.get(0));
|
|
||||||
}
|
|
||||||
catch(NumberFormatException ignored) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// see whether we're showing examples to player or to console, and determine number of pages available
|
// send command example header
|
||||||
List<String> examples = (player == null) ? cmdExamplesConsole : cmdExamplesPlayer;
|
sender.sendMessage(C_HEAD + WorldBorder.plugin.getDescription().getFullName() + " - key: " +
|
||||||
int pageCount = (int) Math.ceil(examples.size() / (double) pageSize);
|
commandEmphasized("command") + C_REQ + "<required> " + C_OPT + "[optional]");
|
||||||
|
|
||||||
// if specified page number is negative or higher than we have available, default back to first page
|
if (page > 0) {
|
||||||
if (page < 0 || page > pageCount)
|
// send examples for this page
|
||||||
page = (player == null) ? 0 : 1;
|
int first = ((page - 1) * pageSize);
|
||||||
|
int count = Math.min(pageSize, examples.size() - first);
|
||||||
|
for (int i = first; i < first + count; i++) {
|
||||||
|
sender.sendMessage(examples.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
// send command example header
|
// send page footer, if relevant; manual spacing to get right side lined up near edge is crude, but sufficient
|
||||||
sender.sendMessage( C_HEAD + WorldBorder.plugin.getDescription().getFullName() + " - key: " +
|
String footer = C_HEAD + " (Page " + page + "/" + pageCount + ") " + cmd(sender);
|
||||||
commandEmphasized("command") + C_REQ + "<required> " + C_OPT + "[optional]" );
|
if (page < pageCount)
|
||||||
|
sender.sendMessage(footer + Integer.toString(page + 1) + C_DESC + " - view next page of commands.");
|
||||||
if (page > 0)
|
else if (page > 1)
|
||||||
{
|
sender.sendMessage(footer + C_DESC + "- view first page of commands.");
|
||||||
// send examples for this page
|
} else {
|
||||||
int first = ((page - 1) * pageSize);
|
// if page "0" is specified, send all examples; done by default for console but can be specified by player
|
||||||
int count = Math.min(pageSize, examples.size() - first);
|
for (String example : examples) {
|
||||||
for(int i = first; i < first + count; i++)
|
sender.sendMessage(example);
|
||||||
{
|
}
|
||||||
sender.sendMessage(examples.get(i));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// send page footer, if relevant; manual spacing to get right side lined up near edge is crude, but sufficient
|
|
||||||
String footer = C_HEAD + " (Page " + page + "/" + pageCount + ") " + cmd(sender);
|
|
||||||
if (page < pageCount)
|
|
||||||
sender.sendMessage(footer + Integer.toString(page + 1) + C_DESC + " - view next page of commands.");
|
|
||||||
else if (page > 1)
|
|
||||||
sender.sendMessage(footer + C_DESC + "- view first page of commands.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// if page "0" is specified, send all examples; done by default for console but can be specified by player
|
|
||||||
for (String example : examples)
|
|
||||||
{
|
|
||||||
sender.sendMessage(example);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,40 +1,34 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdDebug extends WBCmd {
|
||||||
|
public CmdDebug() {
|
||||||
|
name = permission = "debug";
|
||||||
|
minParams = maxParams = 1;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "<on|off> - turn console debug output on or off.");
|
||||||
|
helpText = "Default value: off. Debug mode will show some extra debugging data in the server console/log when " +
|
||||||
|
"players are knocked back from the border or are teleported.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdDebug extends WBCmd
|
@Override
|
||||||
{
|
public void cmdStatus(CommandSender sender) {
|
||||||
public CmdDebug()
|
sender.sendMessage(C_HEAD + "Debug mode is " + enabledColored(Config.Debug()) + C_HEAD + ".");
|
||||||
{
|
}
|
||||||
name = permission = "debug";
|
|
||||||
minParams = maxParams = 1;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "<on|off> - turn console debug output on or off.");
|
@Override
|
||||||
helpText = "Default value: off. Debug mode will show some extra debugging data in the server console/log when " +
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
"players are knocked back from the border or are teleported.";
|
Config.setDebug(strAsBool(params.get(0)));
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (player != null) {
|
||||||
public void cmdStatus(CommandSender sender)
|
Config.log((Config.Debug() ? "Enabled" : "Disabled") + " debug output at the command of player \"" + player.getName() + "\".");
|
||||||
{
|
cmdStatus(sender);
|
||||||
sender.sendMessage(C_HEAD + "Debug mode is " + enabledColored(Config.Debug()) + C_HEAD + ".");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
|
||||||
{
|
|
||||||
Config.setDebug(strAsBool(params.get(0)));
|
|
||||||
|
|
||||||
if (player != null)
|
|
||||||
{
|
|
||||||
Config.log((Config.Debug() ? "Enabled" : "Disabled") + " debug output at the command of player \"" + player.getName() + "\".");
|
|
||||||
cmdStatus(sender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,51 +1,43 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdDelay extends WBCmd {
|
||||||
|
public CmdDelay() {
|
||||||
|
name = permission = "delay";
|
||||||
|
minParams = maxParams = 1;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "<amount> - time between border checks.");
|
||||||
|
helpText = "Default value: 5. The <amount> is in server ticks, of which there are roughly 20 every second, each " +
|
||||||
|
"tick taking ~50ms. The default value therefore has border checks run about 4 times per second.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdDelay extends WBCmd
|
@Override
|
||||||
{
|
public void cmdStatus(CommandSender sender) {
|
||||||
public CmdDelay()
|
int delay = Config.TimerTicks();
|
||||||
{
|
sender.sendMessage(C_HEAD + "Timer delay is set to " + delay + " tick(s). That is roughly " + (delay * 50) + "ms.");
|
||||||
name = permission = "delay";
|
}
|
||||||
minParams = maxParams = 1;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "<amount> - time between border checks.");
|
@Override
|
||||||
helpText = "Default value: 5. The <amount> is in server ticks, of which there are roughly 20 every second, each " +
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
"tick taking ~50ms. The default value therefore has border checks run about 4 times per second.";
|
int delay = 0;
|
||||||
}
|
try {
|
||||||
|
delay = Integer.parseInt(params.get(0));
|
||||||
|
if (delay < 1)
|
||||||
|
throw new NumberFormatException();
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
sendErrorAndHelp(sender, "The timer delay must be an integer of 1 or higher.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
Config.setTimerTicks(delay);
|
||||||
public void cmdStatus(CommandSender sender)
|
|
||||||
{
|
|
||||||
int delay = Config.TimerTicks();
|
|
||||||
sender.sendMessage(C_HEAD + "Timer delay is set to " + delay + " tick(s). That is roughly " + (delay * 50) + "ms.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (player != null)
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
cmdStatus(sender);
|
||||||
{
|
}
|
||||||
int delay = 0;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
delay = Integer.parseInt(params.get(0));
|
|
||||||
if (delay < 1)
|
|
||||||
throw new NumberFormatException();
|
|
||||||
}
|
|
||||||
catch(NumberFormatException ex)
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "The timer delay must be an integer of 1 or higher.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Config.setTimerTicks(delay);
|
|
||||||
|
|
||||||
if (player != null)
|
|
||||||
cmdStatus(sender);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,42 +1,36 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdDenypearl extends WBCmd {
|
||||||
|
public CmdDenypearl() {
|
||||||
|
name = permission = "denypearl";
|
||||||
|
minParams = maxParams = 1;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "<on|off> - stop ender pearls past the border.");
|
||||||
|
helpText = "Default value: on. When enabled, this setting will directly cancel attempts to use an ender pearl to " +
|
||||||
|
"get past the border rather than just knocking the player back. This should prevent usage of ender " +
|
||||||
|
"pearls to glitch into areas otherwise inaccessible at the border edge.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdDenypearl extends WBCmd
|
@Override
|
||||||
{
|
public void cmdStatus(CommandSender sender) {
|
||||||
public CmdDenypearl()
|
sender.sendMessage(C_HEAD + "Direct cancellation of ender pearls thrown past the border is " +
|
||||||
{
|
enabledColored(Config.getDenyEnderpearl()) + C_HEAD + ".");
|
||||||
name = permission = "denypearl";
|
}
|
||||||
minParams = maxParams = 1;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "<on|off> - stop ender pearls past the border.");
|
@Override
|
||||||
helpText = "Default value: on. When enabled, this setting will directly cancel attempts to use an ender pearl to " +
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
"get past the border rather than just knocking the player back. This should prevent usage of ender " +
|
Config.setDenyEnderpearl(strAsBool(params.get(0)));
|
||||||
"pearls to glitch into areas otherwise inaccessible at the border edge.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (player != null) {
|
||||||
public void cmdStatus(CommandSender sender)
|
Config.log((Config.getDenyEnderpearl() ? "Enabled" : "Disabled") + " direct cancellation of ender pearls thrown past the border at the command of player \"" + player.getName() + "\".");
|
||||||
{
|
cmdStatus(sender);
|
||||||
sender.sendMessage(C_HEAD + "Direct cancellation of ender pearls thrown past the border is " +
|
}
|
||||||
enabledColored(Config.getDenyEnderpearl()) + C_HEAD + ".");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
|
||||||
{
|
|
||||||
Config.setDenyEnderpearl(strAsBool(params.get(0)));
|
|
||||||
|
|
||||||
if (player != null)
|
|
||||||
{
|
|
||||||
Config.log((Config.getDenyEnderpearl() ? "Enabled" : "Disabled") + " direct cancellation of ender pearls thrown past the border at the command of player \"" + player.getName() + "\".");
|
|
||||||
cmdStatus(sender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,40 +1,34 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdDynmap extends WBCmd {
|
||||||
|
public CmdDynmap() {
|
||||||
|
name = permission = "dynmap";
|
||||||
|
minParams = maxParams = 1;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "<on|off> - turn DynMap border display on or off.");
|
||||||
|
helpText = "Default value: on. If you are running the DynMap plugin and this setting is enabled, all borders will " +
|
||||||
|
"be visually shown in DynMap.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdDynmap extends WBCmd
|
@Override
|
||||||
{
|
public void cmdStatus(CommandSender sender) {
|
||||||
public CmdDynmap()
|
sender.sendMessage(C_HEAD + "DynMap border display is " + enabledColored(Config.DynmapBorderEnabled()) + C_HEAD + ".");
|
||||||
{
|
}
|
||||||
name = permission = "dynmap";
|
|
||||||
minParams = maxParams = 1;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "<on|off> - turn DynMap border display on or off.");
|
@Override
|
||||||
helpText = "Default value: on. If you are running the DynMap plugin and this setting is enabled, all borders will " +
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
"be visually shown in DynMap.";
|
Config.setDynmapBorderEnabled(strAsBool(params.get(0)));
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (player != null) {
|
||||||
public void cmdStatus(CommandSender sender)
|
cmdStatus(sender);
|
||||||
{
|
Config.log((Config.DynmapBorderEnabled() ? "Enabled" : "Disabled") + " DynMap border display at the command of player \"" + player.getName() + "\".");
|
||||||
sender.sendMessage(C_HEAD + "DynMap border display is " + enabledColored(Config.DynmapBorderEnabled()) + C_HEAD + ".");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
|
||||||
{
|
|
||||||
Config.setDynmapBorderEnabled(strAsBool(params.get(0)));
|
|
||||||
|
|
||||||
if (player != null)
|
|
||||||
{
|
|
||||||
cmdStatus(sender);
|
|
||||||
Config.log((Config.DynmapBorderEnabled() ? "Enabled" : "Disabled") + " DynMap border display at the command of player \"" + player.getName() + "\".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,48 +1,42 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdDynmapmsg extends WBCmd {
|
||||||
|
public CmdDynmapmsg() {
|
||||||
|
name = permission = "dynmapmsg";
|
||||||
|
minParams = 1;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "<text> - DynMap border labels will show this.");
|
||||||
|
helpText = "Default value: \"The border of the world.\". If you are running the DynMap plugin and the " +
|
||||||
|
commandEmphasized("dynmap") + C_DESC + "command setting is enabled, the borders shown in DynMap will " +
|
||||||
|
"be labelled with this text.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdDynmapmsg extends WBCmd
|
@Override
|
||||||
{
|
public void cmdStatus(CommandSender sender) {
|
||||||
public CmdDynmapmsg()
|
sender.sendMessage(C_HEAD + "DynMap border label is set to: " + C_ERR + Config.DynmapMessage());
|
||||||
{
|
}
|
||||||
name = permission = "dynmapmsg";
|
|
||||||
minParams = 1;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "<text> - DynMap border labels will show this.");
|
@Override
|
||||||
helpText = "Default value: \"The border of the world.\". If you are running the DynMap plugin and the " +
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
commandEmphasized("dynmap") + C_DESC + "command setting is enabled, the borders shown in DynMap will " +
|
StringBuilder message = new StringBuilder();
|
||||||
"be labelled with this text.";
|
boolean first = true;
|
||||||
}
|
for (String param : params) {
|
||||||
|
if (!first)
|
||||||
|
message.append(" ");
|
||||||
|
message.append(param);
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
Config.setDynmapMessage(message.toString());
|
||||||
public void cmdStatus(CommandSender sender)
|
|
||||||
{
|
|
||||||
sender.sendMessage(C_HEAD + "DynMap border label is set to: " + C_ERR + Config.DynmapMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (player != null)
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
cmdStatus(sender);
|
||||||
{
|
}
|
||||||
StringBuilder message = new StringBuilder();
|
|
||||||
boolean first = true;
|
|
||||||
for (String param : params)
|
|
||||||
{
|
|
||||||
if (!first)
|
|
||||||
message.append(" ");
|
|
||||||
message.append(param);
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Config.setDynmapMessage(message.toString());
|
|
||||||
|
|
||||||
if (player != null)
|
|
||||||
cmdStatus(sender);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,183 +1,161 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import com.wimbli.WorldBorder.CoordXZ;
|
||||||
|
import com.wimbli.WorldBorder.WorldBorder;
|
||||||
|
import com.wimbli.WorldBorder.WorldFillTask;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdFill extends WBCmd {
|
||||||
|
/* with "view-distance=10" in server.properties on a fast VM test server and "Render Distance: Far" in client,
|
||||||
|
* hitting border during testing was loading 11+ chunks beyond the border in a couple of directions (10 chunks in
|
||||||
|
* the other two directions). This could be worse on a more loaded or worse server, so:
|
||||||
|
*/
|
||||||
|
private final int defaultPadding = CoordXZ.chunkToBlock(13);
|
||||||
|
private String fillWorld = "";
|
||||||
|
private int fillFrequency = 20;
|
||||||
|
private int fillPadding = defaultPadding;
|
||||||
|
private boolean fillForceLoad = false;
|
||||||
|
|
||||||
|
public CmdFill() {
|
||||||
|
name = permission = "fill";
|
||||||
|
hasWorldNameInput = true;
|
||||||
|
consoleRequiresWorldName = false;
|
||||||
|
minParams = 0;
|
||||||
|
maxParams = 3;
|
||||||
|
|
||||||
public class CmdFill extends WBCmd
|
addCmdExample(nameEmphasizedW() + "[freq] [pad] [force] - fill world to border.");
|
||||||
{
|
helpText = "This command will generate missing world chunks inside your border. [freq] is the frequency " +
|
||||||
public CmdFill()
|
"of chunks per second that will be checked (default 20). [pad] is the number of blocks padding added " +
|
||||||
{
|
"beyond the border itself (default 208, to cover player visual range). [force] can be specified as true " +
|
||||||
name = permission = "fill";
|
"to force all chunks to be loaded even if they seem to be fully generated (default false).";
|
||||||
hasWorldNameInput = true;
|
}
|
||||||
consoleRequiresWorldName = false;
|
|
||||||
minParams = 0;
|
|
||||||
maxParams = 3;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasizedW() + "[freq] [pad] [force] - fill world to border.");
|
@Override
|
||||||
helpText = "This command will generate missing world chunks inside your border. [freq] is the frequency " +
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
"of chunks per second that will be checked (default 20). [pad] is the number of blocks padding added " +
|
boolean confirm = false;
|
||||||
"beyond the border itself (default 208, to cover player visual range). [force] can be specified as true " +
|
// check for "cancel", "pause", or "confirm"
|
||||||
"to force all chunks to be loaded even if they seem to be fully generated (default false).";
|
if (params.size() >= 1) {
|
||||||
}
|
String check = params.get(0).toLowerCase();
|
||||||
|
|
||||||
@Override
|
if (check.equals("cancel") || check.equals("stop")) {
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
if (!makeSureFillIsRunning(sender))
|
||||||
{
|
return;
|
||||||
boolean confirm = false;
|
sender.sendMessage(C_HEAD + "Cancelling the world map generation task.");
|
||||||
// check for "cancel", "pause", or "confirm"
|
fillDefaults();
|
||||||
if (params.size() >= 1)
|
Config.StopFillTask();
|
||||||
{
|
return;
|
||||||
String check = params.get(0).toLowerCase();
|
} else if (check.equals("pause")) {
|
||||||
|
if (!makeSureFillIsRunning(sender))
|
||||||
|
return;
|
||||||
|
Config.fillTask.pause();
|
||||||
|
sender.sendMessage(C_HEAD + "The world map generation task is now " + (Config.fillTask.isPaused() ? "" : "un") + "paused.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (check.equals("cancel") || check.equals("stop"))
|
confirm = check.equals("confirm");
|
||||||
{
|
}
|
||||||
if (!makeSureFillIsRunning(sender))
|
|
||||||
return;
|
|
||||||
sender.sendMessage(C_HEAD + "Cancelling the world map generation task.");
|
|
||||||
fillDefaults();
|
|
||||||
Config.StopFillTask();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (check.equals("pause"))
|
|
||||||
{
|
|
||||||
if (!makeSureFillIsRunning(sender))
|
|
||||||
return;
|
|
||||||
Config.fillTask.pause();
|
|
||||||
sender.sendMessage(C_HEAD + "The world map generation task is now " + (Config.fillTask.isPaused() ? "" : "un") + "paused.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
confirm = check.equals("confirm");
|
// if not just confirming, make sure a world name is available
|
||||||
}
|
if (worldName == null && !confirm) {
|
||||||
|
if (player != null)
|
||||||
|
worldName = player.getWorld().getName();
|
||||||
|
else {
|
||||||
|
sendErrorAndHelp(sender, "You must specify a world!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if not just confirming, make sure a world name is available
|
// colorized "/wb fill "
|
||||||
if (worldName == null && !confirm)
|
String cmd = cmd(sender) + nameEmphasized() + C_CMD;
|
||||||
{
|
|
||||||
if (player != null)
|
|
||||||
worldName = player.getWorld().getName();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "You must specify a world!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// colorized "/wb fill "
|
// make sure Fill isn't already running
|
||||||
String cmd = cmd(sender) + nameEmphasized() + C_CMD;
|
if (Config.fillTask != null && Config.fillTask.valid()) {
|
||||||
|
sender.sendMessage(C_ERR + "The world map generation task is already running.");
|
||||||
|
sender.sendMessage(C_DESC + "You can cancel at any time with " + cmd + "cancel" + C_DESC + ", or pause/unpause with " + cmd + "pause" + C_DESC + ".");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// make sure Fill isn't already running
|
// set frequency and/or padding if those were specified
|
||||||
if (Config.fillTask != null && Config.fillTask.valid())
|
try {
|
||||||
{
|
if (params.size() >= 1 && !confirm)
|
||||||
sender.sendMessage(C_ERR + "The world map generation task is already running.");
|
fillFrequency = Math.abs(Integer.parseInt(params.get(0)));
|
||||||
sender.sendMessage(C_DESC + "You can cancel at any time with " + cmd + "cancel" + C_DESC + ", or pause/unpause with " + cmd + "pause" + C_DESC + ".");
|
if (params.size() >= 2 && !confirm)
|
||||||
return;
|
fillPadding = Math.abs(Integer.parseInt(params.get(1)));
|
||||||
}
|
} catch (NumberFormatException ex) {
|
||||||
|
sendErrorAndHelp(sender, "The frequency and padding values must be integers.");
|
||||||
|
fillDefaults();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fillFrequency <= 0) {
|
||||||
|
sendErrorAndHelp(sender, "The frequency value must be greater than zero.");
|
||||||
|
fillDefaults();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// set frequency and/or padding if those were specified
|
// see if the command specifies to load even chunks which should already be fully generated
|
||||||
try
|
if (params.size() == 3)
|
||||||
{
|
fillForceLoad = strAsBool(params.get(2));
|
||||||
if (params.size() >= 1 && !confirm)
|
|
||||||
fillFrequency = Math.abs(Integer.parseInt(params.get(0)));
|
|
||||||
if (params.size() >= 2 && !confirm)
|
|
||||||
fillPadding = Math.abs(Integer.parseInt(params.get(1)));
|
|
||||||
}
|
|
||||||
catch(NumberFormatException ex)
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "The frequency and padding values must be integers.");
|
|
||||||
fillDefaults();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (fillFrequency <= 0)
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "The frequency value must be greater than zero.");
|
|
||||||
fillDefaults();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// see if the command specifies to load even chunks which should already be fully generated
|
// set world if it was specified
|
||||||
if (params.size() == 3)
|
if (worldName != null)
|
||||||
fillForceLoad = strAsBool(params.get(2));
|
fillWorld = worldName;
|
||||||
|
|
||||||
// set world if it was specified
|
if (confirm) { // command confirmed, go ahead with it
|
||||||
if (worldName != null)
|
if (fillWorld.isEmpty()) {
|
||||||
fillWorld = worldName;
|
sendErrorAndHelp(sender, "You must first use this command successfully without confirming.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (confirm)
|
if (player != null)
|
||||||
{ // command confirmed, go ahead with it
|
Config.log("Filling out world to border at the command of player \"" + player.getName() + "\".");
|
||||||
if (fillWorld.isEmpty())
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "You must first use this command successfully without confirming.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player != null)
|
int ticks = 1, repeats = 1;
|
||||||
Config.log("Filling out world to border at the command of player \"" + player.getName() + "\".");
|
if (fillFrequency > 20)
|
||||||
|
repeats = fillFrequency / 20;
|
||||||
|
else
|
||||||
|
ticks = 20 / fillFrequency;
|
||||||
|
|
||||||
int ticks = 1, repeats = 1;
|
/* */
|
||||||
if (fillFrequency > 20)
|
Config.log("world: " + fillWorld + " padding: " + fillPadding + " repeats: " + repeats + " ticks: " + ticks);
|
||||||
repeats = fillFrequency / 20;
|
Config.fillTask = new WorldFillTask(Bukkit.getServer(), player, fillWorld, fillPadding, repeats, ticks, fillForceLoad);
|
||||||
else
|
if (Config.fillTask.valid()) {
|
||||||
ticks = 20 / fillFrequency;
|
int task = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(WorldBorder.plugin, Config.fillTask, ticks, ticks);
|
||||||
|
Config.fillTask.setTaskID(task);
|
||||||
|
sender.sendMessage("WorldBorder map generation task for world \"" + fillWorld + "\" started.");
|
||||||
|
} else
|
||||||
|
sender.sendMessage(C_ERR + "The world map generation task failed to start.");
|
||||||
|
|
||||||
/* */ Config.log("world: " + fillWorld + " padding: " + fillPadding + " repeats: " + repeats + " ticks: " + ticks);
|
fillDefaults();
|
||||||
Config.fillTask = new WorldFillTask(Bukkit.getServer(), player, fillWorld, fillPadding, repeats, ticks, fillForceLoad);
|
} else {
|
||||||
if (Config.fillTask.valid())
|
if (fillWorld.isEmpty()) {
|
||||||
{
|
sendErrorAndHelp(sender, "You must first specify a valid world.");
|
||||||
int task = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(WorldBorder.plugin, Config.fillTask, ticks, ticks);
|
return;
|
||||||
Config.fillTask.setTaskID(task);
|
}
|
||||||
sender.sendMessage("WorldBorder map generation task for world \"" + fillWorld + "\" started.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
sender.sendMessage(C_ERR + "The world map generation task failed to start.");
|
|
||||||
|
|
||||||
fillDefaults();
|
sender.sendMessage(C_HEAD + "World generation task is ready for world \"" + fillWorld + "\", attempting to process up to " + fillFrequency + " chunks per second (default 20). The map will be padded out " + fillPadding + " blocks beyond the border (default " + defaultPadding + "). Parts of the world which are already fully generated will be " + (fillForceLoad ? "loaded anyway." : "skipped."));
|
||||||
}
|
sender.sendMessage(C_HEAD + "This process can take a very long time depending on the world's border size. Also, depending on the chunk processing rate, players will likely experience severe lag for the duration.");
|
||||||
else
|
sender.sendMessage(C_DESC + "You should now use " + cmd + "confirm" + C_DESC + " to start the process.");
|
||||||
{
|
sender.sendMessage(C_DESC + "You can cancel at any time with " + cmd + "cancel" + C_DESC + ", or pause/unpause with " + cmd + "pause" + C_DESC + ".");
|
||||||
if (fillWorld.isEmpty())
|
}
|
||||||
{
|
}
|
||||||
sendErrorAndHelp(sender, "You must first specify a valid world.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sender.sendMessage(C_HEAD + "World generation task is ready for world \"" + fillWorld + "\", attempting to process up to " + fillFrequency + " chunks per second (default 20). The map will be padded out " + fillPadding + " blocks beyond the border (default " + defaultPadding + "). Parts of the world which are already fully generated will be " + (fillForceLoad ? "loaded anyway." : "skipped."));
|
private void fillDefaults() {
|
||||||
sender.sendMessage(C_HEAD + "This process can take a very long time depending on the world's border size. Also, depending on the chunk processing rate, players will likely experience severe lag for the duration.");
|
fillWorld = "";
|
||||||
sender.sendMessage(C_DESC + "You should now use " + cmd + "confirm" + C_DESC + " to start the process.");
|
fillFrequency = 20;
|
||||||
sender.sendMessage(C_DESC + "You can cancel at any time with " + cmd + "cancel" + C_DESC + ", or pause/unpause with " + cmd + "pause" + C_DESC + ".");
|
fillPadding = defaultPadding;
|
||||||
}
|
fillForceLoad = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean makeSureFillIsRunning(CommandSender sender) {
|
||||||
/* with "view-distance=10" in server.properties on a fast VM test server and "Render Distance: Far" in client,
|
if (Config.fillTask != null && Config.fillTask.valid())
|
||||||
* hitting border during testing was loading 11+ chunks beyond the border in a couple of directions (10 chunks in
|
return true;
|
||||||
* the other two directions). This could be worse on a more loaded or worse server, so:
|
sendErrorAndHelp(sender, "The world map generation task is not currently running.");
|
||||||
*/
|
return false;
|
||||||
private final int defaultPadding = CoordXZ.chunkToBlock(13);
|
}
|
||||||
|
|
||||||
private String fillWorld = "";
|
|
||||||
private int fillFrequency = 20;
|
|
||||||
private int fillPadding = defaultPadding;
|
|
||||||
private boolean fillForceLoad = false;
|
|
||||||
|
|
||||||
private void fillDefaults()
|
|
||||||
{
|
|
||||||
fillWorld = "";
|
|
||||||
fillFrequency = 20;
|
|
||||||
fillPadding = defaultPadding;
|
|
||||||
fillForceLoad = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean makeSureFillIsRunning(CommandSender sender)
|
|
||||||
{
|
|
||||||
if (Config.fillTask != null && Config.fillTask.valid())
|
|
||||||
return true;
|
|
||||||
sendErrorAndHelp(sender, "The world map generation task is not currently running.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,61 +1,50 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdFillautosave extends WBCmd {
|
||||||
|
public CmdFillautosave() {
|
||||||
|
name = permission = "fillautosave";
|
||||||
|
minParams = maxParams = 1;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "<seconds> - world save interval for Fill.");
|
||||||
|
helpText = "Default value: 30 seconds.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdFillautosave extends WBCmd
|
@Override
|
||||||
{
|
public void cmdStatus(CommandSender sender) {
|
||||||
public CmdFillautosave()
|
int seconds = Config.FillAutosaveFrequency();
|
||||||
{
|
if (seconds == 0) {
|
||||||
name = permission = "fillautosave";
|
sender.sendMessage(C_HEAD + "World autosave frequency during Fill process is set to 0, disabling it.");
|
||||||
minParams = maxParams = 1;
|
sender.sendMessage(C_HEAD + "Note that much progress can be lost this way if there is a bug or crash in " +
|
||||||
|
"the world generation process from Bukkit or any world generation plugin you use.");
|
||||||
|
} else {
|
||||||
|
sender.sendMessage(C_HEAD + "World autosave frequency during Fill process is set to " + seconds + " seconds (rounded to a multiple of 5).");
|
||||||
|
sender.sendMessage(C_HEAD + "New chunks generated by the Fill process will be forcibly saved to disk " +
|
||||||
|
"this often to prevent loss of progress due to bugs or crashes in the world generation process.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "<seconds> - world save interval for Fill.");
|
@Override
|
||||||
helpText = "Default value: 30 seconds.";
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
}
|
int seconds = 0;
|
||||||
|
try {
|
||||||
|
seconds = Integer.parseInt(params.get(0));
|
||||||
|
if (seconds < 0)
|
||||||
|
throw new NumberFormatException();
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
sendErrorAndHelp(sender, "The world autosave frequency must be an integer of 0 or higher. Setting to 0 will disable autosaving of the world during the Fill process.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
Config.setFillAutosaveFrequency(seconds);
|
||||||
public void cmdStatus(CommandSender sender)
|
|
||||||
{
|
|
||||||
int seconds = Config.FillAutosaveFrequency();
|
|
||||||
if (seconds == 0)
|
|
||||||
{
|
|
||||||
sender.sendMessage(C_HEAD + "World autosave frequency during Fill process is set to 0, disabling it.");
|
|
||||||
sender.sendMessage(C_HEAD + "Note that much progress can be lost this way if there is a bug or crash in " +
|
|
||||||
"the world generation process from Bukkit or any world generation plugin you use.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sender.sendMessage(C_HEAD + "World autosave frequency during Fill process is set to " + seconds + " seconds (rounded to a multiple of 5).");
|
|
||||||
sender.sendMessage(C_HEAD + "New chunks generated by the Fill process will be forcibly saved to disk " +
|
|
||||||
"this often to prevent loss of progress due to bugs or crashes in the world generation process.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (player != null)
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
cmdStatus(sender);
|
||||||
{
|
}
|
||||||
int seconds = 0;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
seconds = Integer.parseInt(params.get(0));
|
|
||||||
if (seconds < 0)
|
|
||||||
throw new NumberFormatException();
|
|
||||||
}
|
|
||||||
catch(NumberFormatException ex)
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "The world autosave frequency must be an integer of 0 or higher. Setting to 0 will disable autosaving of the world during the Fill process.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Config.setFillAutosaveFrequency(seconds);
|
|
||||||
|
|
||||||
if (player != null)
|
|
||||||
cmdStatus(sender);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,26 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdGetmsg extends WBCmd {
|
||||||
|
public CmdGetmsg() {
|
||||||
|
name = permission = "getmsg";
|
||||||
|
minParams = maxParams = 0;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "- display border message.");
|
||||||
|
helpText = "This command simply displays the message shown to players knocked back from the border.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdGetmsg extends WBCmd
|
@Override
|
||||||
{
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
public CmdGetmsg()
|
sender.sendMessage("Border message is currently set to:");
|
||||||
{
|
sender.sendMessage(Config.MessageRaw());
|
||||||
name = permission = "getmsg";
|
sender.sendMessage("Formatted border message:");
|
||||||
minParams = maxParams = 0;
|
sender.sendMessage(Config.Message());
|
||||||
|
}
|
||||||
addCmdExample(nameEmphasized() + "- display border message.");
|
|
||||||
helpText = "This command simply displays the message shown to players knocked back from the border.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
|
||||||
{
|
|
||||||
sender.sendMessage("Border message is currently set to:");
|
|
||||||
sender.sendMessage(Config.MessageRaw());
|
|
||||||
sender.sendMessage("Formatted border message:");
|
|
||||||
sender.sendMessage(Config.Message());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,53 +1,45 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.WorldBorder;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdHelp extends WBCmd {
|
||||||
|
public CmdHelp() {
|
||||||
|
name = permission = "help";
|
||||||
|
minParams = 0;
|
||||||
|
maxParams = 10;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "[command] - get help on command usage.");
|
||||||
public class CmdHelp extends WBCmd
|
|
||||||
{
|
|
||||||
public CmdHelp()
|
|
||||||
{
|
|
||||||
name = permission = "help";
|
|
||||||
minParams = 0;
|
|
||||||
maxParams = 10;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "[command] - get help on command usage.");
|
|
||||||
// helpText = "If [command] is specified, info for that particular command will be provided.";
|
// helpText = "If [command] is specified, info for that particular command will be provided.";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cmdStatus(CommandSender sender)
|
public void cmdStatus(CommandSender sender) {
|
||||||
{
|
String commands = WorldBorder.wbCommand.getCommandNames().toString().replace(", ", C_DESC + ", " + C_CMD);
|
||||||
String commands = WorldBorder.wbCommand.getCommandNames().toString().replace(", ", C_DESC + ", " + C_CMD);
|
sender.sendMessage(C_HEAD + "Commands: " + C_CMD + commands.substring(1, commands.length() - 1));
|
||||||
sender.sendMessage(C_HEAD + "Commands: " + C_CMD + commands.substring(1, commands.length() - 1));
|
sender.sendMessage("Example, for info on \"set\" command: " + cmd(sender) + nameEmphasized() + C_CMD + "set");
|
||||||
sender.sendMessage("Example, for info on \"set\" command: " + cmd(sender) + nameEmphasized() + C_CMD + "set");
|
sender.sendMessage(C_HEAD + "For a full command example list, simply run the root " + cmd(sender) + C_HEAD + "command by itself with nothing specified.");
|
||||||
sender.sendMessage(C_HEAD + "For a full command example list, simply run the root " + cmd(sender) + C_HEAD + "command by itself with nothing specified.");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
{
|
if (params.isEmpty()) {
|
||||||
if (params.isEmpty())
|
sendCmdHelp(sender);
|
||||||
{
|
return;
|
||||||
sendCmdHelp(sender);
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<String> commands = WorldBorder.wbCommand.getCommandNames();
|
Set<String> commands = WorldBorder.wbCommand.getCommandNames();
|
||||||
for (String param : params)
|
for (String param : params) {
|
||||||
{
|
if (commands.contains(param.toLowerCase())) {
|
||||||
if (commands.contains(param.toLowerCase()))
|
WorldBorder.wbCommand.subCommands.get(param.toLowerCase()).sendCmdHelp(sender);
|
||||||
{
|
return;
|
||||||
WorldBorder.wbCommand.subCommands.get(param.toLowerCase()).sendCmdHelp(sender);
|
}
|
||||||
return;
|
}
|
||||||
}
|
sendErrorAndHelp(sender, "No command recognized.");
|
||||||
}
|
}
|
||||||
sendErrorAndHelp(sender, "No command recognized.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,53 +1,45 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdKnockback extends WBCmd {
|
||||||
|
public CmdKnockback() {
|
||||||
|
name = permission = "knockback";
|
||||||
|
minParams = maxParams = 1;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "<distance> - how far to move the player back.");
|
||||||
|
helpText = "Default value: 3.0 (blocks). Players who cross the border will be knocked back to this distance inside.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdKnockback extends WBCmd
|
@Override
|
||||||
{
|
public void cmdStatus(CommandSender sender) {
|
||||||
public CmdKnockback()
|
double kb = Config.KnockBack();
|
||||||
{
|
if (kb < 1)
|
||||||
name = permission = "knockback";
|
sender.sendMessage(C_HEAD + "Knockback is set to 0, disabling border enforcement.");
|
||||||
minParams = maxParams = 1;
|
else
|
||||||
|
sender.sendMessage(C_HEAD + "Knockback is set to " + kb + " blocks inside the border.");
|
||||||
|
}
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "<distance> - how far to move the player back.");
|
@Override
|
||||||
helpText = "Default value: 3.0 (blocks). Players who cross the border will be knocked back to this distance inside.";
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
}
|
double numBlocks = 0.0;
|
||||||
|
try {
|
||||||
|
numBlocks = Double.parseDouble(params.get(0));
|
||||||
|
if (numBlocks < 0.0 || (numBlocks > 0.0 && numBlocks < 1.0))
|
||||||
|
throw new NumberFormatException();
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
sendErrorAndHelp(sender, "The knockback must be a decimal value of at least 1.0, or it can be 0.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
Config.setKnockBack(numBlocks);
|
||||||
public void cmdStatus(CommandSender sender)
|
|
||||||
{
|
|
||||||
double kb = Config.KnockBack();
|
|
||||||
if (kb < 1)
|
|
||||||
sender.sendMessage(C_HEAD + "Knockback is set to 0, disabling border enforcement.");
|
|
||||||
else
|
|
||||||
sender.sendMessage(C_HEAD + "Knockback is set to " + kb + " blocks inside the border.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (player != null)
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
cmdStatus(sender);
|
||||||
{
|
}
|
||||||
double numBlocks = 0.0;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
numBlocks = Double.parseDouble(params.get(0));
|
|
||||||
if (numBlocks < 0.0 || (numBlocks > 0.0 && numBlocks < 1.0))
|
|
||||||
throw new NumberFormatException();
|
|
||||||
}
|
|
||||||
catch(NumberFormatException ex)
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "The knockback must be a decimal value of at least 1.0, or it can be 0.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Config.setKnockBack(numBlocks);
|
|
||||||
|
|
||||||
if (player != null)
|
|
||||||
cmdStatus(sender);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,42 +1,36 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdList extends WBCmd {
|
||||||
|
public CmdList() {
|
||||||
|
name = permission = "list";
|
||||||
|
minParams = maxParams = 0;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "- show border information for all worlds.");
|
||||||
|
helpText = "This command will list full information for every border you have set including position, " +
|
||||||
|
"radius, and shape. The default border shape will also be indicated.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdList extends WBCmd
|
@Override
|
||||||
{
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
public CmdList()
|
sender.sendMessage("Default border shape for all worlds is \"" + Config.ShapeName() + "\".");
|
||||||
{
|
|
||||||
name = permission = "list";
|
|
||||||
minParams = maxParams = 0;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "- show border information for all worlds.");
|
Set<String> list = Config.BorderDescriptions();
|
||||||
helpText = "This command will list full information for every border you have set including position, " +
|
|
||||||
"radius, and shape. The default border shape will also be indicated.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (list.isEmpty()) {
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
sender.sendMessage("There are no borders currently set.");
|
||||||
{
|
return;
|
||||||
sender.sendMessage("Default border shape for all worlds is \"" + Config.ShapeName() + "\".");
|
}
|
||||||
|
|
||||||
Set<String> list = Config.BorderDescriptions();
|
for (String borderDesc : list) {
|
||||||
|
sender.sendMessage(borderDesc);
|
||||||
if (list.isEmpty())
|
}
|
||||||
{
|
}
|
||||||
sender.sendMessage("There are no borders currently set.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(String borderDesc : list)
|
|
||||||
{
|
|
||||||
sender.sendMessage(borderDesc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,35 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdPortal extends WBCmd {
|
||||||
|
public CmdPortal() {
|
||||||
|
name = permission = "portal";
|
||||||
|
minParams = maxParams = 1;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "<on|off> - turn portal redirection on or off.");
|
||||||
|
helpText = "Default value: on. This feature monitors new portal creation and changes the target new portal " +
|
||||||
|
"location if it is outside of the border. Try disabling this if you have problems with other plugins " +
|
||||||
|
"related to portals.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdPortal extends WBCmd
|
@Override
|
||||||
{
|
public void cmdStatus(CommandSender sender) {
|
||||||
public CmdPortal()
|
sender.sendMessage(C_HEAD + "Portal redirection is " + enabledColored(Config.portalRedirection()) + C_HEAD + ".");
|
||||||
{
|
}
|
||||||
name = permission = "portal";
|
|
||||||
minParams = maxParams = 1;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "<on|off> - turn portal redirection on or off.");
|
@Override
|
||||||
helpText = "Default value: on. This feature monitors new portal creation and changes the target new portal " +
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
"location if it is outside of the border. Try disabling this if you have problems with other plugins " +
|
Config.setPortalRedirection(strAsBool(params.get(0)));
|
||||||
"related to portals.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (player != null) {
|
||||||
public void cmdStatus(CommandSender sender)
|
Config.log((Config.portalRedirection() ? "Enabled" : "Disabled") + " portal redirection at the command of player \"" + player.getName() + "\".");
|
||||||
{
|
cmdStatus(sender);
|
||||||
sender.sendMessage(C_HEAD + "Portal redirection is " + enabledColored(Config.portalRedirection()) + C_HEAD + ".");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
|
||||||
{
|
|
||||||
Config.setPortalRedirection(strAsBool(params.get(0)));
|
|
||||||
|
|
||||||
if (player != null)
|
|
||||||
{
|
|
||||||
Config.log((Config.portalRedirection() ? "Enabled" : "Disabled") + " portal redirection at the command of player \"" + player.getName() + "\".");
|
|
||||||
cmdStatus(sender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,37 +1,33 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
import java.util.List;
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.Config;
|
import java.util.List;
|
||||||
|
|
||||||
public class CmdPreventPlace extends WBCmd {
|
public class CmdPreventPlace extends WBCmd {
|
||||||
|
|
||||||
public CmdPreventPlace() {
|
public CmdPreventPlace() {
|
||||||
name = permission = "preventblockplace";
|
name = permission = "preventblockplace";
|
||||||
minParams = maxParams = 1;
|
minParams = maxParams = 1;
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "<on|off> - stop block placement past border.");
|
addCmdExample(nameEmphasized() + "<on|off> - stop block placement past border.");
|
||||||
helpText = "Default value: off. When enabled, this setting will prevent players from placing blocks outside the world's border.";
|
helpText = "Default value: off. When enabled, this setting will prevent players from placing blocks outside the world's border.";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cmdStatus(CommandSender sender)
|
public void cmdStatus(CommandSender sender) {
|
||||||
{
|
sender.sendMessage(C_HEAD + "Prevention of block placement outside the border is " + enabledColored(Config.preventBlockPlace()) + C_HEAD + ".");
|
||||||
sender.sendMessage(C_HEAD + "Prevention of block placement outside the border is " + enabledColored(Config.preventBlockPlace()) + C_HEAD + ".");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
{
|
Config.setPreventBlockPlace(strAsBool(params.get(0)));
|
||||||
Config.setPreventBlockPlace(strAsBool(params.get(0)));
|
|
||||||
|
|
||||||
if (player != null)
|
if (player != null) {
|
||||||
{
|
Config.log((Config.preventBlockPlace() ? "Enabled" : "Disabled") + " preventblockplace at the command of player \"" + player.getName() + "\".");
|
||||||
Config.log((Config.preventBlockPlace() ? "Enabled" : "Disabled") + " preventblockplace at the command of player \"" + player.getName() + "\".");
|
cmdStatus(sender);
|
||||||
cmdStatus(sender);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -8,29 +8,26 @@ import java.util.List;
|
|||||||
|
|
||||||
public class CmdPreventSpawn extends WBCmd {
|
public class CmdPreventSpawn extends WBCmd {
|
||||||
|
|
||||||
public CmdPreventSpawn() {
|
public CmdPreventSpawn() {
|
||||||
name = permission = "preventmobspawn";
|
name = permission = "preventmobspawn";
|
||||||
minParams = maxParams = 1;
|
minParams = maxParams = 1;
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "<on|off> - stop mob spawning past border.");
|
addCmdExample(nameEmphasized() + "<on|off> - stop mob spawning past border.");
|
||||||
helpText = "Default value: off. When enabled, this setting will prevent mobs from naturally spawning outside the world's border.";
|
helpText = "Default value: off. When enabled, this setting will prevent mobs from naturally spawning outside the world's border.";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cmdStatus(CommandSender sender)
|
public void cmdStatus(CommandSender sender) {
|
||||||
{
|
sender.sendMessage(C_HEAD + "Prevention of mob spawning outside the border is " + enabledColored(Config.preventMobSpawn()) + C_HEAD + ".");
|
||||||
sender.sendMessage(C_HEAD + "Prevention of mob spawning outside the border is " + enabledColored(Config.preventMobSpawn()) + C_HEAD + ".");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
{
|
Config.setPreventMobSpawn(strAsBool(params.get(0)));
|
||||||
Config.setPreventMobSpawn(strAsBool(params.get(0)));
|
|
||||||
|
|
||||||
if (player != null)
|
if (player != null) {
|
||||||
{
|
Config.log((Config.preventMobSpawn() ? "Enabled" : "Disabled") + " preventmobspawn at the command of player \"" + player.getName() + "\".");
|
||||||
Config.log((Config.preventMobSpawn() ? "Enabled" : "Disabled") + " preventmobspawn at the command of player \"" + player.getName() + "\".");
|
cmdStatus(sender);
|
||||||
cmdStatus(sender);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,91 +1,74 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.BorderData;
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdRadius extends WBCmd {
|
||||||
|
public CmdRadius() {
|
||||||
|
name = permission = "radius";
|
||||||
|
hasWorldNameInput = true;
|
||||||
|
minParams = 1;
|
||||||
|
maxParams = 2;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasizedW() + "<radiusX> [radiusZ] - change radius.");
|
||||||
|
helpText = "Using this command you can adjust the radius of an existing border. If [radiusZ] is not " +
|
||||||
|
"specified, the radiusX value will be used for both. You can also optionally specify + or - at the start " +
|
||||||
|
"of <radiusX> and [radiusZ] to increase or decrease the existing radius rather than setting a new value.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdRadius extends WBCmd
|
@Override
|
||||||
{
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
public CmdRadius()
|
if (worldName == null)
|
||||||
{
|
worldName = player.getWorld().getName();
|
||||||
name = permission = "radius";
|
|
||||||
hasWorldNameInput = true;
|
|
||||||
minParams = 1;
|
|
||||||
maxParams = 2;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasizedW() + "<radiusX> [radiusZ] - change radius.");
|
BorderData border = Config.Border(worldName);
|
||||||
helpText = "Using this command you can adjust the radius of an existing border. If [radiusZ] is not " +
|
if (border == null) {
|
||||||
"specified, the radiusX value will be used for both. You can also optionally specify + or - at the start " +
|
sendErrorAndHelp(sender, "This world (\"" + worldName + "\") must first have a border set normally.");
|
||||||
"of <radiusX> and [radiusZ] to increase or decrease the existing radius rather than setting a new value.";
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
double x = border.getX();
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
double z = border.getZ();
|
||||||
{
|
int radiusX;
|
||||||
if (worldName == null)
|
int radiusZ;
|
||||||
worldName = player.getWorld().getName();
|
try {
|
||||||
|
if (params.get(0).startsWith("+")) {
|
||||||
|
// Add to the current radius
|
||||||
|
radiusX = border.getRadiusX();
|
||||||
|
radiusX += Integer.parseInt(params.get(0).substring(1));
|
||||||
|
} else if (params.get(0).startsWith("-")) {
|
||||||
|
// Subtract from the current radius
|
||||||
|
radiusX = border.getRadiusX();
|
||||||
|
radiusX -= Integer.parseInt(params.get(0).substring(1));
|
||||||
|
} else
|
||||||
|
radiusX = Integer.parseInt(params.get(0));
|
||||||
|
|
||||||
BorderData border = Config.Border(worldName);
|
if (params.size() == 2) {
|
||||||
if (border == null)
|
if (params.get(1).startsWith("+")) {
|
||||||
{
|
// Add to the current radius
|
||||||
sendErrorAndHelp(sender, "This world (\"" + worldName + "\") must first have a border set normally.");
|
radiusZ = border.getRadiusZ();
|
||||||
return;
|
radiusZ += Integer.parseInt(params.get(1).substring(1));
|
||||||
}
|
} else if (params.get(1).startsWith("-")) {
|
||||||
|
// Subtract from the current radius
|
||||||
|
radiusZ = border.getRadiusZ();
|
||||||
|
radiusZ -= Integer.parseInt(params.get(1).substring(1));
|
||||||
|
} else
|
||||||
|
radiusZ = Integer.parseInt(params.get(1));
|
||||||
|
} else
|
||||||
|
radiusZ = radiusX;
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
sendErrorAndHelp(sender, "The radius value(s) must be integers.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
double x = border.getX();
|
Config.setBorder(worldName, radiusX, radiusZ, x, z);
|
||||||
double z = border.getZ();
|
|
||||||
int radiusX;
|
|
||||||
int radiusZ;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (params.get(0).startsWith("+"))
|
|
||||||
{
|
|
||||||
// Add to the current radius
|
|
||||||
radiusX = border.getRadiusX();
|
|
||||||
radiusX += Integer.parseInt(params.get(0).substring(1));
|
|
||||||
}
|
|
||||||
else if(params.get(0).startsWith("-"))
|
|
||||||
{
|
|
||||||
// Subtract from the current radius
|
|
||||||
radiusX = border.getRadiusX();
|
|
||||||
radiusX -= Integer.parseInt(params.get(0).substring(1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
radiusX = Integer.parseInt(params.get(0));
|
|
||||||
|
|
||||||
if (params.size() == 2)
|
if (player != null)
|
||||||
{
|
sender.sendMessage("Radius has been set. " + Config.BorderDescription(worldName));
|
||||||
if (params.get(1).startsWith("+"))
|
}
|
||||||
{
|
|
||||||
// Add to the current radius
|
|
||||||
radiusZ = border.getRadiusZ();
|
|
||||||
radiusZ += Integer.parseInt(params.get(1).substring(1));
|
|
||||||
}
|
|
||||||
else if(params.get(1).startsWith("-"))
|
|
||||||
{
|
|
||||||
// Subtract from the current radius
|
|
||||||
radiusZ = border.getRadiusZ();
|
|
||||||
radiusZ -= Integer.parseInt(params.get(1).substring(1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
radiusZ = Integer.parseInt(params.get(1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
radiusZ = radiusX;
|
|
||||||
}
|
|
||||||
catch(NumberFormatException ex)
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "The radius value(s) must be integers.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Config.setBorder(worldName, radiusX, radiusZ, x, z);
|
|
||||||
|
|
||||||
if (player != null)
|
|
||||||
sender.sendMessage("Radius has been set. " + Config.BorderDescription(worldName));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,31 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import com.wimbli.WorldBorder.WorldBorder;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdReload extends WBCmd {
|
||||||
|
public CmdReload() {
|
||||||
|
name = permission = "reload";
|
||||||
|
minParams = maxParams = 0;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "- re-load data from config.yml.");
|
||||||
|
helpText = "If you make manual changes to config.yml while the server is running, you can use this command " +
|
||||||
|
"to make WorldBorder load the changes without needing to restart the server.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdReload extends WBCmd
|
@Override
|
||||||
{
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
public CmdReload()
|
if (player != null)
|
||||||
{
|
Config.log("Reloading config file at the command of player \"" + player.getName() + "\".");
|
||||||
name = permission = "reload";
|
|
||||||
minParams = maxParams = 0;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "- re-load data from config.yml.");
|
Config.load(WorldBorder.plugin, true);
|
||||||
helpText = "If you make manual changes to config.yml while the server is running, you can use this command " +
|
|
||||||
"to make WorldBorder load the changes without needing to restart the server.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (player != null)
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
sender.sendMessage("WorldBorder configuration reloaded.");
|
||||||
{
|
}
|
||||||
if (player != null)
|
|
||||||
Config.log("Reloading config file at the command of player \"" + player.getName() + "\".");
|
|
||||||
|
|
||||||
Config.load(WorldBorder.plugin, true);
|
|
||||||
|
|
||||||
if (player != null)
|
|
||||||
sender.sendMessage("WorldBorder configuration reloaded.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,59 +1,50 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdRemount extends WBCmd {
|
||||||
|
public CmdRemount() {
|
||||||
|
name = permission = "remount";
|
||||||
|
minParams = maxParams = 1;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "<amount> - player remount delay after knockback.");
|
||||||
|
helpText = "Default value: 0 (disabled). If set higher than 0, WorldBorder will attempt to re-mount players who " +
|
||||||
|
"are knocked back from the border while riding something after this many server ticks. This setting can " +
|
||||||
|
"cause really nasty glitches if enabled and set too low due to CraftBukkit teleportation problems.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdRemount extends WBCmd
|
@Override
|
||||||
{
|
public void cmdStatus(CommandSender sender) {
|
||||||
public CmdRemount()
|
int delay = Config.RemountTicks();
|
||||||
{
|
if (delay == 0)
|
||||||
name = permission = "remount";
|
sender.sendMessage(C_HEAD + "Remount delay set to 0. Players will be left dismounted when knocked back from the border while on a vehicle.");
|
||||||
minParams = maxParams = 1;
|
else {
|
||||||
|
sender.sendMessage(C_HEAD + "Remount delay set to " + delay + " tick(s). That is roughly " + (delay * 50) + "ms / " + (((double) delay * 50.0) / 1000.0) + " seconds. Setting to 0 would disable remounting.");
|
||||||
|
if (delay < 10)
|
||||||
|
sender.sendMessage(C_ERR + "WARNING:" + C_DESC + " setting this to less than 10 (and greater than 0) is not recommended. This can lead to nasty client glitches.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "<amount> - player remount delay after knockback.");
|
@Override
|
||||||
helpText = "Default value: 0 (disabled). If set higher than 0, WorldBorder will attempt to re-mount players who " +
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
"are knocked back from the border while riding something after this many server ticks. This setting can " +
|
int delay = 0;
|
||||||
"cause really nasty glitches if enabled and set too low due to CraftBukkit teleportation problems.";
|
try {
|
||||||
}
|
delay = Integer.parseInt(params.get(0));
|
||||||
|
if (delay < 0)
|
||||||
|
throw new NumberFormatException();
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
sendErrorAndHelp(sender, "The remount delay must be an integer of 0 or higher. Setting to 0 will disable remounting.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
Config.setRemountTicks(delay);
|
||||||
public void cmdStatus(CommandSender sender)
|
|
||||||
{
|
|
||||||
int delay = Config.RemountTicks();
|
|
||||||
if (delay == 0)
|
|
||||||
sender.sendMessage(C_HEAD + "Remount delay set to 0. Players will be left dismounted when knocked back from the border while on a vehicle.");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sender.sendMessage(C_HEAD + "Remount delay set to " + delay + " tick(s). That is roughly " + (delay * 50) + "ms / " + (((double)delay * 50.0) / 1000.0) + " seconds. Setting to 0 would disable remounting.");
|
|
||||||
if (delay < 10)
|
|
||||||
sender.sendMessage(C_ERR + "WARNING:" + C_DESC + " setting this to less than 10 (and greater than 0) is not recommended. This can lead to nasty client glitches.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (player != null)
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
cmdStatus(sender);
|
||||||
{
|
}
|
||||||
int delay = 0;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
delay = Integer.parseInt(params.get(0));
|
|
||||||
if (delay < 0)
|
|
||||||
throw new NumberFormatException();
|
|
||||||
}
|
|
||||||
catch(NumberFormatException ex)
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "The remount delay must be an integer of 0 or higher. Setting to 0 will disable remounting.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Config.setRemountTicks(delay);
|
|
||||||
|
|
||||||
if (player != null)
|
|
||||||
cmdStatus(sender);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,145 +1,119 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.World;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdSet extends WBCmd {
|
||||||
|
public CmdSet() {
|
||||||
|
name = permission = "set";
|
||||||
|
hasWorldNameInput = true;
|
||||||
|
consoleRequiresWorldName = false;
|
||||||
|
minParams = 1;
|
||||||
|
maxParams = 4;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasizedW() + "<radiusX> [radiusZ] <x> <z> - use x/z coords.");
|
||||||
|
addCmdExample(nameEmphasizedW() + "<radiusX> [radiusZ] ^spawn - use spawn point.");
|
||||||
|
addCmdExample(nameEmphasized() + "<radiusX> [radiusZ] - set border, centered on you.", true, false, true);
|
||||||
|
addCmdExample(nameEmphasized() + "<radiusX> [radiusZ] ^player <name> - center on player.");
|
||||||
|
helpText = "Set a border for a world, with several options for defining the center location. [world] is " +
|
||||||
|
"optional for players and defaults to the world the player is in. If [radiusZ] is not specified, the " +
|
||||||
|
"radiusX value will be used for both. The <x> and <z> coordinates can be decimal values (ex. 1.234).";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdSet extends WBCmd
|
@Override
|
||||||
{
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
public CmdSet()
|
// passsing a single parameter (radiusX) is only acceptable from player
|
||||||
{
|
if ((params.size() == 1) && player == null) {
|
||||||
name = permission = "set";
|
sendErrorAndHelp(sender, "You have not provided a sufficient number of parameters.");
|
||||||
hasWorldNameInput = true;
|
return;
|
||||||
consoleRequiresWorldName = false;
|
}
|
||||||
minParams = 1;
|
|
||||||
maxParams = 4;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasizedW() + "<radiusX> [radiusZ] <x> <z> - use x/z coords.");
|
// "set" command from player or console, world specified
|
||||||
addCmdExample(nameEmphasizedW() + "<radiusX> [radiusZ] ^spawn - use spawn point.");
|
if (worldName != null) {
|
||||||
addCmdExample(nameEmphasized() + "<radiusX> [radiusZ] - set border, centered on you.", true, false, true);
|
if (params.size() == 2 && !params.get(params.size() - 1).equalsIgnoreCase("spawn")) { // command can only be this short if "spawn" is specified rather than x + z or player name
|
||||||
addCmdExample(nameEmphasized() + "<radiusX> [radiusZ] ^player <name> - center on player.");
|
sendErrorAndHelp(sender, "You have not provided a sufficient number of arguments.");
|
||||||
helpText = "Set a border for a world, with several options for defining the center location. [world] is " +
|
return;
|
||||||
"optional for players and defaults to the world the player is in. If [radiusZ] is not specified, the " +
|
}
|
||||||
"radiusX value will be used for both. The <x> and <z> coordinates can be decimal values (ex. 1.234).";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
World world = sender.getServer().getWorld(worldName);
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
if (world == null) {
|
||||||
{
|
if (params.get(params.size() - 1).equalsIgnoreCase("spawn")) {
|
||||||
// passsing a single parameter (radiusX) is only acceptable from player
|
sendErrorAndHelp(sender, "The world you specified (\"" + worldName + "\") could not be found on the server, so the spawn point cannot be determined.");
|
||||||
if ((params.size() == 1) && player == null)
|
return;
|
||||||
{
|
}
|
||||||
sendErrorAndHelp(sender, "You have not provided a sufficient number of parameters.");
|
sender.sendMessage("The world you specified (\"" + worldName + "\") could not be found on the server, but data for it will be stored anyway.");
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
|
// "set" command from player using current world since it isn't specified, or allowed from console only if player name is specified
|
||||||
|
else {
|
||||||
|
if (player == null) {
|
||||||
|
if (!params.get(params.size() - 2).equalsIgnoreCase("player")) { // command can only be called by console without world specified if player is specified instead
|
||||||
|
sendErrorAndHelp(sender, "You must specify a world name from console if not specifying a player name.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
player = Bukkit.getPlayer(params.get(params.size() - 1));
|
||||||
|
if (player == null || !player.isOnline()) {
|
||||||
|
sendErrorAndHelp(sender, "The player you specified (\"" + params.get(params.size() - 1) + "\") does not appear to be online.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
worldName = player.getWorld().getName();
|
||||||
|
}
|
||||||
|
|
||||||
// "set" command from player or console, world specified
|
int radiusX, radiusZ;
|
||||||
if (worldName != null)
|
double x, z;
|
||||||
{
|
int radiusCount = params.size();
|
||||||
if (params.size() == 2 && ! params.get(params.size() - 1).equalsIgnoreCase("spawn"))
|
|
||||||
{ // command can only be this short if "spawn" is specified rather than x + z or player name
|
|
||||||
sendErrorAndHelp(sender, "You have not provided a sufficient number of arguments.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
World world = sender.getServer().getWorld(worldName);
|
try {
|
||||||
if (world == null)
|
if (params.get(params.size() - 1).equalsIgnoreCase("spawn")) { // "spawn" specified for x/z coordinates
|
||||||
{
|
Location loc = sender.getServer().getWorld(worldName).getSpawnLocation();
|
||||||
if (params.get(params.size() - 1).equalsIgnoreCase("spawn"))
|
x = loc.getX();
|
||||||
{
|
z = loc.getZ();
|
||||||
sendErrorAndHelp(sender, "The world you specified (\"" + worldName + "\") could not be found on the server, so the spawn point cannot be determined.");
|
radiusCount -= 1;
|
||||||
return;
|
} else if (params.size() > 2 && params.get(params.size() - 2).equalsIgnoreCase("player")) { // player name specified for x/z coordinates
|
||||||
}
|
Player playerT = Bukkit.getPlayer(params.get(params.size() - 1));
|
||||||
sender.sendMessage("The world you specified (\"" + worldName + "\") could not be found on the server, but data for it will be stored anyway.");
|
if (playerT == null || !playerT.isOnline()) {
|
||||||
}
|
sendErrorAndHelp(sender, "The player you specified (\"" + params.get(params.size() - 1) + "\") does not appear to be online.");
|
||||||
}
|
return;
|
||||||
// "set" command from player using current world since it isn't specified, or allowed from console only if player name is specified
|
}
|
||||||
else
|
worldName = playerT.getWorld().getName();
|
||||||
{
|
x = playerT.getLocation().getX();
|
||||||
if (player == null)
|
z = playerT.getLocation().getZ();
|
||||||
{
|
radiusCount -= 2;
|
||||||
if (! params.get(params.size() - 2).equalsIgnoreCase("player"))
|
} else {
|
||||||
{ // command can only be called by console without world specified if player is specified instead
|
if (player == null || radiusCount > 2) { // x and z specified
|
||||||
sendErrorAndHelp(sender, "You must specify a world name from console if not specifying a player name.");
|
x = Double.parseDouble(params.get(params.size() - 2));
|
||||||
return;
|
z = Double.parseDouble(params.get(params.size() - 1));
|
||||||
}
|
radiusCount -= 2;
|
||||||
player = Bukkit.getPlayer(params.get(params.size() - 1));
|
} else { // using coordinates of command sender (player)
|
||||||
if (player == null || ! player.isOnline())
|
x = player.getLocation().getX();
|
||||||
{
|
z = player.getLocation().getZ();
|
||||||
sendErrorAndHelp(sender, "The player you specified (\"" + params.get(params.size() - 1) + "\") does not appear to be online.");
|
}
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
worldName = player.getWorld().getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
int radiusX, radiusZ;
|
radiusX = Integer.parseInt(params.get(0));
|
||||||
double x, z;
|
if (radiusCount < 2)
|
||||||
int radiusCount = params.size();
|
radiusZ = radiusX;
|
||||||
|
else
|
||||||
|
radiusZ = Integer.parseInt(params.get(1));
|
||||||
|
|
||||||
try
|
if (radiusX < Config.KnockBack() || radiusZ < Config.KnockBack()) {
|
||||||
{
|
sendErrorAndHelp(sender, "Radius value(s) must be more than the knockback distance.");
|
||||||
if (params.get(params.size() - 1).equalsIgnoreCase("spawn"))
|
return;
|
||||||
{ // "spawn" specified for x/z coordinates
|
}
|
||||||
Location loc = sender.getServer().getWorld(worldName).getSpawnLocation();
|
} catch (NumberFormatException ex) {
|
||||||
x = loc.getX();
|
sendErrorAndHelp(sender, "Radius value(s) must be integers and x and z values must be numerical.");
|
||||||
z = loc.getZ();
|
return;
|
||||||
radiusCount -= 1;
|
}
|
||||||
}
|
|
||||||
else if (params.size() > 2 && params.get(params.size() - 2).equalsIgnoreCase("player"))
|
|
||||||
{ // player name specified for x/z coordinates
|
|
||||||
Player playerT = Bukkit.getPlayer(params.get(params.size() - 1));
|
|
||||||
if (playerT == null || ! playerT.isOnline())
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "The player you specified (\"" + params.get(params.size() - 1) + "\") does not appear to be online.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
worldName = playerT.getWorld().getName();
|
|
||||||
x = playerT.getLocation().getX();
|
|
||||||
z = playerT.getLocation().getZ();
|
|
||||||
radiusCount -= 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (player == null || radiusCount > 2)
|
|
||||||
{ // x and z specified
|
|
||||||
x = Double.parseDouble(params.get(params.size() - 2));
|
|
||||||
z = Double.parseDouble(params.get(params.size() - 1));
|
|
||||||
radiusCount -= 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // using coordinates of command sender (player)
|
|
||||||
x = player.getLocation().getX();
|
|
||||||
z = player.getLocation().getZ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
radiusX = Integer.parseInt(params.get(0));
|
Config.setBorder(worldName, radiusX, radiusZ, x, z);
|
||||||
if (radiusCount < 2)
|
sender.sendMessage("Border has been set. " + Config.BorderDescription(worldName));
|
||||||
radiusZ = radiusX;
|
}
|
||||||
else
|
|
||||||
radiusZ = Integer.parseInt(params.get(1));
|
|
||||||
|
|
||||||
if (radiusX < Config.KnockBack() || radiusZ < Config.KnockBack())
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "Radius value(s) must be more than the knockback distance.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(NumberFormatException ex)
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "Radius value(s) must be integers and x and z values must be numerical.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Config.setBorder(worldName, radiusX, radiusZ, x, z);
|
|
||||||
sender.sendMessage("Border has been set. " + Config.BorderDescription(worldName));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,58 +1,48 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.World;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdSetcorners extends WBCmd {
|
||||||
|
public CmdSetcorners() {
|
||||||
|
name = "setcorners";
|
||||||
|
permission = "set";
|
||||||
|
hasWorldNameInput = true;
|
||||||
|
minParams = maxParams = 4;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasizedW() + "<x1> <z1> <x2> <z2> - corner coords.");
|
||||||
|
helpText = "This is an alternate way to set a border, by specifying the X and Z coordinates of two opposite " +
|
||||||
|
"corners of the border area ((x1, z1) to (x2, z2)). [world] is optional for players and defaults to the " +
|
||||||
|
"world the player is in.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdSetcorners extends WBCmd
|
@Override
|
||||||
{
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
public CmdSetcorners()
|
if (worldName == null) {
|
||||||
{
|
worldName = player.getWorld().getName();
|
||||||
name = "setcorners";
|
} else {
|
||||||
permission = "set";
|
World worldTest = sender.getServer().getWorld(worldName);
|
||||||
hasWorldNameInput = true;
|
if (worldTest == null)
|
||||||
minParams = maxParams = 4;
|
sender.sendMessage("The world you specified (\"" + worldName + "\") could not be found on the server, but data for it will be stored anyway.");
|
||||||
|
}
|
||||||
|
|
||||||
addCmdExample(nameEmphasizedW() + "<x1> <z1> <x2> <z2> - corner coords.");
|
try {
|
||||||
helpText = "This is an alternate way to set a border, by specifying the X and Z coordinates of two opposite " +
|
double x1 = Double.parseDouble(params.get(0));
|
||||||
"corners of the border area ((x1, z1) to (x2, z2)). [world] is optional for players and defaults to the " +
|
double z1 = Double.parseDouble(params.get(1));
|
||||||
"world the player is in.";
|
double x2 = Double.parseDouble(params.get(2));
|
||||||
}
|
double z2 = Double.parseDouble(params.get(3));
|
||||||
|
Config.setBorderCorners(worldName, x1, z1, x2, z2);
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
sendErrorAndHelp(sender, "The x1, z1, x2, and z2 coordinate values must be numerical.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
if (player != null)
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
sender.sendMessage("Border has been set. " + Config.BorderDescription(worldName));
|
||||||
{
|
}
|
||||||
if (worldName == null)
|
|
||||||
{
|
|
||||||
worldName = player.getWorld().getName();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
World worldTest = sender.getServer().getWorld(worldName);
|
|
||||||
if (worldTest == null)
|
|
||||||
sender.sendMessage("The world you specified (\"" + worldName + "\") could not be found on the server, but data for it will be stored anyway.");
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
double x1 = Double.parseDouble(params.get(0));
|
|
||||||
double z1 = Double.parseDouble(params.get(1));
|
|
||||||
double x2 = Double.parseDouble(params.get(2));
|
|
||||||
double z2 = Double.parseDouble(params.get(3));
|
|
||||||
Config.setBorderCorners(worldName, x1, z1, x2, z2);
|
|
||||||
}
|
|
||||||
catch(NumberFormatException ex)
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "The x1, z1, x2, and z2 coordinate values must be numerical.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(player != null)
|
|
||||||
sender.sendMessage("Border has been set. " + Config.BorderDescription(worldName));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,48 +1,42 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdSetmsg extends WBCmd {
|
||||||
|
public CmdSetmsg() {
|
||||||
|
name = permission = "setmsg";
|
||||||
|
minParams = 1;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "<text> - set border message.");
|
||||||
|
helpText = "Default value: \"&cYou have reached the edge of this world.\". This command lets you set the message shown to players who are knocked back from the border.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdSetmsg extends WBCmd
|
@Override
|
||||||
{
|
public void cmdStatus(CommandSender sender) {
|
||||||
public CmdSetmsg()
|
sender.sendMessage(C_HEAD + "Border message is set to:");
|
||||||
{
|
sender.sendMessage(Config.MessageRaw());
|
||||||
name = permission = "setmsg";
|
sender.sendMessage(C_HEAD + "Formatted border message:");
|
||||||
minParams = 1;
|
sender.sendMessage(Config.Message());
|
||||||
|
}
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "<text> - set border message.");
|
@Override
|
||||||
helpText = "Default value: \"&cYou have reached the edge of this world.\". This command lets you set the message shown to players who are knocked back from the border.";
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
}
|
StringBuilder message = new StringBuilder();
|
||||||
|
boolean first = true;
|
||||||
|
for (String param : params) {
|
||||||
|
if (!first)
|
||||||
|
message.append(" ");
|
||||||
|
message.append(param);
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
Config.setMessage(message.toString());
|
||||||
public void cmdStatus(CommandSender sender)
|
|
||||||
{
|
|
||||||
sender.sendMessage(C_HEAD + "Border message is set to:");
|
|
||||||
sender.sendMessage(Config.MessageRaw());
|
|
||||||
sender.sendMessage(C_HEAD + "Formatted border message:");
|
|
||||||
sender.sendMessage(Config.Message());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
cmdStatus(sender);
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
}
|
||||||
{
|
|
||||||
StringBuilder message = new StringBuilder();
|
|
||||||
boolean first = true;
|
|
||||||
for (String param : params)
|
|
||||||
{
|
|
||||||
if (!first)
|
|
||||||
message.append(" ");
|
|
||||||
message.append(param);
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Config.setMessage(message.toString());
|
|
||||||
|
|
||||||
cmdStatus(sender);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,49 +1,43 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdShape extends WBCmd {
|
||||||
|
public CmdShape() {
|
||||||
|
name = permission = "shape";
|
||||||
|
minParams = maxParams = 1;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "<round|square> - set the default border shape.");
|
||||||
|
addCmdExample(nameEmphasized() + "<elliptic|rectangular> - same as above.");
|
||||||
|
helpText = "Default value: round/elliptic. The default border shape will be used on all worlds which don't " +
|
||||||
|
"have an individual shape set using the " + commandEmphasized("wshape") + C_DESC + "command. Elliptic " +
|
||||||
|
"and round work the same, as rectangular and square do. The difference is down to whether the X and Z " +
|
||||||
|
"radius are the same.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdShape extends WBCmd
|
@Override
|
||||||
{
|
public void cmdStatus(CommandSender sender) {
|
||||||
public CmdShape()
|
sender.sendMessage(C_HEAD + "The default border shape for all worlds is currently set to \"" + Config.ShapeName() + "\".");
|
||||||
{
|
}
|
||||||
name = permission = "shape";
|
|
||||||
minParams = maxParams = 1;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "<round|square> - set the default border shape.");
|
@Override
|
||||||
addCmdExample(nameEmphasized() + "<elliptic|rectangular> - same as above.");
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
helpText = "Default value: round/elliptic. The default border shape will be used on all worlds which don't " +
|
String shape = params.get(0).toLowerCase();
|
||||||
"have an individual shape set using the " + commandEmphasized("wshape") + C_DESC + "command. Elliptic " +
|
if (shape.equals("rectangular") || shape.equals("square"))
|
||||||
"and round work the same, as rectangular and square do. The difference is down to whether the X and Z " +
|
Config.setShape(false);
|
||||||
"radius are the same.";
|
else if (shape.equals("elliptic") || shape.equals("round"))
|
||||||
}
|
Config.setShape(true);
|
||||||
|
else {
|
||||||
|
sendErrorAndHelp(sender, "You must specify one of the 4 valid shape names below.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
if (player != null)
|
||||||
public void cmdStatus(CommandSender sender)
|
cmdStatus(sender);
|
||||||
{
|
}
|
||||||
sender.sendMessage(C_HEAD + "The default border shape for all worlds is currently set to \"" + Config.ShapeName() + "\".");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
|
||||||
{
|
|
||||||
String shape = params.get(0).toLowerCase();
|
|
||||||
if (shape.equals("rectangular") || shape.equals("square"))
|
|
||||||
Config.setShape(false);
|
|
||||||
else if (shape.equals("elliptic") || shape.equals("round"))
|
|
||||||
Config.setShape(true);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "You must specify one of the 4 valid shape names below.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player != null)
|
|
||||||
cmdStatus(sender);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,175 +1,152 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import com.wimbli.WorldBorder.CoordXZ;
|
||||||
|
import com.wimbli.WorldBorder.WorldBorder;
|
||||||
|
import com.wimbli.WorldBorder.WorldTrimTask;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdTrim extends WBCmd {
|
||||||
|
/* with "view-distance=10" in server.properties on a fast VM test server and "Render Distance: Far" in client,
|
||||||
|
* hitting border during testing was loading 11+ chunks beyond the border in a couple of directions (10 chunks in
|
||||||
|
* the other two directions). This could be worse on a more loaded or worse server, so:
|
||||||
|
*/
|
||||||
|
private final int defaultPadding = CoordXZ.chunkToBlock(13);
|
||||||
|
private String trimWorld = "";
|
||||||
|
private int trimFrequency = 5000;
|
||||||
|
private int trimPadding = defaultPadding;
|
||||||
|
|
||||||
|
public CmdTrim() {
|
||||||
|
name = permission = "trim";
|
||||||
|
hasWorldNameInput = true;
|
||||||
|
consoleRequiresWorldName = false;
|
||||||
|
minParams = 0;
|
||||||
|
maxParams = 2;
|
||||||
|
|
||||||
public class CmdTrim extends WBCmd
|
addCmdExample(nameEmphasizedW() + "[freq] [pad] - trim world outside of border.");
|
||||||
{
|
helpText = "This command will remove chunks which are outside the world's border. [freq] is the frequency " +
|
||||||
public CmdTrim()
|
"of chunks per second that will be checked (default 5000). [pad] is the number of blocks padding kept " +
|
||||||
{
|
"beyond the border itself (default 208, to cover player visual range).";
|
||||||
name = permission = "trim";
|
}
|
||||||
hasWorldNameInput = true;
|
|
||||||
consoleRequiresWorldName = false;
|
|
||||||
minParams = 0;
|
|
||||||
maxParams = 2;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasizedW() + "[freq] [pad] - trim world outside of border.");
|
@Override
|
||||||
helpText = "This command will remove chunks which are outside the world's border. [freq] is the frequency " +
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
"of chunks per second that will be checked (default 5000). [pad] is the number of blocks padding kept " +
|
boolean confirm = false;
|
||||||
"beyond the border itself (default 208, to cover player visual range).";
|
// check for "cancel", "pause", or "confirm"
|
||||||
}
|
if (params.size() >= 1) {
|
||||||
|
String check = params.get(0).toLowerCase();
|
||||||
|
|
||||||
@Override
|
if (check.equals("cancel") || check.equals("stop")) {
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
if (!makeSureTrimIsRunning(sender))
|
||||||
{
|
return;
|
||||||
boolean confirm = false;
|
sender.sendMessage(C_HEAD + "Cancelling the world map trimming task.");
|
||||||
// check for "cancel", "pause", or "confirm"
|
trimDefaults();
|
||||||
if (params.size() >= 1)
|
Config.StopTrimTask();
|
||||||
{
|
return;
|
||||||
String check = params.get(0).toLowerCase();
|
} else if (check.equals("pause")) {
|
||||||
|
if (!makeSureTrimIsRunning(sender))
|
||||||
|
return;
|
||||||
|
Config.trimTask.pause();
|
||||||
|
sender.sendMessage(C_HEAD + "The world map trimming task is now " + (Config.trimTask.isPaused() ? "" : "un") + "paused.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (check.equals("cancel") || check.equals("stop"))
|
confirm = check.equals("confirm");
|
||||||
{
|
}
|
||||||
if (!makeSureTrimIsRunning(sender))
|
|
||||||
return;
|
|
||||||
sender.sendMessage(C_HEAD + "Cancelling the world map trimming task.");
|
|
||||||
trimDefaults();
|
|
||||||
Config.StopTrimTask();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (check.equals("pause"))
|
|
||||||
{
|
|
||||||
if (!makeSureTrimIsRunning(sender))
|
|
||||||
return;
|
|
||||||
Config.trimTask.pause();
|
|
||||||
sender.sendMessage(C_HEAD + "The world map trimming task is now " + (Config.trimTask.isPaused() ? "" : "un") + "paused.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
confirm = check.equals("confirm");
|
// if not just confirming, make sure a world name is available
|
||||||
}
|
if (worldName == null && !confirm) {
|
||||||
|
if (player != null)
|
||||||
|
worldName = player.getWorld().getName();
|
||||||
|
else {
|
||||||
|
sendErrorAndHelp(sender, "You must specify a world!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if not just confirming, make sure a world name is available
|
// colorized "/wb trim "
|
||||||
if (worldName == null && !confirm)
|
String cmd = cmd(sender) + nameEmphasized() + C_CMD;
|
||||||
{
|
|
||||||
if (player != null)
|
|
||||||
worldName = player.getWorld().getName();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "You must specify a world!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// colorized "/wb trim "
|
// make sure Trim isn't already running
|
||||||
String cmd = cmd(sender) + nameEmphasized() + C_CMD;
|
if (Config.trimTask != null && Config.trimTask.valid()) {
|
||||||
|
sender.sendMessage(C_ERR + "The world map trimming task is already running.");
|
||||||
|
sender.sendMessage(C_DESC + "You can cancel at any time with " + cmd + "cancel" + C_DESC + ", or pause/unpause with " + cmd + "pause" + C_DESC + ".");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// make sure Trim isn't already running
|
// set frequency and/or padding if those were specified
|
||||||
if (Config.trimTask != null && Config.trimTask.valid())
|
try {
|
||||||
{
|
if (params.size() >= 1 && !confirm)
|
||||||
sender.sendMessage(C_ERR + "The world map trimming task is already running.");
|
trimFrequency = Math.abs(Integer.parseInt(params.get(0)));
|
||||||
sender.sendMessage(C_DESC + "You can cancel at any time with " + cmd + "cancel" + C_DESC + ", or pause/unpause with " + cmd + "pause" + C_DESC + ".");
|
if (params.size() >= 2 && !confirm)
|
||||||
return;
|
trimPadding = Math.abs(Integer.parseInt(params.get(1)));
|
||||||
}
|
} catch (NumberFormatException ex) {
|
||||||
|
sendErrorAndHelp(sender, "The frequency and padding values must be integers.");
|
||||||
|
trimDefaults();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (trimFrequency <= 0) {
|
||||||
|
sendErrorAndHelp(sender, "The frequency value must be greater than zero.");
|
||||||
|
trimDefaults();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// set frequency and/or padding if those were specified
|
// set world if it was specified
|
||||||
try
|
if (worldName != null)
|
||||||
{
|
trimWorld = worldName;
|
||||||
if (params.size() >= 1 && !confirm)
|
|
||||||
trimFrequency = Math.abs(Integer.parseInt(params.get(0)));
|
|
||||||
if (params.size() >= 2 && !confirm)
|
|
||||||
trimPadding = Math.abs(Integer.parseInt(params.get(1)));
|
|
||||||
}
|
|
||||||
catch(NumberFormatException ex)
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "The frequency and padding values must be integers.");
|
|
||||||
trimDefaults();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (trimFrequency <= 0)
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "The frequency value must be greater than zero.");
|
|
||||||
trimDefaults();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set world if it was specified
|
if (confirm) { // command confirmed, go ahead with it
|
||||||
if (worldName != null)
|
if (trimWorld.isEmpty()) {
|
||||||
trimWorld = worldName;
|
sendErrorAndHelp(sender, "You must first use this command successfully without confirming.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (confirm)
|
if (player != null)
|
||||||
{ // command confirmed, go ahead with it
|
Config.log("Trimming world beyond border at the command of player \"" + player.getName() + "\".");
|
||||||
if (trimWorld.isEmpty())
|
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "You must first use this command successfully without confirming.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player != null)
|
int ticks = 1, repeats = 1;
|
||||||
Config.log("Trimming world beyond border at the command of player \"" + player.getName() + "\".");
|
if (trimFrequency > 20)
|
||||||
|
repeats = trimFrequency / 20;
|
||||||
|
else
|
||||||
|
ticks = 20 / trimFrequency;
|
||||||
|
|
||||||
int ticks = 1, repeats = 1;
|
Config.trimTask = new WorldTrimTask(Bukkit.getServer(), player, trimWorld, trimPadding, repeats);
|
||||||
if (trimFrequency > 20)
|
if (Config.trimTask.valid()) {
|
||||||
repeats = trimFrequency / 20;
|
int task = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(WorldBorder.plugin, Config.trimTask, ticks, ticks);
|
||||||
else
|
Config.trimTask.setTaskID(task);
|
||||||
ticks = 20 / trimFrequency;
|
sender.sendMessage("WorldBorder map trimming task for world \"" + trimWorld + "\" started.");
|
||||||
|
} else
|
||||||
|
sender.sendMessage(C_ERR + "The world map trimming task failed to start.");
|
||||||
|
|
||||||
Config.trimTask = new WorldTrimTask(Bukkit.getServer(), player, trimWorld, trimPadding, repeats);
|
trimDefaults();
|
||||||
if (Config.trimTask.valid())
|
} else {
|
||||||
{
|
if (trimWorld.isEmpty()) {
|
||||||
int task = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(WorldBorder.plugin, Config.trimTask, ticks, ticks);
|
sendErrorAndHelp(sender, "You must first specify a valid world.");
|
||||||
Config.trimTask.setTaskID(task);
|
return;
|
||||||
sender.sendMessage("WorldBorder map trimming task for world \"" + trimWorld + "\" started.");
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
sender.sendMessage(C_ERR + "The world map trimming task failed to start.");
|
|
||||||
|
|
||||||
trimDefaults();
|
sender.sendMessage(C_HEAD + "World trimming task is ready for world \"" + trimWorld + "\", attempting to process up to " + trimFrequency + " chunks per second (default 20). The map will be trimmed past " + trimPadding + " blocks beyond the border (default " + defaultPadding + ").");
|
||||||
}
|
sender.sendMessage(C_HEAD + "This process can take a very long time depending on the world's overall size. Also, depending on the chunk processing rate, players may experience lag for the duration.");
|
||||||
else
|
sender.sendMessage(C_DESC + "You should now use " + cmd + "confirm" + C_DESC + " to start the process.");
|
||||||
{
|
sender.sendMessage(C_DESC + "You can cancel at any time with " + cmd + "cancel" + C_DESC + ", or pause/unpause with " + cmd + "pause" + C_DESC + ".");
|
||||||
if (trimWorld.isEmpty())
|
}
|
||||||
{
|
}
|
||||||
sendErrorAndHelp(sender, "You must first specify a valid world.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sender.sendMessage(C_HEAD + "World trimming task is ready for world \"" + trimWorld + "\", attempting to process up to " + trimFrequency + " chunks per second (default 20). The map will be trimmed past " + trimPadding + " blocks beyond the border (default " + defaultPadding + ").");
|
private void trimDefaults() {
|
||||||
sender.sendMessage(C_HEAD + "This process can take a very long time depending on the world's overall size. Also, depending on the chunk processing rate, players may experience lag for the duration.");
|
trimWorld = "";
|
||||||
sender.sendMessage(C_DESC + "You should now use " + cmd + "confirm" + C_DESC + " to start the process.");
|
trimFrequency = 5000;
|
||||||
sender.sendMessage(C_DESC + "You can cancel at any time with " + cmd + "cancel" + C_DESC + ", or pause/unpause with " + cmd + "pause" + C_DESC + ".");
|
trimPadding = defaultPadding;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
private boolean makeSureTrimIsRunning(CommandSender sender) {
|
||||||
/* with "view-distance=10" in server.properties on a fast VM test server and "Render Distance: Far" in client,
|
if (Config.trimTask != null && Config.trimTask.valid())
|
||||||
* hitting border during testing was loading 11+ chunks beyond the border in a couple of directions (10 chunks in
|
return true;
|
||||||
* the other two directions). This could be worse on a more loaded or worse server, so:
|
sendErrorAndHelp(sender, "The world map trimming task is not currently running.");
|
||||||
*/
|
return false;
|
||||||
private final int defaultPadding = CoordXZ.chunkToBlock(13);
|
}
|
||||||
|
|
||||||
private String trimWorld = "";
|
|
||||||
private int trimFrequency = 5000;
|
|
||||||
private int trimPadding = defaultPadding;
|
|
||||||
|
|
||||||
private void trimDefaults()
|
|
||||||
{
|
|
||||||
trimWorld = "";
|
|
||||||
trimFrequency = 5000;
|
|
||||||
trimPadding = defaultPadding;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean makeSureTrimIsRunning(CommandSender sender)
|
|
||||||
{
|
|
||||||
if (Config.trimTask != null && Config.trimTask.valid())
|
|
||||||
return true;
|
|
||||||
sendErrorAndHelp(sender, "The world map trimming task is not currently running.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,40 +1,34 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdWhoosh extends WBCmd {
|
||||||
|
public CmdWhoosh() {
|
||||||
|
name = permission = "whoosh";
|
||||||
|
minParams = maxParams = 1;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "<on|off> - turn knockback effect on or off.");
|
||||||
|
helpText = "Default value: on. This will show a particle effect and play a sound where a player is knocked " +
|
||||||
|
"back from the border.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdWhoosh extends WBCmd
|
@Override
|
||||||
{
|
public void cmdStatus(CommandSender sender) {
|
||||||
public CmdWhoosh()
|
sender.sendMessage(C_HEAD + "\"Whoosh\" knockback effect is " + enabledColored(Config.whooshEffect()) + C_HEAD + ".");
|
||||||
{
|
}
|
||||||
name = permission = "whoosh";
|
|
||||||
minParams = maxParams = 1;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "<on|off> - turn knockback effect on or off.");
|
@Override
|
||||||
helpText = "Default value: on. This will show a particle effect and play a sound where a player is knocked " +
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
"back from the border.";
|
Config.setWhooshEffect(strAsBool(params.get(0)));
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (player != null) {
|
||||||
public void cmdStatus(CommandSender sender)
|
Config.log((Config.whooshEffect() ? "Enabled" : "Disabled") + " \"whoosh\" knockback effect at the command of player \"" + player.getName() + "\".");
|
||||||
{
|
cmdStatus(sender);
|
||||||
sender.sendMessage(C_HEAD + "\"Whoosh\" knockback effect is " + enabledColored(Config.whooshEffect()) + C_HEAD + ".");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
|
||||||
{
|
|
||||||
Config.setWhooshEffect(strAsBool(params.get(0)));
|
|
||||||
|
|
||||||
if (player != null)
|
|
||||||
{
|
|
||||||
Config.log((Config.whooshEffect() ? "Enabled" : "Disabled") + " \"whoosh\" knockback effect at the command of player \"" + player.getName() + "\".");
|
|
||||||
cmdStatus(sender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,61 +1,54 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.BorderData;
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdWrap extends WBCmd {
|
||||||
|
public CmdWrap() {
|
||||||
|
name = permission = "wrap";
|
||||||
|
minParams = 1;
|
||||||
|
maxParams = 2;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "{world} <on|off> - can make border crossings wrap.");
|
||||||
|
helpText = "When border wrapping is enabled for a world, players will be sent around to the opposite edge " +
|
||||||
|
"of the border when they cross it instead of being knocked back. [world] is optional for players and " +
|
||||||
|
"defaults to the world the player is in.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdWrap extends WBCmd
|
@Override
|
||||||
{
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
public CmdWrap()
|
if (player == null && params.size() == 1) {
|
||||||
{
|
sendErrorAndHelp(sender, "When running this command from console, you must specify a world.");
|
||||||
name = permission = "wrap";
|
return;
|
||||||
minParams = 1;
|
}
|
||||||
maxParams = 2;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "{world} <on|off> - can make border crossings wrap.");
|
boolean wrap = false;
|
||||||
helpText = "When border wrapping is enabled for a world, players will be sent around to the opposite edge " +
|
|
||||||
"of the border when they cross it instead of being knocked back. [world] is optional for players and " +
|
|
||||||
"defaults to the world the player is in.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
// world and wrap on/off specified
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
if (params.size() == 2) {
|
||||||
{
|
worldName = params.get(0);
|
||||||
if (player == null && params.size() == 1)
|
wrap = strAsBool(params.get(1));
|
||||||
{
|
}
|
||||||
sendErrorAndHelp(sender, "When running this command from console, you must specify a world.");
|
// no world specified, just wrap on/off
|
||||||
return;
|
else {
|
||||||
}
|
worldName = player.getWorld().getName();
|
||||||
|
wrap = strAsBool(params.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
boolean wrap = false;
|
BorderData border = Config.Border(worldName);
|
||||||
|
if (border == null) {
|
||||||
|
sendErrorAndHelp(sender, "This world (\"" + worldName + "\") does not have a border set.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// world and wrap on/off specified
|
border.setWrapping(wrap);
|
||||||
if (params.size() == 2)
|
Config.setBorder(worldName, border, false);
|
||||||
{
|
|
||||||
worldName = params.get(0);
|
|
||||||
wrap = strAsBool(params.get(1));
|
|
||||||
}
|
|
||||||
// no world specified, just wrap on/off
|
|
||||||
else
|
|
||||||
{
|
|
||||||
worldName = player.getWorld().getName();
|
|
||||||
wrap = strAsBool(params.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
BorderData border = Config.Border(worldName);
|
sender.sendMessage("Border for world \"" + worldName + "\" is now set to " + (wrap ? "" : "not ") + "wrap around.");
|
||||||
if (border == null)
|
}
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "This world (\"" + worldName + "\") does not have a border set.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
border.setWrapping(wrap);
|
|
||||||
Config.setBorder(worldName, border, false);
|
|
||||||
|
|
||||||
sender.sendMessage("Border for world \"" + worldName + "\" is now set to " + (wrap ? "" : "not ") + "wrap around.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,69 +1,62 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import com.wimbli.WorldBorder.BorderData;
|
||||||
|
import com.wimbli.WorldBorder.Config;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.command.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.wimbli.WorldBorder.*;
|
public class CmdWshape extends WBCmd {
|
||||||
|
public CmdWshape() {
|
||||||
|
name = permission = "wshape";
|
||||||
|
minParams = 1;
|
||||||
|
maxParams = 2;
|
||||||
|
|
||||||
|
addCmdExample(nameEmphasized() + "{world} <elliptic|rectangular|default> - shape");
|
||||||
|
addCmdExample(C_DESC + " override for a single world.", true, true, false);
|
||||||
|
addCmdExample(nameEmphasized() + "{world} <round|square|default> - same as above.");
|
||||||
|
helpText = "This will override the default border shape for a single world. The value \"default\" implies " +
|
||||||
|
"a world is just using the default border shape. See the " + commandEmphasized("shape") + C_DESC +
|
||||||
|
"command for more info and to set the default border shape.";
|
||||||
|
}
|
||||||
|
|
||||||
public class CmdWshape extends WBCmd
|
@Override
|
||||||
{
|
public void execute(CommandSender sender, Player player, List<String> params, String worldName) {
|
||||||
public CmdWshape()
|
if (player == null && params.size() == 1) {
|
||||||
{
|
sendErrorAndHelp(sender, "When running this command from console, you must specify a world.");
|
||||||
name = permission = "wshape";
|
return;
|
||||||
minParams = 1;
|
}
|
||||||
maxParams = 2;
|
|
||||||
|
|
||||||
addCmdExample(nameEmphasized() + "{world} <elliptic|rectangular|default> - shape");
|
String shapeName = "";
|
||||||
addCmdExample(C_DESC + " override for a single world.", true, true, false);
|
|
||||||
addCmdExample(nameEmphasized() + "{world} <round|square|default> - same as above.");
|
|
||||||
helpText = "This will override the default border shape for a single world. The value \"default\" implies " +
|
|
||||||
"a world is just using the default border shape. See the " + commandEmphasized("shape") + C_DESC +
|
|
||||||
"command for more info and to set the default border shape.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
// world and shape specified
|
||||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
if (params.size() == 2) {
|
||||||
{
|
worldName = params.get(0);
|
||||||
if (player == null && params.size() == 1)
|
shapeName = params.get(1).toLowerCase();
|
||||||
{
|
}
|
||||||
sendErrorAndHelp(sender, "When running this command from console, you must specify a world.");
|
// no world specified, just shape
|
||||||
return;
|
else {
|
||||||
}
|
worldName = player.getWorld().getName();
|
||||||
|
shapeName = params.get(0).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
String shapeName = "";
|
BorderData border = Config.Border(worldName);
|
||||||
|
if (border == null) {
|
||||||
|
sendErrorAndHelp(sender, "This world (\"" + worldName + "\") does not have a border set.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// world and shape specified
|
Boolean shape = null;
|
||||||
if (params.size() == 2)
|
if (shapeName.equals("rectangular") || shapeName.equals("square"))
|
||||||
{
|
shape = false;
|
||||||
worldName = params.get(0);
|
else if (shapeName.equals("elliptic") || shapeName.equals("round"))
|
||||||
shapeName = params.get(1).toLowerCase();
|
shape = true;
|
||||||
}
|
|
||||||
// no world specified, just shape
|
|
||||||
else
|
|
||||||
{
|
|
||||||
worldName = player.getWorld().getName();
|
|
||||||
shapeName = params.get(0).toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
BorderData border = Config.Border(worldName);
|
border.setShape(shape);
|
||||||
if (border == null)
|
Config.setBorder(worldName, border, false);
|
||||||
{
|
|
||||||
sendErrorAndHelp(sender, "This world (\"" + worldName + "\") does not have a border set.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Boolean shape = null;
|
sender.sendMessage("Border shape for world \"" + worldName + "\" is now set to \"" + Config.ShapeName(shape) + "\".");
|
||||||
if (shapeName.equals("rectangular") || shapeName.equals("square"))
|
}
|
||||||
shape = false;
|
|
||||||
else if (shapeName.equals("elliptic") || shapeName.equals("round"))
|
|
||||||
shape = true;
|
|
||||||
|
|
||||||
border.setShape(shape);
|
|
||||||
Config.setBorder(worldName, border, false);
|
|
||||||
|
|
||||||
sender.sendMessage("Border shape for world \"" + worldName + "\" is now set to \"" + Config.ShapeName(shape) + "\".");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,147 +1,128 @@
|
|||||||
package com.wimbli.WorldBorder.cmd;
|
package com.wimbli.WorldBorder.cmd;
|
||||||
|
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.command.*;
|
public abstract class WBCmd {
|
||||||
import org.bukkit.entity.Player;
|
/*
|
||||||
|
* Primary variables, should be set as needed in constructors for the subclassed commands
|
||||||
|
*/
|
||||||
|
|
||||||
|
// color values for strings
|
||||||
|
public final static String C_CMD = ChatColor.AQUA.toString(); // main commands
|
||||||
|
public final static String C_DESC = ChatColor.WHITE.toString(); // command descriptions
|
||||||
|
public final static String C_ERR = ChatColor.RED.toString(); // errors / notices
|
||||||
|
public final static String C_HEAD = ChatColor.YELLOW.toString(); // command listing header
|
||||||
|
public final static String C_OPT = ChatColor.DARK_GREEN.toString(); // optional values
|
||||||
|
public final static String C_REQ = ChatColor.GREEN.toString(); // required values
|
||||||
|
// colorized root command, for console and for player
|
||||||
|
public final static String CMD_C = C_CMD + "wb ";
|
||||||
|
public final static String CMD_P = C_CMD + "/wb ";
|
||||||
|
// much like the above, but used for displaying command list from root /wb command, listing all commands
|
||||||
|
public final static List<String> cmdExamplesConsole = new ArrayList<String>(48); // 48 command capacity, 6 full pages
|
||||||
|
|
||||||
|
|
||||||
public abstract class WBCmd
|
/*
|
||||||
{
|
* Helper variables and methods
|
||||||
/*
|
*/
|
||||||
* Primary variables, should be set as needed in constructors for the subclassed commands
|
public final static List<String> cmdExamplesPlayer = new ArrayList<String>(48); // still, could need to increase later
|
||||||
*/
|
// command name, command permission; normally the same thing
|
||||||
|
public String name = "";
|
||||||
|
public String permission = null;
|
||||||
|
// whether command can accept a world name before itself
|
||||||
|
public boolean hasWorldNameInput = false;
|
||||||
|
public boolean consoleRequiresWorldName = true;
|
||||||
|
// minimum and maximum number of accepted parameters
|
||||||
|
public int minParams = 0;
|
||||||
|
public int maxParams = 9999;
|
||||||
|
// help/explanation text to be shown after command example(s) for this command
|
||||||
|
public String helpText = null;
|
||||||
|
// list of command examples for this command to be displayed as usage reference, separate between players and console
|
||||||
|
// ... these generally should be set indirectly using addCmdExample() within the constructor for each command class
|
||||||
|
public List<String> cmdExamplePlayer = new ArrayList<String>();
|
||||||
|
public List<String> cmdExampleConsole = new ArrayList<String>();
|
||||||
|
|
||||||
// command name, command permission; normally the same thing
|
/*
|
||||||
public String name = "";
|
* The guts of the command run in here; needs to be overriden in the subclassed commands
|
||||||
public String permission = null;
|
*/
|
||||||
|
public abstract void execute(CommandSender sender, Player player, List<String> params, String worldName);
|
||||||
|
|
||||||
// whether command can accept a world name before itself
|
/*
|
||||||
public boolean hasWorldNameInput = false;
|
* This is an optional override, used to provide some extra command status info, like the currently set value
|
||||||
public boolean consoleRequiresWorldName = true;
|
*/
|
||||||
|
public void cmdStatus(CommandSender sender) {
|
||||||
|
}
|
||||||
|
|
||||||
// minimum and maximum number of accepted parameters
|
// add command examples for use the default "/wb" command list and for internal usage reference, formatted and colorized
|
||||||
public int minParams = 0;
|
public void addCmdExample(String example) {
|
||||||
public int maxParams = 9999;
|
addCmdExample(example, true, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
// help/explanation text to be shown after command example(s) for this command
|
public void addCmdExample(String example, boolean forPlayer, boolean forConsole, boolean prefix) {
|
||||||
public String helpText = null;
|
// go ahead and colorize required "<>" and optional "[]" parameters, extra command words, and description
|
||||||
|
example = example.replace("<", C_REQ + "<").replace("[", C_OPT + "[").replace("^", C_CMD).replace("- ", C_DESC + "- ");
|
||||||
|
|
||||||
/*
|
// all "{}" are replaced by "[]" (optional) for player, "<>" (required) for console
|
||||||
* The guts of the command run in here; needs to be overriden in the subclassed commands
|
if (forPlayer) {
|
||||||
*/
|
String exampleP = (prefix ? CMD_P : "") + example.replace("{", C_OPT + "[").replace("}", "]");
|
||||||
public abstract void execute(CommandSender sender, Player player, List<String> params, String worldName);
|
cmdExamplePlayer.add(exampleP);
|
||||||
|
cmdExamplesPlayer.add(exampleP);
|
||||||
|
}
|
||||||
|
if (forConsole) {
|
||||||
|
String exampleC = (prefix ? CMD_C : "") + example.replace("{", C_REQ + "<").replace("}", ">");
|
||||||
|
cmdExampleConsole.add(exampleC);
|
||||||
|
cmdExamplesConsole.add(exampleC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
// return root command formatted for player or console, based on sender
|
||||||
* This is an optional override, used to provide some extra command status info, like the currently set value
|
public String cmd(CommandSender sender) {
|
||||||
*/
|
return (sender instanceof Player) ? CMD_P : CMD_C;
|
||||||
public void cmdStatus(CommandSender sender) {}
|
}
|
||||||
|
|
||||||
|
// formatted and colorized text, intended for marking command name
|
||||||
|
public String commandEmphasized(String text) {
|
||||||
|
return C_CMD + ChatColor.UNDERLINE + text + ChatColor.RESET + " ";
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
// returns green "enabled" or red "disabled" text
|
||||||
* Helper variables and methods
|
public String enabledColored(boolean enabled) {
|
||||||
*/
|
return enabled ? C_REQ + "enabled" : C_ERR + "disabled";
|
||||||
|
}
|
||||||
|
|
||||||
// color values for strings
|
// formatted and colorized command name, optionally prefixed with "[world]" (for player) / "<world>" (for console)
|
||||||
public final static String C_CMD = ChatColor.AQUA.toString(); // main commands
|
public String nameEmphasized() {
|
||||||
public final static String C_DESC = ChatColor.WHITE.toString(); // command descriptions
|
return commandEmphasized(name);
|
||||||
public final static String C_ERR = ChatColor.RED.toString(); // errors / notices
|
}
|
||||||
public final static String C_HEAD = ChatColor.YELLOW.toString(); // command listing header
|
|
||||||
public final static String C_OPT = ChatColor.DARK_GREEN.toString(); // optional values
|
|
||||||
public final static String C_REQ = ChatColor.GREEN.toString(); // required values
|
|
||||||
|
|
||||||
// colorized root command, for console and for player
|
public String nameEmphasizedW() {
|
||||||
public final static String CMD_C = C_CMD + "wb ";
|
return "{world} " + nameEmphasized();
|
||||||
public final static String CMD_P = C_CMD + "/wb ";
|
}
|
||||||
|
|
||||||
// list of command examples for this command to be displayed as usage reference, separate between players and console
|
// send command example message(s) and other helpful info
|
||||||
// ... these generally should be set indirectly using addCmdExample() within the constructor for each command class
|
public void sendCmdHelp(CommandSender sender) {
|
||||||
public List<String> cmdExamplePlayer = new ArrayList<String>();
|
for (String example : ((sender instanceof Player) ? cmdExamplePlayer : cmdExampleConsole)) {
|
||||||
public List<String> cmdExampleConsole = new ArrayList<String>();
|
sender.sendMessage(example);
|
||||||
|
}
|
||||||
|
cmdStatus(sender);
|
||||||
|
if (helpText != null && !helpText.isEmpty())
|
||||||
|
sender.sendMessage(C_DESC + helpText);
|
||||||
|
}
|
||||||
|
|
||||||
// much like the above, but used for displaying command list from root /wb command, listing all commands
|
// send error message followed by command example message(s)
|
||||||
public final static List<String> cmdExamplesConsole = new ArrayList<String>(48); // 48 command capacity, 6 full pages
|
public void sendErrorAndHelp(CommandSender sender, String error) {
|
||||||
public final static List<String> cmdExamplesPlayer = new ArrayList<String>(48); // still, could need to increase later
|
sender.sendMessage(C_ERR + error);
|
||||||
|
sendCmdHelp(sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
// interpret string as boolean value (yes/no, true/false, on/off, +/-, 1/0)
|
||||||
// add command examples for use the default "/wb" command list and for internal usage reference, formatted and colorized
|
public boolean strAsBool(String str) {
|
||||||
public void addCmdExample(String example)
|
str = str.toLowerCase();
|
||||||
{
|
return str.startsWith("y") || str.startsWith("t") || str.startsWith("on") || str.startsWith("+") || str.startsWith("1");
|
||||||
addCmdExample(example, true, true, true);
|
}
|
||||||
}
|
|
||||||
public void addCmdExample(String example, boolean forPlayer, boolean forConsole, boolean prefix)
|
|
||||||
{
|
|
||||||
// go ahead and colorize required "<>" and optional "[]" parameters, extra command words, and description
|
|
||||||
example = example.replace("<", C_REQ+"<").replace("[", C_OPT+"[").replace("^", C_CMD).replace("- ", C_DESC+"- ");
|
|
||||||
|
|
||||||
// all "{}" are replaced by "[]" (optional) for player, "<>" (required) for console
|
|
||||||
if (forPlayer)
|
|
||||||
{
|
|
||||||
String exampleP = (prefix ? CMD_P : "") + example.replace("{", C_OPT + "[").replace("}", "]");
|
|
||||||
cmdExamplePlayer.add(exampleP);
|
|
||||||
cmdExamplesPlayer.add(exampleP);
|
|
||||||
}
|
|
||||||
if (forConsole)
|
|
||||||
{
|
|
||||||
String exampleC = (prefix ? CMD_C : "") + example.replace("{", C_REQ + "<").replace("}", ">");
|
|
||||||
cmdExampleConsole.add(exampleC);
|
|
||||||
cmdExamplesConsole.add(exampleC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return root command formatted for player or console, based on sender
|
|
||||||
public String cmd(CommandSender sender)
|
|
||||||
{
|
|
||||||
return (sender instanceof Player) ? CMD_P : CMD_C;
|
|
||||||
}
|
|
||||||
|
|
||||||
// formatted and colorized text, intended for marking command name
|
|
||||||
public String commandEmphasized(String text)
|
|
||||||
{
|
|
||||||
return C_CMD + ChatColor.UNDERLINE + text + ChatColor.RESET + " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns green "enabled" or red "disabled" text
|
|
||||||
public String enabledColored(boolean enabled)
|
|
||||||
{
|
|
||||||
return enabled ? C_REQ+"enabled" : C_ERR+"disabled";
|
|
||||||
}
|
|
||||||
|
|
||||||
// formatted and colorized command name, optionally prefixed with "[world]" (for player) / "<world>" (for console)
|
|
||||||
public String nameEmphasized()
|
|
||||||
{
|
|
||||||
return commandEmphasized(name);
|
|
||||||
}
|
|
||||||
public String nameEmphasizedW()
|
|
||||||
{
|
|
||||||
return "{world} " + nameEmphasized();
|
|
||||||
}
|
|
||||||
|
|
||||||
// send command example message(s) and other helpful info
|
|
||||||
public void sendCmdHelp(CommandSender sender)
|
|
||||||
{
|
|
||||||
for (String example : ((sender instanceof Player) ? cmdExamplePlayer : cmdExampleConsole))
|
|
||||||
{
|
|
||||||
sender.sendMessage(example);
|
|
||||||
}
|
|
||||||
cmdStatus(sender);
|
|
||||||
if (helpText != null && !helpText.isEmpty())
|
|
||||||
sender.sendMessage(C_DESC + helpText);
|
|
||||||
}
|
|
||||||
|
|
||||||
// send error message followed by command example message(s)
|
|
||||||
public void sendErrorAndHelp(CommandSender sender, String error)
|
|
||||||
{
|
|
||||||
sender.sendMessage(C_ERR + error);
|
|
||||||
sendCmdHelp(sender);
|
|
||||||
}
|
|
||||||
|
|
||||||
// interpret string as boolean value (yes/no, true/false, on/off, +/-, 1/0)
|
|
||||||
public boolean strAsBool(String str)
|
|
||||||
{
|
|
||||||
str = str.toLowerCase();
|
|
||||||
return str.startsWith("y") || str.startsWith("t") || str.startsWith("on") || str.startsWith("+") || str.startsWith("1");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
name: WorldBorder
|
name: WorldBorder
|
||||||
author: Brettflan
|
authors: [Brettflan, PryPurity]
|
||||||
description: Efficient, feature-rich plugin for limiting the size of your worlds.
|
description: Efficient, feature-rich plugin for limiting the size of your worlds.
|
||||||
version: 1.9.10 (beta)
|
version: 2.0.0 (beta)
|
||||||
api-version: 1.13
|
api-version: 1.13
|
||||||
main: com.wimbli.WorldBorder.WorldBorder
|
main: com.wimbli.WorldBorder.WorldBorder
|
||||||
softdepend:
|
softdepend:
|
||||||
@ -11,41 +11,41 @@ commands:
|
|||||||
description: Primary command for WorldBorder.
|
description: Primary command for WorldBorder.
|
||||||
aliases: [wb]
|
aliases: [wb]
|
||||||
usage: |
|
usage: |
|
||||||
/<command> - list available commands (show help).
|
/<command> - list available commands (show help).
|
||||||
/<command> help [command] - get help on command usage.
|
/<command> help [command] - get help on command usage.
|
||||||
/<command> [world] set <radiusX> [radiusZ] <x> <z> - set world border.
|
/<command> [world] set <radiusX> [radiusZ] <x> <z> - set world border.
|
||||||
/<command> [world] set <radiusX> [radiusZ] spawn - use spawn point.
|
/<command> [world] set <radiusX> [radiusZ] spawn - use spawn point.
|
||||||
/<command> set <radiusX> [radiusZ] - set world border, centered on you.
|
/<command> set <radiusX> [radiusZ] - set world border, centered on you.
|
||||||
/<command> set <radiusX> [radiusZ] player <name> - center on player.
|
/<command> set <radiusX> [radiusZ] player <name> - center on player.
|
||||||
/<command> [world] setcorners <x1> <z1> <x2> <z2> - set border from corners.
|
/<command> [world] setcorners <x1> <z1> <x2> <z2> - set border from corners.
|
||||||
/<command> [world] radius <radiusX> [radiusZ] - change border's radius.
|
/<command> [world] radius <radiusX> [radiusZ] - change border's radius.
|
||||||
/<command> list - show border information for all worlds.
|
/<command> list - show border information for all worlds.
|
||||||
/<command> shape <elliptic|rectangular> - set the default border shape.
|
/<command> shape <elliptic|rectangular> - set the default border shape.
|
||||||
/<command> shape <round|square> - same as above, backwards compatible.
|
/<command> shape <round|square> - same as above, backwards compatible.
|
||||||
/<command> [world] clear - remove border for this world.
|
/<command> [world] clear - remove border for this world.
|
||||||
/<command> clear all - remove border for all worlds.
|
/<command> clear all - remove border for all worlds.
|
||||||
/<command> [world] fill [freq] [pad] [force] - generate world to border.
|
/<command> [world] fill [freq] [pad] [force] - generate world to border.
|
||||||
/<command> [world] trim [freq] [pad] - trim world outside of border.
|
/<command> [world] trim [freq] [pad] - trim world outside of border.
|
||||||
/<command> bypass [player] [on/off] - let player go beyond border.
|
/<command> bypass [player] [on/off] - let player go beyond border.
|
||||||
/<command> bypasslist - list players with border bypass enabled.
|
/<command> bypasslist - list players with border bypass enabled.
|
||||||
/<command> knockback <distance> - how far to move the player back.
|
/<command> knockback <distance> - how far to move the player back.
|
||||||
/<command> wrap [world] <on/off> - can make border crossings wrap around.
|
/<command> wrap [world] <on/off> - can make border crossings wrap around.
|
||||||
/<command> whoosh <on/off> - turn knockback effect on or off.
|
/<command> whoosh <on/off> - turn knockback effect on or off.
|
||||||
/<command> getmsg - display border message.
|
/<command> getmsg - display border message.
|
||||||
/<command> setmsg <text> - set border message.
|
/<command> setmsg <text> - set border message.
|
||||||
/<command> wshape [world] <elliptic|rectangular|default> - override shape.
|
/<command> wshape [world] <elliptic|rectangular|default> - override shape.
|
||||||
/<command> wshape [world] <round|square|default> - same as above values.
|
/<command> wshape [world] <round|square|default> - same as above values.
|
||||||
/<command> delay <amount> - time between border checks.
|
/<command> delay <amount> - time between border checks.
|
||||||
/<command> dynmap <on/off> - turn DynMap border display on or off.
|
/<command> dynmap <on/off> - turn DynMap border display on or off.
|
||||||
/<command> dynmapmsg <text> - DynMap border labels will show this.
|
/<command> dynmapmsg <text> - DynMap border labels will show this.
|
||||||
/<command> remount <amount> - delay before remounting after knockback.
|
/<command> remount <amount> - delay before remounting after knockback.
|
||||||
/<command> fillautosave <seconds> - world save interval for Fill process.
|
/<command> fillautosave <seconds> - world save interval for Fill process.
|
||||||
/<command> portal <on/off> - turn portal redirection on or off.
|
/<command> portal <on/off> - turn portal redirection on or off.
|
||||||
/<command> denypearl <on/off> - stop ender pearls thrown past the border.
|
/<command> denypearl <on/off> - stop ender pearls thrown past the border.
|
||||||
/<command> preventblockplace <on|off> - stop block placement past border.
|
/<command> preventblockplace <on|off> - stop block placement past border.
|
||||||
/<command> preventmobspawn <on|off> - stop mob spawning past border.
|
/<command> preventmobspawn <on|off> - stop mob spawning past border.
|
||||||
/<command> reload - re-load data from config.yml.
|
/<command> reload - re-load data from config.yml.
|
||||||
/<command> debug <on/off> - turn debug mode on or off.
|
/<command> debug <on/off> - turn debug mode on or off.
|
||||||
permissions:
|
permissions:
|
||||||
worldborder.*:
|
worldborder.*:
|
||||||
description: Grants all WorldBorder permissions
|
description: Grants all WorldBorder permissions
|
||||||
|
Loading…
Reference in New Issue
Block a user