Compare commits

...

No commits in common. "1.7.2" and "master" have entirely different histories.

64 changed files with 3926 additions and 1105 deletions

3
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,3 @@
github: [Phoenix616]
patreon: Phoenix616
custom: https://phoenix616.dev/tip

44
.github/ISSUE_TEMPLATE/bug-report.md vendored Normal file
View File

@ -0,0 +1,44 @@
---
name: Bug report
about: Report an error that that you found
title: ''
labels: ''
assignees: ''
---
#### Plugin Version
<!-- The full plugin version like it is printed in the log or /version RandomTeleport -->
#### Config
<!-- The full config file -->
```yaml
[Put the config here]
```
#### Environment description
<!-- Information like the operating system and language as well as full server version from /version -->
#### Full Log
<!-- The full log file, especially important if you have a stack trace -->
```
[Your log here]
```
#### What other programs/plugins are you running?
<!-- List of your plugins, ideally with the version or other programs that might be related -->
#### What is happening?
<!-- Explain what happens and what steps should be done to reproduce the issue. Ideally with pictures and the full error log! -->
#### What did you expect to happen?
<!-- Explain what you expected to happen after performing the previously described steps -->
#### Additional context
<!-- Add any other context or screenshots about the bug report here. -->

11
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: "#moep IRC channel on irc.spi.gt"
url: "https://kiwiirc.com/client/irc.spi.gt/#moep"
about: My public chat channel to discuss any of my projects
- name: SpigotMC Discussion Thread
url: https://www.spigotmc.org/threads/fubs-random-teleport.29162/
about: Ask questions and discuss the resource publicly
- name: SpigotMC PM
url: https://www.spigotmc.org/conversations/add?to=Phoenix616&title=RandomTeleport%20Question
about: Ask me questions privately

24
.github/ISSUE_TEMPLATE/enhancement.md vendored Normal file
View File

@ -0,0 +1,24 @@
---
name: Enhancement
about: Request a feature or suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
#### Is your feature request related to a problem? Please describe.
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when... -->
#### Describe the solution you'd like
<!-- A clear and concise description of what you want to happen. -->
#### Describe alternatives you've considered
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
#### Additional context
<!-- Add any other context or screenshots about the feature request here. -->

18
.gitignore vendored
View File

@ -1,12 +1,6 @@
bin
*.class
# Package Files #
*.jar
*.war
*.ear
# Eclipse stuff
.classpath
.project
.settings/
# IntelliJ project files
.idea
*.iml
out
gen
target

View File

@ -1,6 +1,86 @@
RandomTeleport
RandomTeleport v2
==============
Plugin which lets you teleport players to a random location of a map within your provided paramaters.
Second generation random teleport Bukkit Plugin.
Lets you teleport players to a random location of a map within your provided parameters while respecting stuff like world borders and region protections.
SpigotMC resource page: http://www.spigotmc.org/resources/fubs-random-teleport.1094/
## Command
Aliases: `randomteleport`, `randomtp`, `rtp`
Permission: `randomteleport.use`
Usage | Description
--------------------------------------------|-------------------------------
`/rtp` | uses the default preset
`/rtp <preset1,...> [<playername>]` | uses a specific or random preset
`/rtp <minRange> <maxRange> [<options>]` | `minRange` - minimum distance to the center point (square shaped) <br> `maxRange` - maximum distance to the center point (square shaped)
`/rtp --stat` | shows a statistic of the teleports since the last restart
`/rtp --reload` | reloads the config
Option | Description
--------------------------------|-------------------------------------------
`-p,-player <playername>` | teleports other players
`-w,-world <world1,world2,...>` | teleports the player in a specific or random world
`-b,-biome <biomename...>` | only teleport to this biome (multiple allowed, Bukkit biome names!)
`-x,-xPos <x value>` | x axis of the center point, if not set the player's x axis is used
`-z,-zPos <z value>` | z axis of the center point, if not set the player's z axis is used
`-minY <y value>` | minimum y value that the random location should have (default: 0)
`-maxY <y value>` | maximum y value that the random location should have (default: world height, half in nether)
`-l,-loaded` | only search loaded chunks for possible locations (might fail more often)
`-g,-generated` | only search generated chunks for possible locations
`-c, -cooldown <seconds>` | cooldown in seconds after which the player can use this teleporter again
`-id <id>` | the ID to use for the cooldown, uses automatically generated one if not provided
`-f,-force` | teleport even if there is no dirt/grass/sand/gravel, only checks for lava/water/cactus, ignores WorldGuard/Faction regions
`-f,-force [<blocks/regions>]` | only ignore blocks or regions
`-t,-tries <amount>` | the amount of times the plugin should try to find a random location before giving up
`-sp,spawnpoint [force]` | set the respawn point of the player to the location he teleported to (force overrides existing spawnpoint)
`-checkdelay <ticks>` | the amount of ticks to wait between each chunk check
`-debug` | print some more debugging information in the log
## Permissions
Permission | Default | Description
------------------------------------|---------|---------------------------
randomteleport.use | op | Gives permission to the command
randomteleport.manual | op | Gives permission to manually specify parameters in the command
randomteleport.manual.option.* | op | Gives permission to use certain options in the command
randomteleport.tpothers | op | Gives permission to teleport other players
randomteleport.cooldownexempt | op | Teleportcooldown does not effect these players
randomteleport.stat | op | Permission for showing the teleport statistic
randomteleport.reload | op | Permission to use the reload command
randomteleport.presets.default | op | Gives permission to use the default random teleport preset
randomteleport.presets.* | op | Gives permission to use all random teleport presets
randomteleport.sign.preset.default | op | Gives permission to use the default preset with a rightclick on a preset sign
randomteleport.sign.preset.* | op | Gives permission to use all presets with a rightclick on a preset sign
randomteleport.sign.create | op | Allows creating preset signs ([rtp] or [RandomTP] on the 2nd line and the preset name on the 3rd)
randomteleport.sign.destroy | op | Allows destroying preset signs ([rtp] or [RandomTP] on the 2nd line and the preset name on the 3rd)
## Downloads
Releases: [SpigotMC resource page](http://www.spigotmc.org/resources/fubs-random-teleport.1094/)
Development Builds: [Minebench.de Jenkins server](https://ci.minebench.de/job/Randomteleport/)
## License
```
RandomTeleport
Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
```

View File

@ -1,122 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>de.themoep</groupId>
<artifactId>RandomTeleport</artifactId>
<version>1.7.2</version>
<description>Randomly teleport players on your server!</description>
<name>RandomTeleport</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<build.number>${buildNumber}</build.number>
<minecraft.plugin.version>${project.version} ${buildDescription}</minecraft.plugin.version>
</properties>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
</repository>
<repository>
<id>sk89q-repo</id>
<url>http://maven.sk89q.com/repo/</url>
</repository>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.9-R0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>de.themoep</groupId>
<artifactId>ClanControl</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.sk89q</groupId>
<artifactId>worldguard</artifactId>
<version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>me.ryanhamshire</groupId>
<artifactId>GriefPrevention</artifactId>
<version>13.6</version>
<scope>system</scope>
<systemPath>${basedir}/lib/GriefPrevention-13.6.jar</systemPath>
</dependency>
<dependency>
<groupId>com.massivecraft</groupId>
<artifactId>MassiveCore</artifactId>
<version>2.7.1</version>
<scope>system</scope>
<systemPath>${basedir}/lib/MassiveCore-2.7.1.jar</systemPath>
</dependency>
<dependency>
<groupId>com.massivecraft</groupId>
<artifactId>MassiveCore-old</artifactId>
<version>7.4.0</version>
<scope>system</scope>
<systemPath>${basedir}/lib/MassiveCore-7.4.0.jar</systemPath>
</dependency>
<dependency>
<groupId>de.themoep</groupId>
<artifactId>factionsutil</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${basedir}/lib/Factions-Dependencies-2.6+2.7.1+UUID.jar</systemPath>
</dependency>
<dependency>
<groupId>com.github.Brettflan</groupId>
<artifactId>WorldBorder</artifactId>
<version>master-c5df3417c8-1</version>
</dependency>
</dependencies>
<profiles>
<profile>
<id>static_build_number</id>
<activation>
<property>
<name>!env.BUILD_NUMBER</name>
</property>
</activation>
<properties>
<buildNumber>0</buildNumber>
<buildDescription>(manually compiled)</buildDescription>
</properties>
</profile>
<profile>
<id>dynamic_build_number</id>
<activation>
<property>
<name>env.BUILD_NUMBER</name>
</property>
</activation>
<properties>
<buildNumber>${env.BUILD_NUMBER}</buildNumber>
<buildDescription>(build #${env.BUILD_NUMBER})</buildDescription>
</properties>
</profile>
</profiles>
<build>
<finalName>${project.name}</finalName>
<resources>
<resource>
<filtering>true</filtering>
<directory>${project.basedir}/src/main/resources</directory>
</resource>
</resources>
</build>
</project>

View File

@ -1,75 +0,0 @@
package de.themoep.bukkit.plugin.RandomTeleport.Listeners;
import de.themoep.bukkit.plugin.RandomTeleport.RandomTeleport;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.block.Sign;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.player.PlayerInteractEvent;
/**
* Created by Phoenix616 on 23.11.2014.
*/
public class SignListener implements Listener {
private final RandomTeleport plugin;
public SignListener(RandomTeleport plugin) {
this.plugin = plugin;
}
@EventHandler
public void onSignCreate(SignChangeEvent event) {
if(event.getLine(1).equalsIgnoreCase("[rtp]") || event.getLine(1).equalsIgnoreCase("[RandomTP]")){
if(!event.getPlayer().hasPermission("randomteleport.sign.create")){
event.getBlock().breakNaturally();
event.getPlayer().sendMessage(ChatColor.RED + "You don't have permission to create RandomTeleport preset signs! " + ChatColor.ITALIC + " (randomteleport.sign.create)");
} else {
event.getPlayer().sendMessage(ChatColor.GREEN + "RandomTeleport preset sign created!");
if(plugin.getConfig().getString("presets." + event.getLine(2).toLowerCase()) == null) {
event.getPlayer().sendMessage(ChatColor.DARK_RED + "Warning: " + ChatColor.RED + "The RandomTeleport preset " + ChatColor.GOLD + event.getLine(2).toLowerCase() + ChatColor.RED + " does not exist!");
}
}
}
}
@EventHandler
public void onSignDestroy(BlockBreakEvent event){
if(event.getBlock().getType() == Material.WALL_SIGN || event.getBlock().getType() == Material.SIGN_POST) {
Sign sign = (Sign) event.getBlock().getState();
if(sign.getLine(1).equalsIgnoreCase("[rtp]") || sign.getLine(1).equalsIgnoreCase("[RandomTP]")){
if(!event.getPlayer().hasPermission("randomteleport.sign.create")){
event.setCancelled(true);
event.getPlayer().sendMessage(ChatColor.RED + "You don't have permission to break RandomTeleport signs! " + ChatColor.ITALIC + " (randomteleport.sign.create)");
} else {
event.getPlayer().sendMessage(ChatColor.RED + "RandomTeleport sign destroyed!");
}
}
}
}
@EventHandler
public void onSignClick(PlayerInteractEvent event) {
if(event.getAction() == Action.RIGHT_CLICK_BLOCK && !event.isCancelled() && (event.getClickedBlock().getType() == Material.WALL_SIGN || event.getClickedBlock().getType() == Material.SIGN_POST)) {
Sign sign = (Sign) event.getClickedBlock().getState();
if(sign.getLine(1).equalsIgnoreCase("[rtp]") || sign.getLine(1).equalsIgnoreCase("[RandomTP]")) {
String preset = sign.getLine(2).toLowerCase();
if(event.getPlayer().hasPermission("randomteleport.sign.preset." + preset)) {
if(plugin.getConfig().getString("presets." + preset) == null) {
event.getPlayer().sendMessage(ChatColor.RED + "The RandomTeleport preset " + ChatColor.GOLD + preset + ChatColor.RED + " does not exist!");
} else {
String cmd = "rtp " + preset + " " + event.getPlayer().getName();
plugin.getServer().dispatchCommand(plugin.getServer().getConsoleSender(), cmd);
}
} else {
event.getPlayer().sendMessage(ChatColor.RED + "You don't have permission to use the preset " + preset + "! " + ChatColor.ITALIC + " (randomteleport.sign.preset." + preset + ")");
}
}
}
}
}

View File

@ -1,817 +0,0 @@
package de.themoep.bukkit.plugin.RandomTeleport;
import com.google.common.collect.ImmutableMap;
import com.wimbli.WorldBorder.BorderData;
import com.wimbli.WorldBorder.WorldBorder;
import de.themoep.bukkit.plugin.RandomTeleport.Listeners.SignListener;
import de.themoep.clancontrol.ClanControl;
import de.themoep.clancontrol.Region;
import de.themoep.clancontrol.RegionStatus;
import me.ryanhamshire.GriefPrevention.GriefPrevention;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockCanBuildEvent;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.logging.Level;
public class RandomTeleport extends JavaPlugin implements CommandExecutor {
public static RandomTeleport instance;
public Level debugLevel;
public HashMap<String,Long> cooldown = new HashMap<String,Long> ();
public HashSet<UUID> playerlock = new HashSet<UUID> ();
public int[] checkstat = new int[100];
public int factionsApiVersion = 0;
public boolean worldguard = false;
public boolean clancontrol = false;
public boolean griefprevention = false;
public boolean worldborder = false;
@SuppressWarnings("unchecked")
@Override
public void onEnable() {
instance = this;
loadConfig();
getLogger().log(Level.INFO, "Attempting to load cooldown.map...");
cooldown = (HashMap<String, Long>) readMap("cooldown.map");
getServer().getPluginManager().registerEvents(new SignListener(this), this);
if(Bukkit.getPluginManager().getPlugin("WorldGuard") != null){
getLogger().log(Level.INFO, "Detected WorldGuard.");
worldguard = true;
}
if(Bukkit.getPluginManager().getPlugin("GriefPrevention") != null) {
getLogger().log(Level.INFO, "Detected GriefPrevention.");
griefprevention = true;
}
if(Bukkit.getPluginManager().getPlugin("ClanControl") != null){
getLogger().log(Level.INFO, "Detected ClanControl.");
clancontrol = true;
}
if(Bukkit.getPluginManager().getPlugin("WorldBorder") != null) {
getLogger().log(Level.INFO, "Detected WorldBorder.");
worldborder = true;
}
if(Bukkit.getPluginManager().getPlugin("Factions") != null){
String version = Bukkit.getPluginManager().getPlugin("Factions").getDescription().getVersion();
if(version.startsWith("2.7") || version.startsWith("2.8") || version.startsWith("2.9") || version.startsWith("2.10")) {
factionsApiVersion = 27;
} else if(version.startsWith("1.6")){
factionsApiVersion = 16;
} else {
factionsApiVersion = 26;
}
getLogger().log(Level.INFO, "Detected Factions " + version + ".");
}
}
private void loadConfig() {
saveDefaultConfig();
reloadConfig();
debugLevel = getConfig().getBoolean("debug", false) ? Level.INFO : Level.FINER;
}
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) throws NumberFormatException {
if(cmd.getName().equalsIgnoreCase("randomteleport") || cmd.getName().equalsIgnoreCase("randomtp") || cmd.getName().equalsIgnoreCase("rtp")) {
boolean forceBlocks = false;
boolean forceRegions = false;
boolean loadedChunksOnly = false;
/*
0 -> don't set it
1 -> set it only if the player doesn't have a bed spawn
2 -> force it even if the player has a bed spawn
*/
int setSpawnpoint = 0;
//boolean tppoints = false;
boolean xoption = false;
boolean zoption = false;
boolean coption = false;
String playername = sender.getName();
Player player = Bukkit.getServer().getPlayer(playername);
int xCenter = 0;
int zCenter = 0;
int minRange;
int maxRange;
int cooldowntime = 0;
World world = null;
List<Biome> biomeList = new ArrayList<Biome>();
if(args.length == 0 && sender.hasPermission("randomteleport.presets.default")) {
if(getConfig().getString("presets.default") != null) {
String defaultcmd = getConfig().getString("presets.default").replace("/", "");
defaultcmd = defaultcmd + " -p " + sender.getName();
getServer().dispatchCommand(getServer().getConsoleSender(),defaultcmd);
getLogger().log(debugLevel, "Running preset command default: " + defaultcmd);
return true;
}
}
if(args.length == 1 && args[0].equalsIgnoreCase("stat") && sender.hasPermission("randomteleport.stat")) {
sender.sendMessage("--RandomTeleport statistics--");
sender.sendMessage("Checks - Times occured");
for(int i = 0; i < 100; i++) {
if(checkstat[i] != 0) {
if(i == 99) {
sender.sendMessage(ChatColor.RED + "Canceled - " + checkstat[i] + "x");
} else {
sender.sendMessage(i + 1 + " - " + checkstat[i] + "x");
}
}
}
return true;
}
if(args.length == 1 && args[0].equalsIgnoreCase("reload") && sender.hasPermission("randomteleport.reload")) {
loadConfig();
sender.sendMessage(ChatColor.GREEN + "Config reloaded!");
return true;
}
if(args.length == 1 && sender.hasPermission("randomteleport.presets." + args[0].toLowerCase())) {
if(getConfig().getString("presets." + args[0].toLowerCase()) == null) {
sender.sendMessage(ChatColor.RED + "The Random Teleport " + args[0].toLowerCase() + " does not exist!");
return true;
}
String presetCmd = getConfig().getString("presets." + args[0].toLowerCase()).replace("/", "");
presetCmd = presetCmd + " -p " + sender.getName();
getLogger().log(debugLevel, "Running preset command " + args[0].toLowerCase() + ": " + presetCmd);
getServer().dispatchCommand(getServer().getConsoleSender(), presetCmd);
return true;
}
if(args.length == 2 && sender.hasPermission("randomteleport.tpothers") && this.getConfig().getString("presets." + args[0].toLowerCase()) != null) {
Player toTp = Bukkit.getServer().getPlayer(args[1]);
if(toTp == null) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " Player '" + args[1] + "' was not found online!");
return true;
}
String defaultcmd = this.getConfig().getString("presets." + args[0].toLowerCase()).replace("/", "");
defaultcmd = defaultcmd + " -p " + toTp.getName();
getServer().dispatchCommand(sender,defaultcmd);
return true;
}
// analyze the args & get parameter
if(!sender.hasPermission("randomteleport.use") && sender instanceof Player) {
sender.sendMessage("You don't have the permission randomteleport.use");
return true;
}
if(args.length < 2) {
sender.sendMessage(ChatColor.DARK_RED + "Syntax error:" + ChatColor.RED + " Not enough arguments!");
return false;
}
try {
//set ranges
minRange = Integer.parseInt(args[0]);
maxRange = Integer.parseInt(args[1]);
if(minRange >= maxRange) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " maxRange must be bigger then minRange!");
return true;
}
} catch(NumberFormatException e) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " Your input contains an invalid number!");
return true;
}
//getLogger().info("Success: Parsing bounds");
if(args.length > 2) {
for(int i = 2; i < args.length; i++) {
if(args[i].startsWith("-")) {
if(args[i].equalsIgnoreCase("-p") || args[i].equalsIgnoreCase("-player") && sender.hasPermission("randomteleport.tpothers")) {
if(i+1 >= args.length || args[i+1].startsWith("-")) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " The " + args[i] + " option needs an argument (" + args[i] + " value)!");
return true;
}
playername = args[i+1];
player = Bukkit.getServer().getPlayer(playername);
i++;
getLogger().log(debugLevel, "Player: " + playername);
if(player == null) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " Player '" + playername + "' was not found online!");
return true;
}
} else if(args[i].equalsIgnoreCase("-w") || args[i].equalsIgnoreCase("-world")) {
if(i+1 >= args.length || args[i+1].startsWith("-")) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " The " + args[i] + " option needs an argument (" + args[i] + " value)!");
return true;
}
getLogger().log(debugLevel, "World: " + args[i+1]);
world = Bukkit.getServer().getWorld(args[i+1]);
if(world == null) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " The world \"" + args[i+1] + "\" given in the " + args[i] + " option does not exist!");
return true;
}
i++;
} else if(args[i].equalsIgnoreCase("-b") || args[i].equalsIgnoreCase("-biome")) {
if(i+1 >= args.length || args[i+1].startsWith("-")) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " The " + args[i] + " option needs an argument (" + args[i] + " value)!");
return true;
}
getLogger().log(debugLevel, "Biomes:");
for(i = i+1; i < args.length; i++) {
if(args[i].startsWith("-")) {
i--;
break;
}
getLogger().log(debugLevel, args[i]);
try {
biomeList.add(Biome.valueOf(args[i].toUpperCase()));
} catch(IllegalArgumentException e) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " The biome \"" + args[i] + "\" given in the -biome option does not exist!");
return true;
}
}
if(biomeList.size() == 0) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " Please specify at least one biome after the -biome option!");
return true;
}
// if -x/-z option is selected set x/z it to its values
} else if(args[i].equalsIgnoreCase("-x") || args[i].equalsIgnoreCase("-xPos")) {
if(i+1 >= args.length || (args[i+1].startsWith("-") && !isNumeric(args[i+1].substring(1)))) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " The " + args[i] + " option needs an argument (" + args[i] + " value)!");
return true;
}
try {
xCenter = Integer.parseInt(args[i+1]);
xoption = true;
i++;
} catch(NumberFormatException e) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " Your input contains a invalid number in the " + args[i] + " option!");
return true;
}
getLogger().log(debugLevel, "xCenter: " + xCenter);
} else if(args[i].equalsIgnoreCase("-z") || args[i].equalsIgnoreCase("-zPos")) {
if(i+1 >= args.length || (args[i+1].startsWith("-") && !isNumeric(args[i+1].substring(1)))) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " The " + args[i] + " option needs an argument (" + args[i] + " value)!");
return true;
}
try {
zCenter = Integer.parseInt(args[i+1]);
zoption = true;
i++;
} catch(NumberFormatException e) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " Your input contains a invalid number in the " + args[i] + " option!");
return true;
}
getLogger().log(debugLevel, "zCenter: " + zCenter);
} else if(args[i].equalsIgnoreCase("-l") || args[i].equalsIgnoreCase("-loaded")) {
if(i+1 >= args.length || args[i+1].startsWith("-")) {
loadedChunksOnly = true;
}
getLogger().log(debugLevel, "Loaded only");
} else if(args[i].equalsIgnoreCase("-c") || args[i].equalsIgnoreCase("-cooldown")) {
if(i+1 >= args.length || args[i+1].startsWith("-")) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " The " + args[i] + " option needs an argument (" + args[i] + " value)!");
return true;
}
try {
cooldowntime = Integer.parseInt(args[i+1]);
coption = true;
i++;
} catch(NumberFormatException e) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " Your input contains a invalid number in the " + args[i] + " option!");
return true;
}
getLogger().log(debugLevel, "cooldowntime: " + cooldowntime);
} else if(args[i].equalsIgnoreCase("-f") || args[i].equalsIgnoreCase("-force")) {
if(i+1 >= args.length || args[i+1].startsWith("-")) {
forceBlocks = true;
forceRegions = true;
} else {
if(args[i+1].equalsIgnoreCase("blocks")) {
forceBlocks = true;
} else if(args[i+1].equalsIgnoreCase("regions")) {
forceRegions = true;
}
i++;
}
getLogger().log(debugLevel, "forceBlocks: " + forceBlocks);
getLogger().log(debugLevel, "forceRegions: " + forceRegions);
} else if(args[i].equalsIgnoreCase("-sp") || args[i].equalsIgnoreCase("-spawnpoint")) {
if(i+1 >= args.length || args[i+1].startsWith("-")) {
setSpawnpoint = 1;
} else {
if(args[i+1].equalsIgnoreCase("true")) {
setSpawnpoint = 2;
} else if(args[i+1].equalsIgnoreCase("false")) {
setSpawnpoint = 1;
}
i++;
}
getLogger().log(debugLevel, "setSpawnpoint: " + setSpawnpoint);
} else {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " Your input contains an invalid option (" + args[i] + ")!");
getLogger().log(debugLevel, "invalid: " + args[i]);
return false;
}
}
}
}
//getLogger().info("Success: Parsed options");
if(playername.equalsIgnoreCase("CONSOLE")) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " Silly filly! The console can not teleport! Did you forgot to add the -player <playername> option?");
return true;
}
if(world == null) {
if(sender instanceof Player) {
world = ((Player) sender).getWorld();
} else if(sender instanceof BlockCommandSender) {
world = ((BlockCommandSender) sender).getBlock().getWorld();
} else if(sender instanceof ConsoleCommandSender) {
world = player.getWorld();
} else {
world = player.getWorld();
}
}
if(world.getEnvironment() == Environment.NETHER && !forceBlocks) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " RandomTeleport currently does not work in the nether!");
return true;
}
if(playerlock.contains(player.getUniqueId())) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " RandomTeleport already tries to teleport this player!");
return true;
}
playerlock.add(player.getUniqueId());
//getLogger().info("Starting to read cooldown hashmap");
String cooldownid = player.getUniqueId().toString() + minRange + maxRange + xCenter + zCenter + cooldowntime + forceBlocks + forceRegions + setSpawnpoint;
if(cooldown.containsKey(cooldownid) && cooldown.get(cooldownid) + cooldowntime * 1000 > System.currentTimeMillis()) {
// convert seconds in dhms format
long cooldown_seconds = (cooldown.get(cooldownid)/1000 + cooldowntime - System.currentTimeMillis()/1000) + 1;
String cooldown_text = "";
int cooldown_days = (int) (cooldown_seconds / 86400);
if(cooldown_days > 0) {
cooldown_seconds = cooldown_seconds - 86400 * cooldown_days;
}
int cooldown_hours = (int) (cooldown_seconds / 3600);
if(cooldown_hours > 0) {
cooldown_seconds = cooldown_seconds - 3600 * cooldown_hours;
}
int cooldown_minutes = (int) (cooldown_seconds / 60);
if(cooldown_minutes > 0) {
cooldown_seconds = cooldown_seconds - 60 * cooldown_minutes;
}
if(cooldown_days > 0) {
cooldown_text = cooldown_days + "d ";
}
if(cooldown_hours > 0) {
cooldown_text = cooldown_text + cooldown_hours + "h ";
}
if(cooldown_minutes > 0) {
cooldown_text = cooldown_text + cooldown_minutes + "m ";
}
if(cooldown_seconds > 0) {
cooldown_text = cooldown_text + cooldown_seconds + "s ";
}
// display cooldown
if(playername.equalsIgnoreCase("CONSOLE")) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " This teleport is on cooldown for player " + player.getName() + "!");
}
player.sendMessage(getTranslation("error.cooldown", ImmutableMap.of("cooldown_text", cooldown_text)));
playerlock.remove(player.getUniqueId());
return true;
}
player.sendMessage(getTranslation("search", ImmutableMap.of("worldname", world.getName())));
// set center coordinates to player location
if(!xoption) {
xCenter = (int) player.getLocation().getX();
}
if(!zoption) {
zCenter = (int) player.getLocation().getZ();
}
getLogger().log(debugLevel, "RandomTeleport for player '" + playername + "' with minRange " + minRange + " maxRange " + maxRange + " xCenter " + xCenter + " zCenter " + zCenter + " forceBlocks=" + forceBlocks + " forceRegions=" + forceRegions);
if(biomeList.size() > 0) {
getLogger().log(Level.INFO, "Biomelist:");
for(Biome biome : biomeList) {
getLogger().log(Level.INFO, " " + biome);
}
}
int x;
int z;
int zold = 0;
int xold = 0;
int chunksum = 0;
int chunksumold = 0;
List<Integer[]> chunklist = new ArrayList<Integer[]>();
if(loadedChunksOnly)
for(Chunk c : world.getLoadedChunks())
if(Math.abs(c.getX()) * 16 <= xCenter + maxRange && Math.abs(c.getX()) * 16 >= xCenter + minRange && Math.abs(c.getZ()) * 16 <= zCenter + maxRange && Math.abs(c.getZ()) * 16 >= zCenter + minRange )
chunklist.add(new Integer[]{c.getX(), c.getZ()});
for(int chunkcount = 0; chunkcount < 10 && chunksum < 81; chunkcount ++) {
int count = 0;
do {
count++;
Random r = new Random();
if(loadedChunksOnly) {
int chunknumber = r.nextInt(chunklist.size());
x = chunklist.get(chunknumber)[0] * 16 + r.nextInt(15);
z = chunklist.get(chunknumber)[1] * 16 + r.nextInt(15);
} else {
//get random range in min and max range
int xRange = minRange + r.nextInt(maxRange - minRange);
int zRange = minRange + r.nextInt(maxRange - minRange);
//make range negative with a 50% chance
if (r.nextBoolean()) xRange = 0 - xRange;
if (r.nextBoolean()) zRange = 0 - zRange;
x = xCenter + xRange;
z = zCenter + zRange;
}
if(count == 100) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " RandomTeleport could not find a save location!");
if(!sender.getName().equalsIgnoreCase(player.getName())){
player.sendMessage(getTranslation("error.location"));
}
getLogger().log(Level.INFO, "Error: RandomTeleport could not find a save location after " + count + " tries for the player '" + playername + "' (minRange " + minRange + " maxRange " + maxRange + " xCenter " + xCenter + " zCenter " + zCenter + " forceBlocks=" + forceBlocks + " forceRegions=" + forceRegions + ")");
if(biomeList.size() > 0) {
getLogger().log(Level.INFO, "Biomelist:");
for(Biome biome : biomeList) {
getLogger().log(Level.INFO, " " + biome);
}
}
checkstat[count-1] = checkstat[count-1]++;
playerlock.remove(player.getUniqueId());
return true;
}
} while(!teleportCheck(player,world,x,z,biomeList, forceBlocks, forceRegions));
checkstat[count-1] = checkstat[count-1] + 1;
// if in force mode don't check chunks around location
if(chunkcount == 0) {
xold = x;
zold = z;
}
if(forceRegions) {
break;
}
//(re)set sum of valid chunks to zero
chunksum = 0;
// checks a square of 9x9 chunks around the random position for protected regions
if(worldguard || factionsApiVersion > 0 || griefprevention || clancontrol) {
for(int i = -4; i <= 4; i++) {
for(int j = -4; j <= 4; j++) {
int xcheck = x + i * 16;
int zcheck = z + j * 16;
Location location = new Location(world, xcheck, world.getHighestBlockYAt(xcheck, zcheck), zcheck);
if(checkforRegion(player,location, false)) chunksum++;
}
}
getLogger().log(debugLevel, "RandomTeleport (" + chunkcount + ". try) found " + chunksum + " unprotected chunks around the location " + x + "/" + z);
// if more not protected chunks were found then at the last random location:
// --> save the position to xold and zold and the chunksum to chunksumold
// --> xold/zold hold the coords of the location with the least protected chunks around it
if(chunksum > chunksumold) {
xold = x;
zold = z;
chunksumold = chunksum;
}
} else {
break;
}
// break the loop and use the x/z values with the highest sum of non proteted chunks
// if there is no location after 10 tries found which has no protected regions in a 15x15 square around the location
// or
// aborts if all 225 around the location are not protected
}
x = xold;
z = zold;
// attempts to teleport player, sends message if it fails
if(!teleportPlayer(playername,x,z,world,setSpawnpoint)) {
sender.sendMessage(ChatColor.DARK_RED + "Error:" + ChatColor.RED + " Player '" + playername + "' is not online anymore!");
} else {
getLogger().log(debugLevel, "Used teleport location X: " + x + " Z: " + z + " for player '" + playername + "' RandomTeleportID: " + cooldownid);
}
if(coption && !player.hasPermission("randomteleport.cooldownexempt")){
cooldown.put(cooldownid, System.currentTimeMillis());
writeMap(cooldown, "cooldown.map");
//getLogger().info("Saved cooldown");
}
playerlock.remove(player.getUniqueId());
return true;
}
return false;
}
/**
* Teleports player with the name playername at the highest block at x/z
* @param playername The name of the player
* @param x Coordinate of the block as int
* @param z Coordinate of the block as int
* @param world The world we should teleport the player to
* @param setSpawnpoint if we should set the player's spawnpoint to the location (1, 2 = force) or not (0)
* @return true if player got teleported
*/
private boolean teleportPlayer(String playername, int x ,int z, World world, int setSpawnpoint) {
final Player player = Bukkit.getServer().getPlayer(playername);
if(player != null && world != null) {
final int yTp = world.getHighestBlockYAt(x, z);
Location loc = new Location(world, x + 0.5, yTp + 0.5, z + 0.5);
player.teleport(loc);
player.sendMessage(getTranslation("teleport", ImmutableMap.of("x", Integer.toString(x), "y", Integer.toString(yTp), "z", Integer.toString(z))));
if(setSpawnpoint == 2 || (setSpawnpoint == 1 && player.getBedSpawnLocation() == null)) {
player.setBedSpawnLocation(loc, true);
player.sendMessage(getTranslation("setspawnpoint"));
}
return true;
}
return false;
}
/**
* Checks if block is valid to teleport to (no lava, fire, water, ...)
* @param player The player we should check
* @param world The world the coordinate is in
* @param x Coordinate of the block as int
* @param z Coordinate of the block as int
* @param biomeList THe list of biomes at that point
* @param forceBlocks true if should only check if the player wont die,
* false for block restrictions check
* @param forceRegions true if should not check if location is in region,
* false for region restriction
* @return true if the block is a valid teleport block
*/
private boolean teleportCheck(Player player, World world, int x, int z, List<Biome> biomeList, boolean forceBlocks, boolean forceRegions) {
if(worldborder) {
WorldBorder wbPlugin = (WorldBorder) getServer().getPluginManager().getPlugin("WorldBorder");
BorderData border = wbPlugin.getWorldBorder(world.getName());
if(border != null && !border.insideBorder(x, z)) {
return false;
}
}
org.bukkit.WorldBorder wb = world.getWorldBorder();
double wbMaxX = wb.getCenter().getX() + wb.getSize();
double wbMinX = wb.getCenter().getX() - wb.getSize();
double wbMaxZ = wb.getCenter().getZ() + wb.getSize();
double wbMinZ = wb.getCenter().getZ() - wb.getSize();
if(x > wbMaxX || x < wbMinX) {
return false;
}
if(z > wbMaxZ || z < wbMinZ) {
return false;
}
int y = world.getHighestBlockYAt(x, z);
Block highest = world.getBlockAt(x, y - 1, z);
getLogger().log(debugLevel, "Checked teleport location for player '" + player.getName() + "' X: " + x + " Y: " + (y - 1) + " Z: " + z + " is " + highest.getType() + " + " + world.getBlockAt(x, y + 1, z).getType() + ", Biome: " + highest.getBiome().toString());
if(biomeList.size() > 0 && !biomeList.contains(highest.getBiome())) {
return false;
}
if(!forceBlocks) {
switch (world.getEnvironment()) {
case NETHER:
return false;
case THE_END:
if(highest.getType() == Material.AIR || highest.getType() == Material.WATER || highest.getType() == Material.STATIONARY_WATER || highest.getType() == Material.STATIONARY_LAVA || highest.getType() == Material.WEB || highest.getType() == Material.LAVA || highest.getType() == Material.CACTUS || highest.getType() == Material.ENDER_PORTAL || highest.getType() == Material.PORTAL)
return false;
case NORMAL:
default:
if(highest.getType() != Material.SAND && highest.getType() != Material.GRAVEL && highest.getType() != Material.DIRT && highest.getType() != Material.GRASS)
return false;
}
} else {
if(highest.getType() == Material.AIR || highest.getType() == Material.WATER || highest.getType() == Material.STATIONARY_WATER || highest.getType() == Material.STATIONARY_LAVA || highest.getType() == Material.WEB || highest.getType() == Material.LAVA || highest.getType() == Material.CACTUS || highest.getType() == Material.ENDER_PORTAL || highest.getType() == Material.PORTAL)
return false;
}
return checkforRegion(player, highest.getLocation(), forceRegions);
}
/**
* Checks if the player can build at the highest block of the location
* @param player The Player to check with
* @param location the black at the location to check
* @param forceRegions true if should not check if location is in region,
* false for region restriction
* @return true or false
*/
//
private boolean checkforRegion(Player player, Location location, boolean forceRegions) {
if(!forceRegions) {
Block block = location.getWorld().getBlockAt(location);
BlockCanBuildEvent canBuildEvent = new BlockCanBuildEvent(block, block.getTypeId(), true);
getServer().getPluginManager().callEvent(canBuildEvent);
if(!canBuildEvent.isBuildable()) {
return false;
}
if(worldguard && !com.sk89q.worldguard.bukkit.WGBukkit.getPlugin().canBuild(player, block)) {
return false;
}
if(griefprevention && GriefPrevention.instance.dataStore.getClaimAt(location, true, null) != null) {
return false;
}
if(clancontrol) {
boolean chunkOccupied = ClanControl.getInstance().getRegionManager().getChunk(location) != null;
Region region = ClanControl.getInstance().getRegionManager().getRegion(location);
if(chunkOccupied || (region != null && region.getStatus() != RegionStatus.FREE)) {
return false;
}
}
if(factionsApiVersion == 27) {
com.massivecraft.factions.entity.Faction faction = com.massivecraft.factions.entity.BoardColl.get().getFactionAt(com.massivecraft.massivecore.ps.PS.valueOf(block));
if(faction != com.massivecraft.factions.entity.FactionColl.get().getNone()) {
return false;
}
}
if(factionsApiVersion == 26) {
com.massivecraft.factions.entity.Faction faction = com.massivecraft.factions.entity.BoardColls.get().getFactionAt(com.massivecraft.massivecore.ps.PS.valueOf(block));
if(faction != com.massivecraft.factions.entity.FactionColls.get().getForWorld(location.getWorld().getName()).getNone()) {
return false;
}
}
if(factionsApiVersion == 16) {
com.massivecraft.factions.Faction faction = com.massivecraft.factions.Board.getInstance().getFactionAt(new com.massivecraft.factions.FLocation(location));
if(faction != com.massivecraft.factions.Factions.getInstance().getNone()) {
return false;
}
}
}
return true;
}
/**
* Writes a Hashmap to a file
* @param object The Hashmap to write
* @param outputFile The file to write to
*/
public void writeMap(Object object, String outputFile) {
try {
File file = new File(getDataFolder(), outputFile);
if (!file.isFile()) {
if(!file.createNewFile()){
throw new IOException("Error creating new file: " + file.getPath());
}
}
FileOutputStream fileOut = new FileOutputStream(file.getPath());
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(object);
out.close();
fileOut.close();
getLogger().fine("Serialized data is saved in " + file.getPath());
} catch(IOException i) {
i.printStackTrace();
}
}
/**
* Reads a Hashmap from a file
* @param inputFile The file to read from
* @return An Object which is a HashMap<Object,Object>
*/
@SuppressWarnings("unchecked")
public Object readMap(String inputFile) {
HashMap<Object, Object> map = new HashMap<Object,Object>();
File file = new File(getDataFolder(), inputFile);
if (!file.isFile()) {
getLogger().log(Level.INFO, "No file found in " + file.getPath());
try {
if(!file.createNewFile()) {
throw new IOException("Error while creating new file: " + file.getPath());
} else {
writeMap(map, inputFile);
getLogger().log(Level.INFO, "New file created in " + file.getPath());
}
} catch (IOException e) {
e.printStackTrace();
}
}
try {
FileInputStream fileIn = new FileInputStream(file.getPath());
ObjectInputStream in = new ObjectInputStream(fileIn);
map = (HashMap<Object, Object>) in.readObject();
in.close();
fileIn.close();
getLogger().log(Level.INFO, "Sucessfully loaded cooldown.map.");
} catch(IOException i) {
getLogger().log(Level.WARNING, "No saved Map found in " + inputFile);
} catch(ClassNotFoundException e) {
e.printStackTrace();
}
return map;
}
/**
* Checks if a string is mumeric
* @param str to test
* @return True if input string is numeric
*/
public static boolean isNumeric(String str) {
for (char c : str.toCharArray()) {
if (!Character.isDigit(c)) return false;
}
return true;
}
public String getTranslation(String key) {
if(getConfig().getString("msg." + key, "").isEmpty()) {
return ChatColor.RED + "Unknown language key: " + ChatColor.YELLOW + key;
} else {
return ChatColor.translateAlternateColorCodes('&', getConfig().getString("msg." + key));
}
}
public String getTranslation(String key, Map<String, String> replacements) {
String string = getTranslation(key);
// insert replacements
if(replacements != null)
for(String variable : replacements.keySet())
string = string.replaceAll("\\{"+variable+"\\}", replacements.get(variable));
return string;
}
}

View File

@ -1,17 +0,0 @@
debug: false
# Triggered when you use /rtp without any additional paramters
# Just write your command as you would use it ingame here
# Don't use the -p parameter, this will get added automaticly with the senders name/the specified playername
presets:
default: "/rtp 100 1000 -f"
# add more to use /rtp <rtpname>, player needs "randomteleport.presets.<rtpname>"
# <rtpname>: "/rtp 1 2"
test: "rtp 10 200 -f"
msg:
search: "&7RandomTeleport searches for a safe place in world {worldname}. . ."
teleport: "&7RandomTeleport teleported you to X: {x} Y: {y} Z: {z}!"
setspawnpoint: "&7Your Respawnpoint has been set to your current location!"
error:
location: "&4Error: &cRandomTeleport could not find a save location!"
cooldown: "&cYou have to wait {cooldown_text}before using this RandomTeleport again!"

View File

@ -1,60 +0,0 @@
name: RandomTeleport
main: de.themoep.bukkit.plugin.RandomTeleport.RandomTeleport
softdepend: [WorldGuard,Factions,GriefPrevention,ClanControl,WorldBorder]
version: '${minecraft.plugin.version}'
description: provides a command to teleport the player to a random save location
author: Phoenix616
website: http://dev.bukkit.org/bukkit-plugins/randomteleport/
commands:
randomteleport:
aliases: [randomtp, rtp]
description: RandomTeleport command.
usage: |
/<command> - uses the default preset
/<command> <preset> [<playername>]- uses a specific preset
/<command> <minRange> <maxRange> [-p, -w, -x, -z, -c, -f]
minRange - minimum distance to the center point (square shaped)
maxRange - maximum distance to the center point (square shaped)
Options:
> -p,-player <playername> - teleports other players
> -w,-world <worldname> - teleports the player in a specific world
> -b,-biome <biomename> [<biome 2> ...] - only teleport to this biome (multiple allowed, Bukkit biome names!)
> -x,-xPos <x value> - x axis of the center point, if not set the player's x axis is used
> -z,-zPos <z value> - z axis of the center point, if not set the player's z axis is used
> -l,-loaded - only search loaded chunks for possible locations
> -c, -cooldown <seconds> - cooldown in seconds after which the player can use this teleporter again
> -f,-force - teleport even if there is no dirt/grass/sand/gravel, only checks for lava/water/cactus, ignores WorldGuard/Faction regions
> -f,-force [<blocks|regions>] - only ignore blocks or regions
/<command> stat - shows a statistic of the teleports since the last restart
/<command> reload - reloads the config
permissions:
randomteleport.use:
description: Gives permission to the command
default: op
randomteleport.tpothers:
description: Gives permission to teleport other players
default: op
randomteleport.cooldownexempt:
description: Teleportcooldown does not effect these players
default: op
randomteleport.stat:
description: Permission for showing the teleport statistic
default: op
randomteleport.reload:
description: Permission to use the reload command
default: op
randomteleport.presets.default:
description: Gives permission to use the default random teleport preset
default: op
randomteleport.presets.*:
description: Gives permission to use all random teleport presets
default: op
randomteleport.sign.preset.default:
description: Gives permission to use the default preset with a rightclick on a preset sign
default: op
randomteleport.sign.preset.*:
description: Gives permission to use all presets with a rightclick on a preset sign
default: op
randomteleport.sign.create:
description: Allows to create and destroy preset signs ([rtp] or [RandomTP] on the 2nd line and the preset name on the 3rd)
default: op

105
pom.xml Normal file
View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>de.themoep.randomteleport</groupId>
<artifactId>randomteleport-parent</artifactId>
<version>2.0-SNAPSHOT</version>
<description>Randomly teleport players on your server!</description>
<name>FUBSRandomTeleport</name>
<packaging>pom</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<build.number>${buildNumber}</build.number>
<minecraft.plugin.name>RandomTeleport</minecraft.plugin.name>
<minecraft.plugin.version>${project.version} ${buildDescription}</minecraft.plugin.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<licenses>
<license>
<url>https://moep.tv/licenses/gpl-v3.txt</url>
<name>GPLv3</name>
</license>
</licenses>
<modules>
<module>randomteleport-hook</module>
<module>randomteleport-plugin-hooks</module>
<module>randomteleport-plugin</module>
</modules>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/groups/public</url>
</repository>
<repository>
<id>paper-repo</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<repository>
<id>minebench-repo</id>
<url>https://repo.minebench.de/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.16.5-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.papermc</groupId>
<artifactId>paperlib</artifactId>
<version>1.0.7</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>de.themoep</groupId>
<artifactId>minedown</artifactId>
<version>1.6.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>de.themoep.utils</groupId>
<artifactId>lang-bukkit</artifactId>
<version>1.2-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>static_build_number</id>
<activation>
<property>
<name>!env.BUILD_NUMBER</name>
</property>
</activation>
<properties>
<buildNumber>0</buildNumber>
<buildDescription>(compiled at ${maven.build.timestamp})</buildDescription>
</properties>
</profile>
<profile>
<id>dynamic_build_number</id>
<activation>
<property>
<name>env.BUILD_NUMBER</name>
</property>
</activation>
<properties>
<buildNumber>${env.BUILD_NUMBER}</buildNumber>
<buildDescription>(build ${env.BUILD_NUMBER})</buildDescription>
</properties>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>randomteleport-parent</artifactId>
<groupId>de.themoep.randomteleport</groupId>
<version>2.0-SNAPSHOT</version>
</parent>
<artifactId>randomteleport-hook</artifactId>
</project>

View File

@ -0,0 +1,182 @@
package de.themoep.randomteleport.hook;
/*
* RandomTeleport
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.plugin.Plugin;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.stream.Collectors;
public class HookManager implements Listener, ProtectionHook, WorldborderHook {
private final Plugin plugin;
private Map<String, PluginHook> hookMap = new LinkedHashMap<>();
public HookManager(Plugin plugin) {
this.plugin = plugin;
hookMap.put("Vanilla Minecraft", new MinecraftHook(plugin));
plugin.getServer().getPluginManager().registerEvents(this, plugin);
for (Plugin p : plugin.getServer().getPluginManager().getPlugins()) {
if (p.isEnabled()) {
registerHook(p);
}
}
}
private void registerHook(Plugin plugin) {
String path = getClass().getPackage().getName() + ".plugin." + plugin.getName();
String version = plugin.getDescription().getVersion().replace('.', '_').replace('-', '_');
Class<?> hookClass = null;
do {
try {
hookClass = Class.forName(path + version + "Hook");
if (!PluginHook.class.isAssignableFrom(hookClass)) {
hookClass = null;
}
} catch (ClassNotFoundException ignored) {}
if (version.contains("_")) {
version = version.substring(0, version.lastIndexOf('_'));
} else {
try {
hookClass = Class.forName(path + "Hook");
if (!PluginHook.class.isAssignableFrom(hookClass)) {
hookClass = null;
}
} catch (ClassNotFoundException ignored) {}
break;
}
} while (hookClass == null);
if (hookClass != null) {
try {
PluginHook hook = (PluginHook) hookClass.getConstructor().newInstance();
if (hook instanceof Listener) {
getPlugin().getServer().getPluginManager().registerEvents((Listener) hook, getPlugin());
}
hookMap.put(plugin.getName(), hook);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
plugin.getLogger().log(Level.SEVERE, "Could not hook into " + plugin.getName() + " " + plugin.getDescription().getVersion() + "!", e);
}
}
}
@EventHandler
public void onPluginEnable(PluginEnableEvent event) {
registerHook(event.getPlugin());
}
@EventHandler
public void onPluginDisable(PluginDisableEvent event) {
PluginHook hook = hookMap.remove(event.getPlugin().getName());
if (hook instanceof Listener) {
hook.unregisterEvents();
}
}
@Override
public Plugin getPlugin() {
return plugin;
}
@Override
public String getPluginName() {
return plugin.getName();
}
/**
* Get all hooks of a certain type, hooks registered later override hooks registered before them
* @param hookClass The type of hook to get
* @param <T> The type of hook to get
* @return A list of hooks, empty if there are none
*/
public <T extends PluginHook> List<T> getHooks(Class<T> hookClass) {
List<T> list = hookMap.values().stream().filter(hookClass::isInstance).map(h -> (T) h).collect(Collectors.toList());
Collections.reverse(list);
return list;
}
// Convenience methods to check all registered hooks
@Override
public boolean canBuild(Player player, Location location) {
for (ProtectionHook hook : getHooks(ProtectionHook.class)) {
if (!hook.canBuild(player, location)) {
return false;
}
}
return true;
}
@Override
public boolean canBuild(Player player, World world, int chunkX, int chunkZ) {
for (ProtectionHook hook : getHooks(ProtectionHook.class)) {
if (!hook.canBuild(player, world, chunkX, chunkZ)) {
return false;
}
}
return true;
}
@Override
public Location getCenter(World world) {
for (WorldborderHook hook : getHooks(WorldborderHook.class)) {
Location center = hook.getCenter(world);
if (center != null) {
return center;
}
}
return null;
}
@Override
public double getBorderRadius(World world) {
for (WorldborderHook hook : getHooks(WorldborderHook.class)) {
double radius = hook.getBorderRadius(world);
if (radius > 0) {
return radius;
}
}
return -1;
}
@Override
public boolean isInsideBorder(Location location) {
for (WorldborderHook hook : getHooks(WorldborderHook.class)) {
if (!hook.isInsideBorder(location)) {
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,83 @@
package de.themoep.randomteleport.hook;
/*
* RandomTeleport
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import io.papermc.lib.PaperLib;
import io.papermc.lib.features.blockstatesnapshot.BlockStateSnapshotResult;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Lockable;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
public class MinecraftHook implements ProtectionHook, WorldborderHook {
private final Plugin plugin;
public MinecraftHook(Plugin plugin) {
this.plugin = plugin;
}
@Override
public Plugin getPlugin() {
return plugin;
}
@Override
public String getPluginName() {
return "Vanilla Minecraft";
}
@Override
public boolean canBuild(Player player, Location location) {
BlockStateSnapshotResult state = PaperLib.getBlockState(location.getBlock(), false);
if (state.getState() instanceof Lockable) {
return ((Lockable) state.getState()).getLock() == null;
}
return true;
}
@Override
public boolean canBuild(Player player, World world, int chunkX, int chunkZ) {
return true;
}
@Override
public Location getCenter(World world) {
if (world.getWorldBorder() != null) {
return world.getWorldBorder().getCenter();
}
return null;
}
@Override
public double getBorderRadius(World world) {
if (world.getWorldBorder() != null) {
return world.getWorldBorder().getSize() / 2;
}
return 0;
}
@Override
public boolean isInsideBorder(Location location) {
if (location.getWorld().getWorldBorder() != null) {
return location.getWorld().getWorldBorder().isInside(location);
}
return true;
}
}

View File

@ -0,0 +1,33 @@
package de.themoep.randomteleport.hook;
/*
* RandomTeleport
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import org.bukkit.plugin.Plugin;
public interface PluginHook {
Plugin getPlugin();
String getPluginName();
default int getHookVersion() {
return 0;
};
default void unregisterEvents() {};
}

View File

@ -0,0 +1,57 @@
package de.themoep.randomteleport.hook;
/*
* RandomTeleport
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
public interface ProtectionHook extends PluginHook {
/**
* Check if a player can build at a location
*
* @param player The player to check
* @param location The location to check
* @return Whether or not the player can build
*/
boolean canBuild(Player player, Location location);
/**
* Check if a player can build in a chunk
* @param player The player to check
* @param chunk The chunk to check
* @return Whether or not the player can build
*/
default boolean canBuild(Player player, Chunk chunk) {
return canBuild(player, chunk.getWorld(), chunk.getX(), chunk.getZ());
}
/**
* Check if a player can build in a chunk
* @param player The player to check
* @param world The chunk's world
* @param chunkX The chunk's X coordinate
* @param chunkZ The chunk's Z coordinate
* @return Whether or not the player can build
*/
boolean canBuild(Player player, World world, int chunkX, int chunkZ);
}

View File

@ -0,0 +1,46 @@
package de.themoep.randomteleport.hook;
/*
* RandomTeleport
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import org.bukkit.Location;
import org.bukkit.World;
public interface WorldborderHook extends PluginHook {
/**
* Get the center of the world border
* @param world The world to get the border center for
* @return The center or null if there is no border
*/
Location getCenter(World world);
/**
* Get the radius of the world border
* @param world The world to get the border radius for
* @return The radius or -1 if there is no border
*/
double getBorderRadius(World world);
/**
* Convenience method to check if a location is inside the border
* @param location The location to check
* @return True if it is inside (or there is no border), false if not
*/
boolean isInsideBorder(Location location);
}

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>randomteleport-plugin-hooks</artifactId>
<groupId>de.themoep.randomteleport.pluginhook</groupId>
<version>2.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>chunkyborder</artifactId>
<repositories>
<repository>
<id>codemc</id>
<url>https://repo.codemc.io/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.popcraft</groupId>
<artifactId>chunkyborder-bukkit</artifactId>
<version>1.1.42</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.popcraft</groupId>
<artifactId>chunky-bukkit</artifactId>
<version>1.3.52</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.13-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,47 @@
package de.themoep.randomteleport.hook.plugin;
import de.themoep.randomteleport.hook.WorldborderHook;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.plugin.Plugin;
import org.popcraft.chunkyborder.BorderData;
import org.popcraft.chunkyborder.ChunkyBorder;
public class ChunkyBorderHook implements WorldborderHook {
private final Plugin plugin;
private final ChunkyBorder chunkyBorder;
public ChunkyBorderHook() {
this.plugin = Bukkit.getPluginManager().getPlugin("ChunkyBorder");
chunkyBorder = plugin.getServer().getServicesManager().getRegistration(ChunkyBorder.class).getProvider();
}
@Override
public Plugin getPlugin() {
return this.plugin;
}
@Override
public Location getCenter(World world) {
BorderData borderData = chunkyBorder.getBorders().get(world.getName());
return borderData != null ? new Location(world, borderData.getCenterX(),0D,borderData.getCenterZ()) : null;
}
@Override
public double getBorderRadius(World world) {
BorderData borderData = chunkyBorder.getBorders().get(world.getName());
return borderData != null ? borderData.getRadiusX() : -1;
}
@Override
public boolean isInsideBorder(Location location) {
BorderData borderData = chunkyBorder.getBorders().get(location.getWorld().getName());
return borderData == null || borderData.getBorder().isBounding(location.getBlockX(),location.getBlockZ());
}
@Override
public String getPluginName() {
return plugin.getName();
}
}

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>randomteleport-plugin-hooks</artifactId>
<groupId>de.themoep.randomteleport.pluginhook</groupId>
<version>2.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>factions-uuid</artifactId>
<repositories>
<repository>
<id>factions-repo</id>
<url>https://ci.ender.zone/plugin/repository/everything/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.massivecraft</groupId>
<artifactId>Factions</artifactId>
<version>1.6.9.5-U0.2.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,57 @@
package de.themoep.randomteleport.hook.plugin;
/*
* RandomTeleport - Factions UUID Hook
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.massivecraft.factions.Board;
import com.massivecraft.factions.FLocation;
import de.themoep.randomteleport.hook.ProtectionHook;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
public class Factions1_6_9_5_U0Hook implements ProtectionHook {
private final Plugin inst;
public Factions1_6_9_5_U0Hook() {
inst = Bukkit.getPluginManager().getPlugin("Factions");
}
@Override
public Plugin getPlugin() {
return inst;
}
@Override
public String getPluginName() {
return inst.getName();
}
@Override
public boolean canBuild(Player player, Location location) {
return Board.getInstance().getFactionAt(new FLocation(location)) == null;
}
@Override
public boolean canBuild(Player player, World world, int chunkX, int chunkZ) {
return Board.getInstance().getFactionAt(new FLocation(world.getName(), chunkX, chunkZ)) == null;
}
}

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>randomteleport-plugin-hooks</artifactId>
<groupId>de.themoep.randomteleport.pluginhook</groupId>
<version>2.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>factions</artifactId>
<repositories>
<repository>
<id>minebench-repo</id>
<url>https://repo.minebench.de/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.massivecraft.factions</groupId>
<artifactId>factions</artifactId>
<version>2.12.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.massivecraft.massivecore</groupId>
<artifactId>massivecore</artifactId>
<version>2.12.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,56 @@
package de.themoep.randomteleport.hook.plugin;
/*
* RandomTeleport - Factions Hook
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.massivecraft.factions.entity.BoardColl;
import com.massivecraft.massivecore.ps.PS;
import de.themoep.randomteleport.hook.ProtectionHook;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
public class Factions2Hook implements ProtectionHook {
private final Plugin inst;
public Factions2Hook() {
inst = Bukkit.getPluginManager().getPlugin("Factions");
}
@Override
public Plugin getPlugin() {
return inst;
}
@Override
public String getPluginName() {
return inst.getName();
}
@Override
public boolean canBuild(Player player, Location location) {
return BoardColl.get().getFactionAt(PS.valueOf(location)) == null;
}
@Override
public boolean canBuild(Player player, World world, int chunkX, int chunkZ) {
return BoardColl.get().getFactionAt(PS.valueOf(world.getName(), chunkX, chunkZ)) == null;
}
}

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>randomteleport-plugin-hooks</artifactId>
<groupId>de.themoep.randomteleport.pluginhook</groupId>
<version>2.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>griefdefender</artifactId>
<repositories>
<repository>
<id>gdapi</id>
<url>https://repo.glaremasters.me/repository/bloodshot</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.griefdefender</groupId>
<artifactId>api</artifactId>
<version>2.1.0-20220122.032038-5</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.13-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,46 @@
package de.themoep.randomteleport.hook.plugin;
import com.griefdefender.api.GriefDefender;
import com.griefdefender.api.claim.ClaimManager;
import com.griefdefender.api.claim.ClaimTypes;
import de.themoep.randomteleport.hook.ProtectionHook;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
public class GriefDefenderHook implements ProtectionHook {
@Override
public Plugin getPlugin() {
return Bukkit.getPluginManager().getPlugin("GriefDefender");
}
@Override
public String getPluginName() {
return "GriefDefender";
}
@Override
public boolean canBuild(Player player, Location location) {
return canBuild(location.getWorld(), location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
@Override
public boolean canBuild(Player player, World world, int chunkX, int chunkZ) {
return canBuild(world, chunkX * 16, world.getSeaLevel(), chunkZ * 16);
}
private boolean canBuild(World world, int x, int y, int z) {
if (GriefDefender.getCore().isEnabled(world.getUID())) {
ClaimManager claimManager = GriefDefender.getCore().getClaimManager(world.getUID());
if (claimManager == null) {
return true;
} else {
return claimManager.getClaimAt(x, y, z).getType() == ClaimTypes.WILDERNESS;
}
}
return true;
}
}

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ RandomTeleport - randomteleport-plugin-hooks - $project.description
~ Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<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">
<parent>
<artifactId>randomteleport-plugin-hooks</artifactId>
<groupId>de.themoep.randomteleport.pluginhook</groupId>
<version>2.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>griefprevention</artifactId>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.github.TechFortress</groupId>
<artifactId>GriefPrevention</artifactId>
<version>16.12.0</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.13-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,62 @@
package de.themoep.randomteleport.hook.plugin;
/*
* RandomTeleport - GriefPrevention Hook
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import de.themoep.randomteleport.hook.ProtectionHook;
import me.ryanhamshire.GriefPrevention.*;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
public class GriefPreventionHook implements ProtectionHook {
private final GriefPrevention inst;
public GriefPreventionHook() {
inst = GriefPrevention.instance;
}
@Override
public Plugin getPlugin() {
return inst;
}
@Override
public String getPluginName() {
return inst.getName();
}
@Override
public boolean canBuild(Player player, Location location) {
return inst.dataStore.getClaimAt(location, false, null) == null;
}
@Override
public boolean canBuild(Player player, World world, int chunkX, int chunkZ) {
if (inst.claimsEnabledForWorld(world)) {
for (Claim claim : inst.dataStore.getClaims(chunkX, chunkZ)) {
if (claim.getLesserBoundaryCorner().getWorld().equals(world) && !player.getUniqueId().equals(claim.ownerID)) {
return false;
}
}
}
return true;
}
}

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>randomteleport-parent</artifactId>
<groupId>de.themoep.randomteleport</groupId>
<version>2.0-SNAPSHOT</version>
</parent>
<groupId>de.themoep.randomteleport.pluginhook</groupId>
<artifactId>randomteleport-plugin-hooks</artifactId>
<packaging>pom</packaging>
<modules>
<module>worldguard-6</module>
<module>worldguard-7</module>
<module>griefprevention</module>
<module>griefdefender</module>
<module>redprotect</module>
<module>factions</module>
<module>factions-uuid</module>
<module>worldborder</module>
<module>chunkyborder</module>
</modules>
<dependencies>
<dependency>
<groupId>de.themoep.randomteleport</groupId>
<artifactId>randomteleport-hook</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>randomteleport-plugin-hooks</artifactId>
<groupId>de.themoep.randomteleport.pluginhook</groupId>
<version>2.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>redprotect</artifactId>
<repositories>
<repository>
<id>redprotect-repo</id>
<url>https://raw.githubusercontent.com/FabioZumbi12/RedProtect/mvn-repo/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>br.net.fabiozumbi12.RedProtect</groupId>
<artifactId>RedProtect-Spigot</artifactId>
<version>7.6.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>br.net.fabiozumbi12.RedProtect</groupId>
<artifactId>RedProtect-Core</artifactId>
<version>7.6.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.13-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,62 @@
package de.themoep.randomteleport.hook.plugin;
/*
* RandomTeleport - RedProtect Hook
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import br.net.fabiozumbi12.RedProtect.Bukkit.RedProtect;
import br.net.fabiozumbi12.RedProtect.Bukkit.Region;
import de.themoep.randomteleport.hook.ProtectionHook;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
public class RedProtectHook implements ProtectionHook {
private final RedProtect inst;
public RedProtectHook() {
inst = RedProtect.get();
}
@Override
public Plugin getPlugin() {
return inst;
}
@Override
public String getPluginName() {
return inst.getName();
}
@Override
public boolean canBuild(Player player, Location location) {
Region region = inst.getAPI().getRegion(location);
return region == null || region.canBuild(player);
}
@Override
public boolean canBuild(Player player, World world, int chunkX, int chunkZ) {
for (Region region : inst.getAPI().getChunkRegions(world.getChunkAt(chunkX, chunkZ))) {
if (!region.canBuild(player)) {
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>randomteleport-plugin-hooks</artifactId>
<groupId>de.themoep.randomteleport.pluginhook</groupId>
<version>2.0-SNAPSHOT</version>
</parent>
<artifactId>worldborder</artifactId>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.github.Brettflan</groupId>
<artifactId>WorldBorder</artifactId>
<version>master-c5df3417c8-1</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,62 @@
package de.themoep.randomteleport.hook.plugin;
/*
* RandomTeleport - worldborder - $project.description
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.wimbli.WorldBorder.BorderData;
import com.wimbli.WorldBorder.WorldBorder;
import de.themoep.randomteleport.hook.WorldborderHook;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.plugin.Plugin;
public class WorldBorderHook implements WorldborderHook {
private final WorldBorder plugin;
public WorldBorderHook() {
plugin = WorldBorder.plugin;
}
@Override
public Location getCenter(World world) {
BorderData data = plugin.getWorldBorder(world.getName());
return data == null ? null : new Location(world, data.getX(), 0, data.getZ());
}
@Override
public double getBorderRadius(World world) {
BorderData data = plugin.getWorldBorder(world.getName());
return data == null ? -1 : Math.min(data.getRadiusX(), data.getRadiusZ());
}
@Override
public boolean isInsideBorder(Location location) {
BorderData data = plugin.getWorldBorder(location.getWorld().getName());
return data == null || data.insideBorder(location);
}
@Override
public Plugin getPlugin() {
return plugin;
}
@Override
public String getPluginName() {
return plugin.getName();
}
}

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>randomteleport-plugin-hooks</artifactId>
<groupId>de.themoep.randomteleport.pluginhook</groupId>
<version>2.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>worldguard-6</artifactId>
<repositories>
<repository>
<id>sk89q-repo</id>
<url>https://maven.sk89q.com/repo/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.sk89q</groupId>
<artifactId>worldguard</artifactId>
<version>6.1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,55 @@
package de.themoep.randomteleport.hook.plugin;
/*
* RandomTeleport - worldguard-6 - $project.description
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import de.themoep.randomteleport.hook.ProtectionHook;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
public class WorldGuard6Hook implements ProtectionHook {
private final WorldGuardPlugin inst;
public WorldGuard6Hook() {
inst = WorldGuardPlugin.inst();
}
@Override
public Plugin getPlugin() {
return inst;
}
@Override
public String getPluginName() {
return inst.getName();
}
@Override
public boolean canBuild(Player player, Location location) {
return inst.canBuild(player, location);
}
@Override
public boolean canBuild(Player player, World world, int chunkX, int chunkZ) {
return canBuild(player, new Location(world, (double) chunkX * 16 + 8, world.getSeaLevel(), (double) chunkZ * 16 + 8));
}
}

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>randomteleport-plugin-hooks</artifactId>
<groupId>de.themoep.randomteleport.pluginhook</groupId>
<version>2.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>worldguard-7</artifactId>
<repositories>
<repository>
<id>sk89q-repo</id>
<url>https://maven.sk89q.com/repo/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.sk89q.worldguard</groupId>
<artifactId>worldguard-legacy</artifactId>
<version>7.0.0-SNAPSHOT</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.13-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,65 @@
package de.themoep.randomteleport.hook.plugin;
/*
* RandomTeleport - worldguard-7 - $project.description
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.protection.flags.Flags;
import de.themoep.randomteleport.hook.ProtectionHook;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
public class WorldGuard7Hook implements ProtectionHook {
private final WorldGuardPlugin inst;
public WorldGuard7Hook() {
inst = WorldGuardPlugin.inst();
}
@Override
public Plugin getPlugin() {
return inst;
}
@Override
public String getPluginName() {
return inst.getName();
}
@Override
public boolean canBuild(Player player, org.bukkit.Location location) {
return canBuild(WorldGuardPlugin.inst().wrapPlayer(player), BukkitAdapter.adapt(location));
}
@Override
public boolean canBuild(Player player, World world, int chunkX, int chunkZ) {
return canBuild(WorldGuardPlugin.inst().wrapPlayer(player), new Location(
BukkitAdapter.adapt(world), (double) chunkX * 16 + 8, world.getSeaLevel(), (double) chunkZ * 16 + 8)
);
}
private boolean canBuild(LocalPlayer player, Location location) {
return WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery().testBuild(location, player, Flags.BUILD);
}
}

View File

@ -0,0 +1,102 @@
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>randomteleport-parent</artifactId>
<groupId>de.themoep.randomteleport</groupId>
<version>2.0-SNAPSHOT</version>
</parent>
<artifactId>randomteleport-plugin</artifactId>
<packaging>jar</packaging>
<repositories>
<repository>
<id>paper-repo</id>
<url>https://papermc.io/repo/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>randomteleport-hook</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>${project.groupId}.pluginhook</groupId>
<artifactId>worldguard-6</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>${project.groupId}.pluginhook</groupId>
<artifactId>worldguard-7</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>${project.groupId}.pluginhook</groupId>
<artifactId>worldborder</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>${project.groupId}.pluginhook</groupId>
<artifactId>chunkyborder</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>${project.groupId}.pluginhook</groupId>
<artifactId>griefdefender</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>${minecraft.plugin.name}</finalName>
<directory>../target/</directory>
<resources>
<resource>
<filtering>true</filtering>
<directory>${project.basedir}/src/main/resources</directory>
</resource>
</resources>
<plugins>
<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>de.themoep.randomteleport.libs.paperlib</shadedPattern>
</relocation>
<relocation>
<pattern>de.themoep.minedown</pattern>
<shadedPattern>de.themoep.randomteleport.libs.minedown</shadedPattern>
</relocation>
<relocation>
<pattern>de.themoep.utils.lang</pattern>
<shadedPattern>de.themoep.randomteleport.libs.lang</shadedPattern>
</relocation>
</relocations>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,514 @@
package de.themoep.randomteleport;
/*
* RandomTeleport
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import de.themoep.minedown.MineDown;
import de.themoep.randomteleport.api.RandomTeleportAPI;
import de.themoep.randomteleport.hook.HookManager;
import de.themoep.randomteleport.listeners.SignListener;
import de.themoep.randomteleport.searcher.RandomSearcher;
import de.themoep.randomteleport.searcher.options.*;
import de.themoep.randomteleport.searcher.validators.BiomeValidator;
import de.themoep.randomteleport.searcher.validators.BlockValidator;
import de.themoep.randomteleport.searcher.validators.HeightValidator;
import de.themoep.randomteleport.searcher.validators.LocationValidator;
import de.themoep.randomteleport.searcher.validators.ProtectionValidator;
import de.themoep.randomteleport.searcher.validators.WorldborderValidator;
import de.themoep.utils.lang.bukkit.LanguageManager;
import io.papermc.lib.PaperLib;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.stream.Collectors;
public class RandomTeleport extends JavaPlugin implements RandomTeleportAPI {
public static final Random RANDOM = new Random();
private HookManager hookManager;
private LanguageManager lang;
private Table<String, UUID, Map.Entry<Long, Integer>> cooldowns = HashBasedTable.create();
private Map<UUID, RandomSearcher> runningSearchers = new HashMap<>();
private ValidatorRegistry locationValidators = new ValidatorRegistry();
private List<OptionParser> optionParsers = new ArrayList<>();
private Material[] safeBlocks;
private Material[] unsafeBlocks;
private Set<String> signVariables;
private boolean hasMinHeight = true;
public void onEnable() {
hookManager = new HookManager(this);
loadConfig();
initOptionParsers();
initValidators();
getCommand("randomteleport").setExecutor(new RandomTeleportCommand(this));
getServer().getPluginManager().registerEvents(new SignListener(this), this);
}
public void loadConfig() {
saveDefaultConfig();
reloadConfig();
List<String> safeBlocksList;
if (getConfig().contains("save-blocks")) {
safeBlocksList = getConfig().getStringList("save-blocks");
} else {
safeBlocksList = getConfig().getStringList("safe-blocks");
}
safeBlocks = safeBlocksList.stream()
.map(s -> {
Material mat = Material.matchMaterial(s);
if (mat == null) {
getLogger().log(Level.WARNING, "Error in safe blocks config! No material found with name " + s);
}
return mat;
})
.filter(Objects::nonNull)
.toArray(Material[]::new);
List<String> unsafeBlocksList;
if (getConfig().contains("unsave-blocks")) {
unsafeBlocksList = getConfig().getStringList("unsave-blocks");
} else {
unsafeBlocksList = getConfig().getStringList("unsafe-blocks");
}
unsafeBlocks = unsafeBlocksList.stream()
.map(s -> {
Material mat = Material.matchMaterial(s);
if (mat == null) {
getLogger().log(Level.WARNING, "Error in unsafe blocks config! No material found with name " + s);
}
// Air was in the default for a while now but will cause issues. Don't allow that.
if (mat == Material.AIR) {
getLogger().log(Level.WARNING, "Your list of unsafe blocks contained 'air'!" +
" This will cause issues and has not been loaded. Remove it from your config to remove this warning!");
return null;
}
return mat;
})
.filter(Objects::nonNull)
.toArray(Material[]::new);
signVariables = getConfig().getStringList("sign-variables").stream().map(String::toLowerCase).collect(Collectors.toSet());
lang = new LanguageManager(this, getConfig().getString("lang"));
}
private void initOptionParsers() {
addOptionParser(new BooleanOptionParser("debug", (searcher) -> searcher.setDebug(true)));
addOptionParser(new SimpleOptionParser(array("p", "player"), (searcher, args) -> {
if (args.length > 0 && searcher.getInitiator().hasPermission("randomteleport.tpothers")) {
List<Player> players = new ArrayList<>();
for (String arg : args) {
for (String s : arg.split(",")) {
Player player = getServer().getPlayer(s);
if (player == null) {
throw new PlayerNotFoundException(s);
}
players.add(player);
}
}
searcher.getTargets().addAll(players);
return true;
}
return false;
}));
addOptionParser(new SimpleOptionParser(array("x", "xpos"), 1, (searcher, args) -> {
if (args.length > 0) {
searcher.getCenter().setX(Integer.parseInt(args[0]));
return true;
}
return false;
}));
addOptionParser(new SimpleOptionParser(array("z", "zpos"), 1, (searcher, args) -> {
if (args.length > 0) {
searcher.getCenter().setZ(Integer.parseInt(args[0]));
return true;
}
return false;
}));
addOptionParser(new SimpleOptionParser(array("miny"), (searcher, args) -> {
if (args.length > 0) {
searcher.setMinY(Integer.parseInt(args[0]));
return true;
}
return false;
}));
addOptionParser(new SimpleOptionParser(array("maxy"), (searcher, args) -> {
if (args.length > 0) {
searcher.setMaxY(Integer.parseInt(args[0]));
return true;
}
return false;
}));
addOptionParser(new SimpleOptionParser(array("w", "world"), (searcher, args) -> {
if (args.length > 0) {
String[] worldNames = args[0].split(",");
String worldName = worldNames[searcher.getRandom().nextInt(worldNames.length)];
World world = getServer().getWorld(worldName);
if (world == null) {
throw new WorldNotFoundException(worldName);
}
searcher.setWorld(world);
return true;
}
return false;
}));
addOptionParser(new SimpleOptionParser(array("c", "cooldown"), (searcher, args) -> {
if (args.length > 0) {
searcher.setCooldown(Integer.parseInt(args[0]));
return true;
}
return false;
}));
addOptionParser(new SimpleOptionParser(array("f", "force"), (searcher, args) -> {
if (args.length > 0) {
if ("regions".equalsIgnoreCase(args[0])) {
searcher.getValidators().remove("protection");
} else if ("blocks".equalsIgnoreCase(args[0])) {
searcher.getValidators().add(new BlockValidator(false, unsafeBlocks));
} else {
throw new NotFoundException(args[0]);
}
} else {
searcher.getValidators().remove("protection");
searcher.getValidators().add(new BlockValidator(false, unsafeBlocks));
}
return true;
}));
addOptionParser(new SimpleOptionParser(array("b", "biome"), (searcher, args) -> {
if (args.length > 0) {
List<Biome> biomes = new ArrayList<>();
for (String arg : args) {
biomes.add(Biome.valueOf(arg.toUpperCase()));
}
if (!biomes.isEmpty()) {
searcher.getValidators().add(new BiomeValidator(biomes.toArray(new Biome[0])));
return true;
}
return false;
}
return false;
}));
addOptionParser(new SimpleOptionParser(array("l", "loaded"), (searcher, args) -> {
searcher.searchInLoadedOnly(true);
return true;
}));
addOptionParser(new SimpleOptionParser(array("g", "generated"), (searcher, args) -> {
searcher.searchInGeneratedOnly(true);
return true;
}));
addOptionParser(new SimpleOptionParser(array("id"), (searcher, args) -> {
if (args.length > 0) {
searcher.setId(args[0]);
return true;
}
return false;
}));
addOptionParser(new SimpleOptionParser(array("t", "tries"), (searcher, args) -> {
if (args.length > 0) {
searcher.setMaxTries(Integer.parseInt(args[0]));
return true;
}
return false;
}));
addOptionParser(new SimpleOptionParser("checkdelay", (searcher, args) -> {
if (args.length > 0) {
searcher.setCheckDelay(Integer.parseInt(args[0]));
return true;
}
return false;
}));
addOptionParser(new AdditionalOptionParser("spawnpoint", "sp"));
}
private void initValidators() {
locationValidators.add(new WorldborderValidator());
locationValidators.add(new HeightValidator(unsafeBlocks));
locationValidators.add(new ProtectionValidator());
locationValidators.add(new BlockValidator(safeBlocks));
}
/**
* Get the map of all running searchers
* @return The map of running searchers
*/
public Map<UUID, RandomSearcher> getRunningSearchers() {
return runningSearchers;
}
/**
* Utility method to create arrays with a nicer syntax. Seriously, why does Java not just accept {"string"} as parameters?!?
* @param array The array values
* @return The same array
*/
private static <T> T[] array(T... array) {
return array;
}
public boolean sendMessage(Collection<? extends CommandSender> senders, String key, String... replacements) {
boolean r = false;
for (CommandSender sender : senders) {
r |= sendMessage(sender, key, replacements);
}
return r;
}
public boolean sendMessage(CommandSender sender, String key, String... replacements) {
BaseComponent[] message = getComponentMessage(sender, key, replacements);
if (message != null && message.length != 0) {
sender.spigot().sendMessage(message);
return true;
}
return false;
}
public BaseComponent[] getComponentMessage(CommandSender sender, String key, String... replacements) {
return new MineDown(getLang(sender, key))
.placeholderPrefix("{")
.placeholderSuffix("}")
.replace(replacements)
.toComponent();
}
public String getTextMessage(CommandSender sender, String key, String... replacements) {
return TextComponent.toLegacyText(getComponentMessage(sender, key, replacements));
}
private String getLang(CommandSender sender, String key) {
return lang.getConfig(sender).get(key);
}
public HookManager getHookManager() {
return hookManager;
}
public ValidatorRegistry getLocationValidators() {
return locationValidators;
}
/**
*
* @return
*/
public List<OptionParser> getOptionParsers() {
return optionParsers;
}
/**
* Add an option parser to this plugin
* @param parser The parser to add
*/
public void addOptionParser(OptionParser parser) {
optionParsers.add(parser);
if (parser instanceof SimpleOptionParser) {
Permission parent = getServer().getPluginManager().getPermission("randomteleport.manual.option.*");
for (String alias : ((SimpleOptionParser) parser).getAliases()) {
Permission perm = new Permission("randomteleport.manual.option." + alias, PermissionDefault.OP);
perm.addParent(parent, true);
try {
getServer().getPluginManager().addPermission(perm);
} catch (IllegalArgumentException ignored) {} // duplicate
}
}
}
/**
* Check whether or not a sign line matches the configured variables
* @param line The line to match
* @return <tt>true</tt> if it matches; <tt>false</tt> if not
*/
public boolean matchesSignVariable(String line) {
return signVariables.contains(line.toLowerCase());
}
/**
* Create and run a searcher using specified args the same way the command does
* @param sender The sender of the command
* @param center The center location for the searcher
* @param args The arguments to parse
* @return Returns the searcher that is running or null if it was stopped due to a cooldown
* @throws IllegalArgumentException Thrown when arguments couldn't be handled properly
*/
public RandomSearcher parseAndRun(CommandSender sender, Location center, String[] args) {
RandomSearcher searcher = new RandomSearcher(this, sender, center, Integer.parseInt(args[0]), Integer.parseInt(args[1]));
String[] optionArgs = Arrays.copyOfRange(args, 2, args.length);
for (OptionParser parser : getOptionParsers()) {
parser.parse(searcher, optionArgs);
}
int cooldown = 0;
for (Entity target : searcher.getTargets()) {
Map.Entry<Long, Integer> lastUse = cooldowns.get(searcher.getId(), target.getUniqueId());
if (lastUse != null) {
int targetCooldown = (int) ((System.currentTimeMillis() - lastUse.getKey()) / 1000);
if (targetCooldown > cooldown && !target.hasPermission("randomteleport.cooldownexempt")) {
cooldown = targetCooldown;
}
}
}
if (cooldown > 0 && cooldown < searcher.getCooldown()) {
sendMessage(searcher.getTargets(), "error.cooldown", "cooldown_text", Integer.toString(searcher.getCooldown() - cooldown));
return null;
}
sendMessage(searcher.getTargets(), "search", "worldname", searcher.getCenter().getWorld().getName());
searcher.search().thenApply(targetLoc -> {
searcher.getTargets().forEach(e -> {
if (e instanceof Player) {
Location belowLoc = targetLoc.clone().subtract(0, 1, 0);
Block belowBlock = belowLoc.getBlock();
((Player) e).sendBlockChange(belowLoc, belowBlock.getBlockData());
}
targetLoc.setX(targetLoc.getBlockX() + 0.5);
targetLoc.setY(targetLoc.getY() + 0.1);
targetLoc.setZ(targetLoc.getBlockZ() + 0.5);
if (searcher.isDebug()) {
getLogger().info("[DEBUG] Search " + searcher.getId() + " triggered by " + searcher.getInitiator().getName()
+ " will try to teleport " + e.getType() + " " + e.getName() + "/" + e.getUniqueId() + " to " + targetLoc);
}
PaperLib.teleportAsync(e, targetLoc).whenComplete((success, ex) -> {
if (success) {
cooldowns.put(searcher.getId(), e.getUniqueId(), new AbstractMap.SimpleImmutableEntry<>(System.currentTimeMillis(), searcher.getCooldown()));
sendMessage(e, "teleport",
"worldname", targetLoc.getWorld().getName(),
"x", String.valueOf(targetLoc.getBlockX()),
"y", String.valueOf(targetLoc.getBlockY()),
"z", String.valueOf(targetLoc.getBlockZ())
);
if (searcher.getOptions().containsKey("spawnpoint") && e instanceof Player) {
if (((Player) e).getBedSpawnLocation() == null || "force".equalsIgnoreCase(searcher.getOptions().get("spawnpoint"))) {
((Player) e).setBedSpawnLocation(targetLoc, true);
sendMessage(e, "setspawnpoint",
"worldname", targetLoc.getWorld().getName(),
"x", String.valueOf(targetLoc.getBlockX()),
"y", String.valueOf(targetLoc.getBlockY()),
"z", String.valueOf(targetLoc.getBlockZ())
);
}
}
} else {
sendMessage(e, "error.teleport",
"worldname", targetLoc.getWorld().getName(),
"x", String.valueOf(targetLoc.getBlockX()),
"y", String.valueOf(targetLoc.getBlockY()),
"z", String.valueOf(targetLoc.getBlockZ())
);
}
if (ex != null && searcher.isDebug()) {
getLogger().log(Level.SEVERE, "Error while trying to teleport to location!", ex);
}
});
});
return true;
}).exceptionally(ex -> {
sendMessage(sender, "error.location");
if (!(ex.getCause() instanceof NotFoundException)) {
getLogger().log(Level.SEVERE, "Error while trying to find a location!", ex);
}
searcher.getTargets().forEach(e -> {
if (e != sender) {
sendMessage(e, "error.location");
}
});
return true;
});
return searcher;
}
/**
* Run a preset
* @param sender The sender that executed the preset
* @param preset The preset ID to run
* @param target The player targeted by the teleporter
* @param center The center for the search
* @return The RandomSearcher instance that is searching
*/
public RandomSearcher runPreset(CommandSender sender, String preset, Player target, Location center) {
String cmd = getConfig().getString("presets." + preset) + " -p " + target.getName();
if (!cmd.contains("-id")) {
cmd += " -id " + preset;
}
if (cmd.startsWith("/")) {
cmd = cmd.substring(1);
}
if (cmd.startsWith("rtp ")) {
cmd = cmd.substring(4);
}
return parseAndRun(sender, center, cmd.split(" "));
}
@Override
public CompletableFuture<Location> getRandomLocation(Player player, Location origin, int minRange, int maxRange, LocationValidator... validators) {
return getRandomSearcher(player, origin, minRange, maxRange, validators).search();
}
@Override
public CompletableFuture<Boolean> teleportToRandomLocation(Player player, Location origin, int minRange, int maxRange, LocationValidator... validators) {
return getRandomLocation(player, origin, minRange, maxRange, validators).thenApply(player::teleport);
}
@Override
public RandomSearcher getRandomSearcher(Player player, Location origin, int minRange, int maxRange, LocationValidator... validators) {
return new RandomSearcher(this, player, origin, minRange, maxRange, validators);
}
/**
* Utility method to get the min height of a world as old versions didn't have support for this.
* @param world The world
* @return The min height or 0 if querying that isn't supported
*/
public int getMinHeight(World world) {
if (hasMinHeight) {
try {
return world.getMinHeight();
} catch (NoSuchMethodError ignored) {
// getMinHeight is only available starting in 1.16.5
}
hasMinHeight = false;
}
return 0;
}
}

View File

@ -0,0 +1,132 @@
package de.themoep.randomteleport;
/*
* RandomTeleport - randomteleport-plugin - $project.description
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import de.themoep.randomteleport.searcher.RandomSearcher;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import java.util.logging.Level;
public class RandomTeleportCommand implements CommandExecutor {
private final RandomTeleport plugin;
public RandomTeleportCommand(RandomTeleport plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args.length == 0) {
if (sender instanceof Player) {
Player player = (Player) sender;
String preset = "default";
if (plugin.getConfig().getBoolean("use-player-world-as-preset", false)) {
String worldName = player.getWorld().getName().toLowerCase();
if (presetExistsInConfig(worldName))
preset = worldName;
}
runPreset(preset, sender, player, player.getLocation());
return true;
}
} else if (args.length == 1) {
if ("--reload".equalsIgnoreCase(args[0]) && sender.hasPermission("randomteleport.reload")) {
plugin.loadConfig();
plugin.sendMessage(sender, "reloaded");
return true;
} else if ("--stat".equalsIgnoreCase(args[0]) && sender.hasPermission("randomteleport.stat")) {
//TODO: teleporter and searcher statistics
} else if (sender instanceof Player) {
runPreset(args[0].toLowerCase(), sender, (Player) sender, ((Player) sender).getLocation());
return true;
}
} else {
try {
if (sender.hasPermission("randomteleport.manual")) {
plugin.parseAndRun(sender, getLocation(sender), args);
return true;
} else {
plugin.sendMessage(sender, "error.no-permission.general", "perm", "randomteleport.manual");
return true;
}
} catch (IllegalArgumentException e) {
if (args.length == 2) {
Player target = plugin.getServer().getPlayer(args[1]);
if (target == null) {
plugin.sendMessage(sender, "error.player-not-found", "what", args[1]);
return true;
}
String[] presets = args[0].split(",");
runPreset(presets[RandomTeleport.RANDOM.nextInt(presets.length)].toLowerCase(), sender, target, target.getLocation());
return true;
}
sender.sendMessage(e.getMessage());
}
}
return false;
}
private void runPreset(String preset, CommandSender sender, Player target, Location center) {
if (!sender.hasPermission("randomteleport.presets." + preset)) {
plugin.sendMessage(sender, "error.no-permission.preset",
"preset", preset, "perm",
"randomteleport.presets." + preset
);
} else if (sender != target && !sender.hasPermission("randomteleport.tpothers")) {
plugin.sendMessage(sender, "error.no-permission.tp-others", "perm", "randomteleport.tpothers");
} else if (!presetExistsInConfig(preset)) {
plugin.sendMessage(sender, "error.preset-doesnt-exist", "preset", preset);
} else {
if (sender == target) {
for (RandomSearcher searcher : plugin.getRunningSearchers().values()) {
if (searcher.getTargets().contains(target)) {
plugin.sendMessage(sender, "error.already-searching", "preset", preset);
return;
}
}
}
try {
plugin.runPreset(plugin.getServer().getConsoleSender(), preset, target, center);
} catch (IllegalArgumentException e) {
plugin.sendMessage(sender, "error.preset-invalid", "preset", preset);
plugin.getLogger().log(Level.SEVERE, "Error while parsing preset " + preset, e);
}
}
}
private boolean presetExistsInConfig(String preset) {
return plugin.getConfig().getString("presets." + preset) != null;
}
private static Location getLocation(CommandSender sender) {
if (sender instanceof Entity) {
return ((Entity) sender).getLocation();
} else if (sender instanceof BlockCommandSender) {
return ((BlockCommandSender) sender).getBlock().getLocation();
}
return new Location(Bukkit.getWorlds().get(0), 0, 0, 0);
}
}

View File

@ -0,0 +1,78 @@
package de.themoep.randomteleport;
/*
* RandomTeleport
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import de.themoep.randomteleport.searcher.validators.LocationValidator;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
public class ValidatorRegistry {
private Map<String, LocationValidator> validators = new LinkedHashMap<>();
/**
* Get the map of currently set location validators
* @return The map of validators
*/
public Map<String, LocationValidator> getRaw() {
return validators;
}
public Collection<LocationValidator> getAll() {
return validators.values();
}
/**
* Add a location validator that is provided in this plugin
* @param validator The validator to add
* @return The previously registered validator of the same type and name or null if none was registered
*/
public LocationValidator add(LocationValidator validator) {
return validators.put(validator.getType().toLowerCase(), validator);
}
/**
* Remove a location validator that is provided in this plugin
* @param validator The validator to remove
* @return The removed registered validator with the same type or null if it wasn't registered
*/
public LocationValidator remove(LocationValidator validator) {
return remove(validator.getType());
}
/**
* Remove a location validator that is provided in this plugin
* @param type The type of the validator to remove
* @return The removed registered validator with the same type or null if it wasn't registered
*/
public LocationValidator remove(String type) {
return validators.remove(type.toLowerCase());
}
/**
* Get a location validator that is provided in this plugin
* @param type The type of the validator to get
* @return The registered validator with the provided type or null if none was registered
*/
public LocationValidator get(String type) {
return validators.get(type.toLowerCase());
}
}

View File

@ -0,0 +1,65 @@
package de.themoep.randomteleport.api;
/*
* RandomTeleport - randomteleport-plugin - $project.description
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import de.themoep.randomteleport.searcher.RandomSearcher;
import de.themoep.randomteleport.searcher.validators.LocationValidator;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import org.bukkit.Location;
import org.bukkit.entity.Player;
public interface RandomTeleportAPI {
/**
* Returns a random Location
*
* @param player the Player initiating the search
* @param center the location where the search should begin
* @param minRange the minimum distance a found location has to the center location
* @param maxRange the maximum distance a found location has to the center location
* @param validators additional LocationValidators to customize validity check of a location
* @return a random CompletableFuture<Location>
*/
CompletableFuture<Location> getRandomLocation(Player player, Location center, int minRange, int maxRange, LocationValidator... validators);
/**
* Teleports the passed Player to a random Location
*
* @param player the Player initiating the search
* @param center the location where the search should begin
* @param minRange the minimum distance a found location has to the center location
* @param maxRange the maximum distance a found location has to the center location
* @param validators additional LocationValidators to customize validity check of a location
* @return a CompletableFuture<Boolean> true if teleport was successful else false
*/
CompletableFuture<Boolean> teleportToRandomLocation(Player player, Location center, int minRange, int maxRange, LocationValidator... validators);
/**
* Creates a RandomSearcher instance with the passed parameters
*
* @param player the Player initiating the search
* @param center the location where the search should begin
* @param minRange the minimum distance a found location has to the center location
* @param maxRange the maximum distance a found location has to the center location
* @param validators additional LocationValidators to customize validity check of a location
* @return a randomSearcher instance
*/
RandomSearcher getRandomSearcher(Player player, Location center, int minRange, int maxRange, LocationValidator... validators);
}

View File

@ -0,0 +1,109 @@
package de.themoep.randomteleport.listeners;
/*
* RandomTeleport
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import de.themoep.randomteleport.RandomTeleport;
import de.themoep.randomteleport.searcher.RandomSearcher;
import org.bukkit.block.Sign;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import java.util.logging.Level;
public class SignListener implements Listener {
private final RandomTeleport plugin;
public SignListener(RandomTeleport plugin) {
this.plugin = plugin;
}
@EventHandler(ignoreCancelled = true)
public void onSignCreate(SignChangeEvent event) {
if (plugin.matchesSignVariable(event.getLine(1))) {
if (!event.getPlayer().hasPermission("randomteleport.sign.create")) {
event.getBlock().breakNaturally();
plugin.sendMessage(event.getPlayer(), "sign.no-permission.create", "perm", "randomteleport.sign.create");
} else {
String preset = event.getLine(2);
if (preset != null) {
plugin.sendMessage(event.getPlayer(), "sign.created", "preset", preset);
if (plugin.getConfig().getString("presets." + preset.toLowerCase()) == null) {
plugin.sendMessage(event.getPlayer(), "error.preset-doesnt-exist", "preset", preset);
}
}
}
}
}
@EventHandler(ignoreCancelled = true)
public void onSignDestroy(BlockBreakEvent event) {
if (event.getBlock().getType().name().contains("SIGN")) {
Sign sign = (Sign) event.getBlock().getState();
if (plugin.matchesSignVariable(sign.getLine(1))) {
if (!event.getPlayer().hasPermission("randomteleport.sign.destroy")) {
event.setCancelled(true);
plugin.sendMessage(event.getPlayer(), "sign.no-permission.destroy", "perm", "randomteleport.sign.destroy");
} else {
plugin.sendMessage(event.getPlayer(), "sign.destroyed", "preset", sign.getLine(2));
}
}
}
}
@EventHandler(ignoreCancelled = true)
public void onSignClick(PlayerInteractEvent event) {
if (event.getHand() == EquipmentSlot.HAND && event.getAction() == Action.RIGHT_CLICK_BLOCK
&& event.getClickedBlock() != null && event.getClickedBlock().getType().name().contains("SIGN")) {
Sign sign = (Sign) event.getClickedBlock().getState();
if (plugin.matchesSignVariable(sign.getLine(1))) {
String preset = sign.getLine(2).toLowerCase();
if (event.getPlayer().hasPermission("randomteleport.sign.preset." + preset)) {
if (plugin.getConfig().getString("presets." + preset) == null) {
plugin.sendMessage(event.getPlayer(), "error.preset-doesnt-exist", "preset", preset);
} else {
for (RandomSearcher searcher : plugin.getRunningSearchers().values()) {
if (searcher.getTargets().contains(event.getPlayer())) {
plugin.sendMessage(event.getPlayer(), "error.already-searching", "preset", preset);
return;
}
}
try {
plugin.runPreset(plugin.getServer().getConsoleSender(), preset, event.getPlayer(), event.getClickedBlock().getLocation());
} catch (IllegalArgumentException e) {
plugin.sendMessage(event.getPlayer(), "error.preset-invalid", "preset", preset);
plugin.getLogger().log(Level.SEVERE, "Error while parsing preset " + preset, e);
}
}
} else {
plugin.sendMessage(event.getPlayer(), "sign.no-permission.use",
"preset", preset,
"perm", "randomteleport.sign.use"
);
}
}
}
}
}

View File

@ -0,0 +1,546 @@
package de.themoep.randomteleport.searcher;
/*
* RandomTeleport - randomteleport-plugin - $project.description
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
import de.themoep.randomteleport.RandomTeleport;
import de.themoep.randomteleport.ValidatorRegistry;
import de.themoep.randomteleport.searcher.options.NotFoundException;
import de.themoep.randomteleport.searcher.validators.LocationValidator;
import io.papermc.lib.PaperLib;
import org.apache.commons.lang.Validate;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public class RandomSearcher {
private final RandomTeleport plugin;
private final CommandSender initiator;
private final UUID uniqueId = UUID.randomUUID();
private final ValidatorRegistry validators = new ValidatorRegistry();
private static final List<int[]> RANDOM_LIST = new ArrayList<>();
static {
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
RANDOM_LIST.add(new int[]{x, z});
}
}
}
private Random random = RandomTeleport.RANDOM;
private Set<Entity> targets = Collections.newSetFromMap(new LinkedHashMap<>());
private boolean debug = false;
private String id = null;
private long seed = -1;
private Location center;
private int minRadius = 0;
private int maxRadius = Integer.MAX_VALUE;
private int checkDelay = 1;
private boolean minYWasProvided = false;
private int minY;
private boolean maxYWasProvided = false;
private int maxY;
private boolean loadedOnly = false;
private boolean generatedOnly = false;
private int maxTries = 100;
private int cooldown;
private Map<String, String> options = new LinkedHashMap<>();
private long lastCheck;
private int checks = 0;
private final Multimap<Integer, Integer> checked = MultimapBuilder.hashKeys().hashSetValues().build();
private CompletableFuture<Location> future = null;
public RandomSearcher(RandomTeleport plugin, CommandSender initiator, Location center, int minRadius, int maxRadius, LocationValidator... validators) {
this.plugin = plugin;
this.initiator = initiator;
setCenter(center);
setMinRadius(minRadius);
setMaxRadius(maxRadius);
minY = plugin.getMinHeight(center.getWorld());
if (center.getWorld().getEnvironment() == World.Environment.NETHER) {
maxY = 126;
} else {
maxY = center.getWorld().getMaxHeight();
}
this.validators.getRaw().putAll(plugin.getLocationValidators().getRaw());
Arrays.asList(validators).forEach(this.validators::add);
}
/**
* Get all entities targeted by this searcher
* @return The entitiy to target
*/
public Set<Entity> getTargets() {
return targets;
}
public ValidatorRegistry getValidators() {
return validators;
}
/**
* Get a ID unique to each searcher
* @return The searcher's version 4 UUID
*/
public UUID getUniqueId() {
return uniqueId;
}
/**
* Enable debugging messages for this searcher
* @param debug Whether to print debug messages
*/
public void setDebug(boolean debug) {
this.debug = debug;
}
/**
* Get if debugging is enabled for this searcher
* @return Whether to print debug messages
*/
public boolean isDebug() {
return debug;
}
/**
* Set the ID of this searcher used for cooldowns. Set to null to use an automatically generated one!
* @param id The ID of the searcher
*/
public void setId(String id) {
this.id = id;
}
/**
* Get the ID of the searcher used for cooldowns. If no specific one is set then one generated by the settings will be returned
* @return The ID of the searcher
*/
public String getId() {
if (id == null) {
return toString();
}
return id;
}
/**
* Set the seed that should be used when selecting locations. See {@link Random#setSeed(long)}.
* @param seed The seed.
*/
public void setSeed(long seed) {
this.seed = seed;
if (random == RandomTeleport.RANDOM) {
random = new Random(seed);
} else {
random.setSeed(seed);
}
}
/**
* Get the seed of this random searcher. Returns -1 if none was set.
* @return The seed or -1
*/
public long getSeed() {
return seed;
}
/**
* Directly set the Random instance used for selecting coordinates
* @param random The random instance
*/
public void setRandom(Random random) {
this.random = random;
}
/**
* Get the random instance that is used for finding locations
* @return The random instance; {@link RandomTeleport#RANDOM} by default
*/
public Random getRandom() {
return random;
}
/**
* Get the center for this searcher
* @return The center location
*/
public Location getCenter() {
return center;
}
/**
* Set the center of this searcher
* @param center The center location; never null
*/
public void setCenter(Location center) {
Validate.notNull(center, "Center cannot be null!");
Validate.notNull(center.getWorld(), "Center world cannot be null!");
this.center = center;
}
/**
* Get the minimum radius
* @return The minimum radius, always positive and less than the max radius!
*/
public int getMinRadius() {
return minRadius;
}
/**
* Set the minimum search radius
* @param minRadius The min radius; has to be positive and less than the max radius!
*/
public void setMinRadius(int minRadius) {
Validate.isTrue(minRadius >= 0 && minRadius < maxRadius, "Min radius has to be positive and less than the max radius!");
this.minRadius = minRadius;
}
/**
* Get the maximum radius
* @return The maximum radius, always greater than the minimum radius
*/
public int getMaxRadius() {
return maxRadius;
}
/**
* Set the maximum search radius
* @param maxRadius The max radius; has to be greater than the min radius!
*/
public void setMaxRadius(int maxRadius) {
Validate.isTrue(maxRadius > minRadius, "Max radius has to be greater than the min radius!");
this.maxRadius = maxRadius;
}
/**
* Get the delay in ticks between checking chunks when searching
* @return The delay in ticks
*/
public int getCheckDelay() {
return checkDelay;
}
/**
* Set the delay in ticks between checking chunks when searching
* @param checkDelay The delay in ticks
*/
public void setCheckDelay(int checkDelay) {
this.checkDelay = checkDelay;
}
/**
* Get the world this searcher will search in
* @return The world
*/
public World getWorld() {
return center.getWorld();
}
/**
* Set the world this searcher will search in
* @param world The world
*/
public void setWorld(World world) {
center.setWorld(world);
if (!minYWasProvided) {
minY = plugin.getMinHeight(world);
}
if (!maxYWasProvided) {
if (world.getEnvironment() == World.Environment.NETHER) {
maxY = 126;
} else {
maxY = world.getMaxHeight();
}
}
}
/**
* Get the minimum Y
* @return The minimum Y, always positive and less than the max Y!
*/
public int getMinY() {
return minY;
}
/**
* Set the minimum search Y
* @param minY The min Y; has to be positive and less than the max Y!
*/
public void setMinY(int minY) {
Validate.isTrue(minY >= plugin.getMinHeight(center.getWorld()), "Min Y has to be at least the world's minimum height!");
Validate.isTrue(minY < maxY, "Min Y has to be less than the max Y!");
this.minY = minY;
minYWasProvided = true;
}
/**
* Get the maximum Y
* @return The maximum Y, always greater than the minimum Y
*/
public int getMaxY() {
return maxY;
}
/**
* Set the maximum search Y
* @param maxY The max Y; has to be greater than the min Y!
*/
public void setMaxY(int maxY) {
Validate.isTrue(maxY <= center.getWorld().getMaxHeight() && maxY > minY, "Max Y has to be greater than the min Y and at most the world's max height!");
this.maxY = maxY;
maxYWasProvided = true;
}
/**
* By default it will search for coordinates in any chunk, even unloaded ones prompting the server to load new
* chunks which might result in some performance impact if the server doesn't support async loading. This disables
* that and only searches in already loaded chunks. (But might fail more often)
* @param loadedOnly Whether or not to search in loaded chunks only
*/
public void searchInLoadedOnly(boolean loadedOnly) {
this.loadedOnly = loadedOnly;
}
/**
* By default it will search for coordinates in any chunk, even ungenerated ones prompting the world to get
* generated at the point which might result in some performance impact. This disables that and only searches
* in already generated chunks.
* @param generatedOnly Whether or not to search in generated chunks only
*/
public void searchInGeneratedOnly(boolean generatedOnly) {
this.generatedOnly = generatedOnly;
}
public int getMaxTries() {
return maxTries;
}
public void setMaxTries(int maxTries) {
this.maxTries = maxTries;
}
/**
* Set the cooldown that a player has to wait before using a searcher with similar settings again
* @param cooldown The cooldown in seconds
*/
public void setCooldown(int cooldown) {
Validate.isTrue(cooldown >= 0, "Cooldown can't be negative!");
this.cooldown = cooldown;
}
/**
* Get the cooldown that a player has to wait before using a searcher with similar settings again
* @return The cooldown in seconds
*/
public int getCooldown() {
return cooldown;
}
/**
* Get additional options
* @return A map of additional options
*/
public Map<String, String> getOptions() {
return options;
}
/**
* Search for a valid location
* @return A CompletableFuture for when the search task is complete
* @throws IllegalStateException when the searcher is already running
*/
public CompletableFuture<Location> search() {
if (plugin.getRunningSearchers().containsKey(uniqueId)) {
throw new IllegalStateException("Searcher " + uniqueId + " is already running!");
}
plugin.getRunningSearchers().put(uniqueId, this);
if (targets.isEmpty() && initiator instanceof Entity) {
targets.add((Entity) initiator);
}
future = new CompletableFuture<>();
checks = 0;
checked.clear();
if (debug) {
plugin.getLogger().info("[DEBUG] " + uniqueId + " " + this + " started searching...");
}
plugin.getServer().getScheduler().runTask(plugin, () -> checkRandom(future));
future.whenComplete((l, e) -> plugin.getRunningSearchers().remove(uniqueId));
return future;
}
private void checkRandom(CompletableFuture<Location> future) {
if (checks >= maxTries) {
future.completeExceptionally(new NotFoundException("location"));
return;
}
if (future.isCancelled() || future.isDone() || future.isCompletedExceptionally()) {
return;
}
lastCheck = center.getWorld().getTime();
Location randomLoc = center.clone();
randomLoc.setY(plugin.getMinHeight(center.getWorld()));
int minChunk = minRadius >> 4;
int maxChunk = maxRadius >> 4;
int randChunkX;
int randChunkZ;
Chunk[] loadedChunks = new Chunk[0];
if (loadedOnly) {
loadedChunks = randomLoc.getWorld().getLoadedChunks();
if (loadedChunks.length == 0) {
future.completeExceptionally(new NotFoundException("loaded chunk"));
return;
}
}
do {
checks++;
if (checks >= maxTries) {
future.completeExceptionally(new NotFoundException("location"));
return;
}
if (loadedOnly) {
Chunk chunk = loadedChunks[random.nextInt(loadedChunks.length)];
randChunkX = chunk.getX();
randChunkZ = chunk.getZ();
} else {
randChunkX = (random.nextBoolean() ? 1 : -1) * random.nextInt(maxChunk + 1);
randChunkZ = (random.nextBoolean() ? 1 : -1) * random.nextInt(maxChunk + 1);
}
} while (!checked.put(randChunkX, randChunkZ)
|| !inRadius(Math.abs(randChunkX), Math.abs(randChunkZ), minChunk, maxChunk)
|| (generatedOnly && !PaperLib.isChunkGenerated(randomLoc.getWorld(), randChunkX, randChunkZ)));
randomLoc.setX(((center.getBlockX() >> 4) + randChunkX) * 16);
randomLoc.setZ(((center.getBlockZ() >> 4) + randChunkZ) * 16);
PaperLib.getChunkAtAsync(randomLoc).thenApply(c -> {
checks++;
if (c == null) {
// Chunk not generated, test another one
checkRandom(future);
return false;
}
c.addPluginChunkTicket(plugin);
try {
int indexOffset = random.nextInt(RANDOM_LIST.size());
Location foundLoc = null;
for (int i = 0; i < RANDOM_LIST.size(); i++) {
int index = (i + indexOffset) % RANDOM_LIST.size();
boolean validated = true;
Location loc = randomLoc.clone().add(RANDOM_LIST.get(index)[0], 0, RANDOM_LIST.get(index)[1]);
if (!inRadius(loc)) {
continue;
}
for (LocationValidator validator : getValidators().getAll()) {
if (!validator.validate(this, loc)) {
validated = false;
break;
}
}
if (validated) {
foundLoc = loc;
break;
}
}
if (foundLoc != null) {
// all checks are for the top block, put we want a location above that so add 1 to y
future.complete(foundLoc.add(0, 1, 0));
return true;
}
long diff = center.getWorld().getTime() - lastCheck;
if (diff < checkDelay) {
plugin.getServer().getScheduler().runTaskLater(plugin, () -> checkRandom(future), checkDelay - diff);
} else {
checkRandom(future);
}
return false;
} finally {
c.removePluginChunkTicket(plugin);
}
}).exceptionally(future::completeExceptionally);
}
private boolean inRadius(Location location) {
int diffX = Math.abs(location.getBlockX() - center.getBlockX());
int diffZ = Math.abs(location.getBlockZ() - center.getBlockZ());
return inRadius(diffX, diffZ, minRadius, maxRadius);
}
private boolean inRadius(int diffX, int diffZ, int minRadius, int maxRadius) {
return diffX >= minRadius && diffX <= maxRadius && diffZ <= maxRadius
|| diffZ >= minRadius && diffZ <= maxRadius && diffX <= maxRadius;
}
public RandomTeleport getPlugin() {
return plugin;
}
/**
* The sender who initiated this search
* @return The initiator
*/
public CommandSender getInitiator() {
return initiator;
}
/**
* Get the currently running search future
* @return The currently running search future or null if none is running
*/
public CompletableFuture<Location> getFuture() {
return future;
}
@Override
public String toString() {
return "RandomSearcher{" +
"id='" + id + '\'' +
", seed=" + seed +
", center=" + center +
", minRadius=" + minRadius +
", maxRadius=" + maxRadius +
", loadedOnly=" + loadedOnly +
", generatedOnly=" + generatedOnly +
", maxTries=" + maxTries +
", cooldown=" + cooldown +
'}';
}
}

View File

@ -0,0 +1,28 @@
package de.themoep.randomteleport.searcher.options;
/*
* RandomTeleport
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
public class AdditionalOptionParser extends SimpleOptionParser {
public AdditionalOptionParser(String... optionAliases) {
super(optionAliases, ((searcher, args) -> {
searcher.getOptions().put(optionAliases[0], args.length > 0 ? String.join(" ", args) : "true");
return true;
}));
}
}

View File

@ -0,0 +1,38 @@
package de.themoep.randomteleport.searcher.options;
/*
* RandomTeleport - randomteleport-plugin - $project.description
* Copyright (c) 2022 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import de.themoep.randomteleport.searcher.RandomSearcher;
import java.util.function.Consumer;
public class BooleanOptionParser extends SimpleOptionParser {
public BooleanOptionParser(String optionAlias, Consumer<RandomSearcher> consumer) {
this(new String[]{optionAlias}, consumer);
}
public BooleanOptionParser(String[] optionAliases, Consumer<RandomSearcher> consumer) {
super(optionAliases, 0, ((searcher, args) -> {
consumer.accept(searcher);
return true;
}));
}
}

View File

@ -0,0 +1,32 @@
package de.themoep.randomteleport.searcher.options;
/*
* RandomTeleport - randomteleport-plugin - $project.description
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
public class NotFoundException extends IllegalArgumentException {
private final String what;
public NotFoundException(String what) {
super(what + " was not found!");
this.what = what;
}
public String getWhat() {
return what;
}
}

View File

@ -0,0 +1,27 @@
package de.themoep.randomteleport.searcher.options;
/*
* RandomTeleport
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import de.themoep.randomteleport.searcher.RandomSearcher;
public interface OptionParser {
boolean parse(RandomSearcher searcher, String[] args);
}

View File

@ -0,0 +1,28 @@
package de.themoep.randomteleport.searcher.options;
/*
* RandomTeleport
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
public class PlayerNotFoundException extends NotFoundException {
public PlayerNotFoundException(String name) {
super(name);
}
}

View File

@ -0,0 +1,97 @@
package de.themoep.randomteleport.searcher.options;
/*
* RandomTeleport - randomteleport-plugin - $project.description
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import de.themoep.randomteleport.searcher.RandomSearcher;
import org.apache.commons.lang.Validate;
import org.bukkit.command.CommandSender;
import java.util.Arrays;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
public class SimpleOptionParser implements OptionParser {
private Set<String> aliases;
private final int argsLength;
private final BiFunction<RandomSearcher, String[], Boolean> parser;
public SimpleOptionParser(String option, BiFunction<RandomSearcher, String[], Boolean> parser) {
this(new String[]{option}, parser);
}
public SimpleOptionParser(String[] optionAliases, BiFunction<RandomSearcher, String[], Boolean> parser) {
this(optionAliases, -1, parser);
}
public SimpleOptionParser(String[] optionAliases, int argsLength, BiFunction<RandomSearcher, String[], Boolean> parser) {
Validate.notEmpty(optionAliases);
this.aliases = Arrays.stream(optionAliases).map(String::toLowerCase).collect(Collectors.toSet());
this.argsLength = argsLength;
this.parser = parser;
}
@Override
public boolean parse(RandomSearcher searcher, String[] args) {
for (int i = 0; i < args.length; i++) {
if (args[i].startsWith("-")) {
String option = args[i].toLowerCase().substring(1);
if (option.startsWith("-")) {
option = args[i].substring(1);
}
if (aliases.contains(option)) {
if (!hasAccess(searcher.getInitiator())) {
throw new IllegalArgumentException(searcher.getPlugin().getTextMessage(
searcher.getInitiator(), "error.no-permission.option",
"option", option,
"perm", "randomteleport.manual.option." + aliases.iterator().next()));
}
i++;
int argLength = argsLength > 0 ? argsLength : 0;
for (int j = i + argLength; j < args.length; j++) {
if (!args[j].startsWith("-")) {
argLength++;
} else {
break;
}
}
if (i + argLength <= args.length) {
return parser.apply(searcher, Arrays.copyOfRange(args, i, i + argLength));
}
break;
}
}
}
return false;
}
private boolean hasAccess(CommandSender initiator) {
for (String alias : aliases) {
if (initiator.hasPermission("randomteleport.manual.option." + alias)) {
return true;
}
}
return false;
}
public Set<String> getAliases() {
return aliases;
}
}

View File

@ -0,0 +1,28 @@
package de.themoep.randomteleport.searcher.options;
/*
* RandomTeleport
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
public class WorldNotFoundException extends NotFoundException {
public WorldNotFoundException(String name) {
super(name);
}
}

View File

@ -0,0 +1,50 @@
package de.themoep.randomteleport.searcher.validators;
/*
* RandomTeleport - randomteleport-plugin - $project.description
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import de.themoep.randomteleport.searcher.RandomSearcher;
import org.bukkit.Location;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
public class BiomeValidator extends LocationValidator {
private final boolean whitelist;
private final Set<Biome> biomes = EnumSet.noneOf(Biome.class);
public BiomeValidator(Biome... biomes) {
this(true, biomes);
}
public BiomeValidator(boolean whitelist, Biome... biomes) {
super("biome");
this.whitelist = whitelist;
Collections.addAll(this.biomes, biomes);
}
@Override
public boolean validate(RandomSearcher searcher, Location location) {
Block block = location.getBlock();
return block != null && biomes.contains(block.getBiome()) == whitelist;
}
}

View File

@ -0,0 +1,50 @@
package de.themoep.randomteleport.searcher.validators;
/*
* RandomTeleport - randomteleport-plugin - $project.description
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import de.themoep.randomteleport.searcher.RandomSearcher;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
public class BlockValidator extends LocationValidator {
private final boolean whitelist;
private final Set<Material> materials = EnumSet.noneOf(Material.class);
public BlockValidator(Material... materials) {
this(true, materials);
}
public BlockValidator(boolean whitelist, Material... materials) {
super("block");
this.whitelist = whitelist;
Collections.addAll(this.materials, materials);
}
@Override
public boolean validate(RandomSearcher searcher, Location location) {
Block block = location.getBlock();
return block != null && materials.contains(block.getType()) == whitelist;
}
}

View File

@ -0,0 +1,63 @@
package de.themoep.randomteleport.searcher.validators;
/*
* RandomTeleport - randomteleport-plugin - $project.description
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import de.themoep.randomteleport.searcher.RandomSearcher;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import java.util.Collections;
import java.util.EnumSet;
public class HeightValidator extends LocationValidator {
private final EnumSet<Material> unsafeBlocks;
public HeightValidator(Material[] unsafeBlocks) {
super("height");
this.unsafeBlocks = EnumSet.noneOf(Material.class);
Collections.addAll(this.unsafeBlocks, unsafeBlocks);
}
@Override
public boolean validate(RandomSearcher searcher, Location location) {
Block block = location.getWorld().getHighestBlockAt(location);
if (block.getY() > searcher.getMaxY()) {
block = location.getWorld().getBlockAt(
block.getX(),
searcher.getMinY() + searcher.getRandom().nextInt(searcher.getMaxY() - searcher.getMinY()),
block.getZ()
);
}
while (block.isEmpty()) {
block = block.getRelative(BlockFace.DOWN);
if (block == null || block.getY() < searcher.getMinY()) {
return false;
}
}
location.setY(block.getY());
return isSafe(block.getRelative(BlockFace.UP)) && isSafe(block.getRelative(BlockFace.UP, 2));
}
private boolean isSafe(Block block) {
return block.isPassable() && !block.isLiquid() && !unsafeBlocks.contains(block.getType());
}
}

View File

@ -0,0 +1,43 @@
package de.themoep.randomteleport.searcher.validators;
/*
* RandomTeleport - randomteleport-plugin - $project.description
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import de.themoep.randomteleport.searcher.RandomSearcher;
import org.bukkit.Location;
public abstract class LocationValidator {
private String type;
public LocationValidator(String type) {
this.type = type;
}
public String getType() {
return type;
}
/**
* Validate a location
* @param searcher The searcher attempting to use this validator
* @param location The location to validate
* @return True if it's valid; false if not
*/
public abstract boolean validate(RandomSearcher searcher, Location location);
}

View File

@ -0,0 +1,44 @@
package de.themoep.randomteleport.searcher.validators;
/*
* RandomTeleport
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import de.themoep.randomteleport.searcher.RandomSearcher;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
public class ProtectionValidator extends LocationValidator {
public ProtectionValidator() {
super("protection");
}
@Override
public boolean validate(RandomSearcher searcher, Location location) {
if (searcher.getTargets().isEmpty()) {
return true;
}
for (Entity entity : searcher.getTargets()) {
if (entity instanceof Player && !searcher.getPlugin().getHookManager().canBuild((Player) entity, location)) {
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,34 @@
package de.themoep.randomteleport.searcher.validators;
/*
* RandomTeleport - randomteleport-plugin - $project.description
* Copyright (c) 2019 Max Lee aka Phoenix616 (mail@moep.tv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import de.themoep.randomteleport.searcher.RandomSearcher;
import org.bukkit.Location;
public class WorldborderValidator extends LocationValidator {
public WorldborderValidator() {
super("worldborder");
}
@Override
public boolean validate(RandomSearcher searcher, Location location) {
return searcher.getPlugin().getHookManager().isInsideBorder(location);
}
}

View File

@ -0,0 +1,114 @@
# Default language to use when client's language isn't available
lang: en
# Some debug information
debug: true
# Delay in ticks between checking chunks when searching
# Should we search for a preset named like the world the player is in when using /rtp without parameters?
use-player-world-as-preset: false
# Blocks to teleport on in normal mode
safe-blocks:
- sand
- sandstone
- gravel
- dirt
- grass_block
- coarse_dirt
- podzol
- stone
- granite
- diorite
- andesite
- cobblestone
- end_stone
- netherrack
# Blocks not to teleport on or into
unsafe-blocks:
- water
- lava
- oak_sapling
- spruce_sapling
- birch_sapling
- jungle_sapling
- acacia_sapling
- dark_oak_sapling
- white_bed
- orange_bed
- magenta_bed
- light_blue_bed
- yellow_bed
- lime_bed
- pink_bed
- gray_bed
- light_gray_bed
- cyan_bed
- purple_bed
- blue_bed
- brown_bed
- green_bed
- red_bed
- black_bed
- powered_rail
- detector_rail
- cobweb
- piston_head
- tnt
- torch
- fire
- sign
- ladder
- rail
- wall_sign
- lever
- stone_pressure_plate
- iron_door
- redstone_wall_torch
- redstone_torch
- stone_button
- cactus
- magma_block
- nether_portal
- vine
- end_portal
- end_portal_frame
- tripwire_hook
- tripwire
- flower_pot
- oak_leaves
- spruce_leaves
- birch_leaves
- jungle_leaves
- acacia_leaves
- dark_oak_leaves
- barrier
- iron_trapdoor
- oak_trapdoor
- spruce_trapdoor
- birch_trapdoor
- jungle_trapdoor
- acacia_trapdoor
- dark_oak_trapdoor
- oak_door
- spruce_door
- birch_door
- jungle_door
- acacia_door
- dark_oak_door
- end_rod
- end_gateway
- powder_snow
sign-variables:
- "[RTP]"
- "[RandomTP]"
# Just write your command arguments as you would use it ingame behind /rtp
# Don't use the -p parameter, this will get added automatically with the senders name/the specified playername
presets:
# Triggered when you use /rtp without any additional paramters
default: "100 1000"
# add more to use /rtp <rtpname>, player needs "randomteleport.presets.<rtpname>"
# <rtpname>: "/rtp 1 2"
test: "10 200 -f"

View File

@ -0,0 +1,27 @@
reloaded: "&eReloaded the config. Some settings might require a server restart!"
search: "&7RandomTeleport searches for a safe place in world {worldname}. . ."
teleport: "&7RandomTeleport teleported you to X: {x} Y: {y} Z: {z}!"
setspawnpoint: "&7Your Respawnpoint has been set to your current location!"
sign:
created: "&aRandomTeleport preset sign &e{preset}&a created!"
destroyed: "&aRandomTeleport preset sign &e{preset}&a destroyed!"
no-permission:
destroy: "&cYou don't have permission to destroy RandomTeleport preset signs! &o({perm})"
create: "&cYou don't have permission to create RandomTeleport preset signs! &o({perm})"
use: "&cYou don't have permission to use the preset &6{preset}&c! &o({perm})"
error:
location: "&4Error: &cRandomTeleport could not find a safe location!"
teleport: "&4Error: &cRandomTeleport could not teleport you to X: {x} Y: {y} Z: {z}!"
cooldown: "&cYou have to wait {cooldown_text}s before using this RandomTeleport again!"
parse-error: "&cError while parsing option &f{option}&c with value &f{value}&c: {error}"
not-found: "&cCould not find &f{what}&c!"
player-not-found: "&cCould not find a player with the name &f{what}&c!"
world-not-found: "&cCould not find a world with the name &f{what}&c!"
preset-doesnt-exist: "&cThe RandomTeleport preset &6{preset}&c does not exist!"
preset-invalid: "&cThe preset &6{preset}&c is not setup correctly! Please contact an admin."
already-searching: "&cA search is already in progress&c!"
no-permission:
general: "&cYou don't have permission to do that! &o({perm})"
option: "&cYou don't have permission to use the option {option}! &o({perm})"
preset: "&cYou don't have permission to use the preset &6{preset}&c! &o({perm})"
tp-others: "&cYou don't have permission to teleport other players! &o({perm})"

View File

@ -0,0 +1,78 @@
name: RandomTeleport
provides: [FUBSRandomTeleport]
main: de.themoep.randomteleport.RandomTeleport
version: '${minecraft.plugin.version}'
api-version: 1.13
description: ${project.description}
author: Phoenix616
website: https://github.com/Phoenix616/RandomTeleport/
softdepend: [WorldGuard, Factions, GriefPrevention, RedProtect, WorldBorder]
commands:
randomteleport:
aliases: [randomtp, rtp]
description: RandomTeleport command.
permission: randomteleport.use
usage: |
/<command> - uses the default preset
/<command> <preset1,...> [<playername>] - uses a specific or random preset
/<command> <minRange> <maxRange> [-p, -w, -x, -z, -c, -f]
minRange - minimum distance to the center point (square shaped)
maxRange - maximum distance to the center point (square shaped)
Options:
> -p,-player <playername> - teleports other players
> -w,-world <world1,...> - teleports the player in a specific or random world
> -b,-biome <biomename> [<biome 2> ...] - only teleport to this biome (multiple allowed, Bukkit biome names!)
> -x,-xPos <x value> - x axis of the center point, if not set the player's x axis is used
> -z,-zPos <z value> - z axis of the center point, if not set the player's z axis is used
> -minY <y value> - minimum y value that the random location should have (default: 0)
> -maxY <y value> - maximum y value that the random location should have (default: world height, half in nether)
> -l,-loaded - only search loaded chunks for possible locations (might fail more often)
> -g,-generated - only search generated chunks for possible locations
> -c, -cooldown <seconds> - cooldown in seconds after which the player can use this teleporter again
> -id <id> - The ID to use for the cooldown, uses automatically generated one if not provided
> -f,-force - teleport even if there is no dirt/grass/sand/gravel, only checks for lava/water/cactus, ignores WorldGuard/Faction regions
> -f,-force [<blocks|regions>] - only ignore blocks or regions
> -t,-tries <amount> - the amount of times the plugin should try to find a random location before giving up
> -sp,spawnpoint [force] - set the respawn point of the player to the location he teleported to (force overrides existing spawnpoint)
/<command> --stat - shows a statistic of the teleports since the last restart
/<command> --reload - reloads the config
permissions:
randomteleport.use:
description: Gives permission to the command
default: op
randomteleport.manual:
description: Gives permission to manually specify parameters in the command
default: op
randomteleport.manual.option.*:
description: Gives permission to use certain options in the command
default: op
randomteleport.tpothers:
description: Gives permission to teleport other players
default: op
randomteleport.cooldownexempt:
description: Teleportcooldown does not effect these players
default: op
randomteleport.stat:
description: Permission for showing the teleport statistic
default: op
randomteleport.reload:
description: Permission to use the reload command
default: op
randomteleport.presets.default:
description: Gives permission to use the default random teleport preset
default: op
randomteleport.presets.*:
description: Gives permission to use all random teleport presets
default: op
randomteleport.sign.preset.default:
description: Gives permission to use the default preset with a rightclick on a preset sign
default: op
randomteleport.sign.preset.*:
description: Gives permission to use all presets with a rightclick on a preset sign
default: op
randomteleport.sign.create:
description: Allows creating preset signs ([rtp] or [RandomTP] on the 2nd line and the preset name on the 3rd)
default: op
randomteleport.sign.destroy:
description: Allows destroying preset signs ([rtp] or [RandomTP] on the 2nd line and the preset name on the 3rd)
default: op