Compare commits

...

27 Commits

Author SHA1 Message Date
Phoenix616 8bebacc7ba
Fix possible NPEs when no ChunkyBorder border is set in a world (Fixes #56) 2023-04-09 13:45:53 +01:00
Phoenix616 34fc5c3439
Add ability to select random preset 2023-03-16 16:48:59 +01:00
Phoenix616 f934071367
Add ability to select random world in -world parameter 2023-03-16 16:36:49 +01:00
Phoenix616 11cbc0abb8
Make sure the found chunk stays loaded
This is done by adding a plugin chunk ticket and removing it once our logic is done
2023-02-04 14:19:15 +01:00
Phoenix616 548d873790
Update to latest releases of Chunky(Border) (fixes #55) 2023-01-16 17:06:16 +01:00
Phoenix616 29f709a73e
Remove `air` from `unsafe-blocks`.
That causes issues in force blocks mode and is checked internally already.
2022-12-10 15:28:06 +01:00
Phoenix616 8b282d5e76
Re-add debug option and fix min/max y when using world specifier 2022-11-23 00:20:20 +01:00
Phoenix616 ebeb3451af
Use SSL for all maven repos 2022-11-03 23:37:10 +01:00
RedstoneFuture b1b13236f5
Removing hardcoded "s" from cooldown placeholder (#54) 2022-10-12 17:00:47 +01:00
johnfriedrich e5c745e018 Dont shade GD API 2022-05-28 22:50:24 +01:00
johnfriedrich 18ad2b50c0 Use player world as preset when using rtp without parameters 2022-05-28 22:50:24 +01:00
Phoenix616 b8d686d9d3
Re-add backwards support down to 1.13
Also update PaperLib dependency and repo
2022-05-22 12:42:51 +01:00
John c30af21608
Use recent GD API (#51) 2022-05-22 12:29:25 +01:00
Omer Oreg 61c32c5995
Implements Hooks for GriefDefender & ChunkyBorder. (#49)
* Added griefdefender support

* Added info command

* Fixed info command not executing

oops

* Implemented hook for chunkyborder

* Removed --info command

You can get this info in the logs.

* Update plugin.yml

* Added missing GriefDefender hook artifact
2022-05-22 00:23:34 +01:00
Phoenix616 4a77bf1519
Use configured unsafe blocks in height validator 2022-03-08 14:41:16 +01:00
Phoenix616 3ecf194913
Fix NPE when no border is set in WorldBorder 2022-01-14 16:21:42 +01:00
Phoenix616 6098947fbb
Fix issues with world heights (Resolves #50)
This adds support for new 1.17 min world heights as well as move the default nether max y one down.
2022-01-05 01:12:30 +01:00
Phoenix616 8e0643e59c
Check for passable and liquids instead of just solids (Fixes #44) 2021-03-09 14:28:25 +01:00
Phoenix616 9dfc62f9f5
Fix safe vs. save error 2021-02-16 19:50:17 +01:00
Phoenix616 c893b45ddc
Rename maven project and add provides to differentiate from others 2021-02-01 14:24:47 +01:00
Max Lee 6b632d7023
Merge pull request #42 from MWHunter/master
Fix WorldBorder checking for non-circle borders
2020-12-20 23:04:17 +01:00
MWHunter 35a010c41e Use worldborder API instead of an incorrect calculation 2020-12-20 15:48:04 -06:00
Phoenix616 53fece8dac
Add missing softdepend declaration 2020-12-18 01:48:30 +01:00
Phoenix616 dea38a1579
Fix placeholder replacements not working 2020-09-16 00:28:43 +01:00
Phoenix616 73a49f779b
Only apply cooldown if teleport was successful 2020-09-16 00:24:11 +01:00
Phoenix616 a8db0033df
Add MineDown support (and with that RGB colors) 2020-09-03 17:23:23 +01:00
Phoenix616 fc40436422
[CI-SKIP] Add issue templates 2020-08-24 16:59:42 +01:00
25 changed files with 554 additions and 100 deletions

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. -->

View File

@ -16,7 +16,7 @@ Permission: `randomteleport.use`
Usage | Description
--------------------------------------------|-------------------------------
`/rtp` | uses the default preset
`/rtp <preset> [<playername>]` | uses a specific 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
@ -24,7 +24,7 @@ Usage | Description
Option | Description
--------------------------------|-------------------------------------------
`-p,-player <playername>` | teleports other players
`-w,-world <worldname>` | teleports the player in a specific world
`-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
@ -39,6 +39,7 @@ Option | Description
`-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

18
pom.xml
View File

@ -8,7 +8,7 @@
<artifactId>randomteleport-parent</artifactId>
<version>2.0-SNAPSHOT</version>
<description>Randomly teleport players on your server!</description>
<name>RandomTeleport</name>
<name>FUBSRandomTeleport</name>
<packaging>pom</packaging>
<properties>
@ -40,7 +40,7 @@
</repository>
<repository>
<id>paper-repo</id>
<url>https://papermc.io/repo/content/groups/public</url>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<repository>
<id>minebench-repo</id>
@ -50,15 +50,21 @@
<dependencies>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.13.2-R0.1-SNAPSHOT</version>
<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.2</version>
<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>

View File

@ -42,14 +42,5 @@ public interface WorldborderHook extends PluginHook {
* @param location The location to check
* @return True if it is inside (or there is no border), false if not
*/
default boolean isInsideBorder(Location location) {
Location center = getCenter(location.getWorld());
if (center != null) {
double radius = getBorderRadius(location.getWorld());
if (radius > 0) {
return center.distanceSquared(location) <= radius * radius;
}
}
return true;
}
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

@ -15,7 +15,7 @@
<repositories>
<repository>
<id>factions-repo</id>
<url>http://ci.ender.zone/plugin/repository/everything/</url>
<url>https://ci.ender.zone/plugin/repository/everything/</url>
</repository>
</repositories>

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

@ -18,10 +18,12 @@
<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>

View File

@ -44,6 +44,12 @@ public class WorldBorderHook implements WorldborderHook {
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;

View File

@ -15,7 +15,7 @@
<repositories>
<repository>
<id>sk89q-repo</id>
<url>http://maven.sk89q.com/repo/</url>
<url>https://maven.sk89q.com/repo/</url>
</repository>
</repositories>

View File

@ -15,7 +15,7 @@
<repositories>
<repository>
<id>sk89q-repo</id>
<url>http://maven.sk89q.com/repo/</url>
<url>https://maven.sk89q.com/repo/</url>
</repository>
</repositories>

View File

@ -42,6 +42,18 @@
<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>
@ -65,6 +77,10 @@
<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>

View File

@ -20,16 +20,12 @@ package de.themoep.randomteleport;
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.AdditionalOptionParser;
import de.themoep.randomteleport.searcher.options.NotFoundException;
import de.themoep.randomteleport.searcher.options.OptionParser;
import de.themoep.randomteleport.searcher.options.PlayerNotFoundException;
import de.themoep.randomteleport.searcher.options.SimpleOptionParser;
import de.themoep.randomteleport.searcher.options.WorldNotFoundException;
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;
@ -38,6 +34,8 @@ 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;
@ -76,10 +74,12 @@ public class RandomTeleport extends JavaPlugin implements RandomTeleportAPI {
private ValidatorRegistry locationValidators = new ValidatorRegistry();
private List<OptionParser> optionParsers = new ArrayList<>();
private Material[] saveBlocks;
private Material[] unsaveBlocks;
private Material[] safeBlocks;
private Material[] unsafeBlocks;
private Set<String> signVariables;
private boolean hasMinHeight = true;
public void onEnable() {
hookManager = new HookManager(this);
loadConfig();
@ -92,21 +92,39 @@ public class RandomTeleport extends JavaPlugin implements RandomTeleportAPI {
public void loadConfig() {
saveDefaultConfig();
reloadConfig();
saveBlocks = getConfig().getStringList("save-blocks").stream()
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 save-blocks config! No material found with name " + s);
getLogger().log(Level.WARNING, "Error in safe blocks config! No material found with name " + s);
}
return mat;
})
.filter(Objects::nonNull)
.toArray(Material[]::new);
unsaveBlocks = getConfig().getStringList("unsave-blocks").stream()
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 unsave-blocks config! No material found with name " + s);
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;
})
@ -114,11 +132,10 @@ public class RandomTeleport extends JavaPlugin implements RandomTeleportAPI {
.toArray(Material[]::new);
signVariables = getConfig().getStringList("sign-variables").stream().map(String::toLowerCase).collect(Collectors.toSet());
lang = new LanguageManager(this, getConfig().getString("lang"));
lang.setPlaceholderPrefix("{");
lang.setPlaceholderSuffix("}");
}
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<>();
@ -166,11 +183,13 @@ public class RandomTeleport extends JavaPlugin implements RandomTeleportAPI {
}));
addOptionParser(new SimpleOptionParser(array("w", "world"), (searcher, args) -> {
if (args.length > 0) {
World world = getServer().getWorld(args[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(args[0]);
throw new WorldNotFoundException(worldName);
}
searcher.getCenter().setWorld(world);
searcher.setWorld(world);
return true;
}
return false;
@ -187,13 +206,13 @@ public class RandomTeleport extends JavaPlugin implements RandomTeleportAPI {
if ("regions".equalsIgnoreCase(args[0])) {
searcher.getValidators().remove("protection");
} else if ("blocks".equalsIgnoreCase(args[0])) {
searcher.getValidators().add(new BlockValidator(false, unsaveBlocks));
searcher.getValidators().add(new BlockValidator(false, unsafeBlocks));
} else {
throw new NotFoundException(args[0]);
}
} else {
searcher.getValidators().remove("protection");
searcher.getValidators().add(new BlockValidator(false, unsaveBlocks));
searcher.getValidators().add(new BlockValidator(false, unsafeBlocks));
}
return true;
}));
@ -245,9 +264,9 @@ public class RandomTeleport extends JavaPlugin implements RandomTeleportAPI {
private void initValidators() {
locationValidators.add(new WorldborderValidator());
locationValidators.add(new HeightValidator());
locationValidators.add(new HeightValidator(unsafeBlocks));
locationValidators.add(new ProtectionValidator());
locationValidators.add(new BlockValidator(saveBlocks));
locationValidators.add(new BlockValidator(safeBlocks));
}
/**
@ -276,16 +295,28 @@ public class RandomTeleport extends JavaPlugin implements RandomTeleportAPI {
}
public boolean sendMessage(CommandSender sender, String key, String... replacements) {
String message = getMessage(sender, key, replacements);
if (message != null && !message.isEmpty()) {
sender.sendMessage(message);
BaseComponent[] message = getComponentMessage(sender, key, replacements);
if (message != null && message.length != 0) {
sender.spigot().sendMessage(message);
return true;
}
return false;
}
public String getMessage(CommandSender sender, String key, String... replacements) {
return lang.getConfig(sender).get(key, replacements);
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() {
@ -360,13 +391,12 @@ public class RandomTeleport extends JavaPlugin implements RandomTeleportAPI {
}
if (cooldown > 0 && cooldown < searcher.getCooldown()) {
sendMessage(searcher.getTargets(), "error.cooldown", "cooldown_text", (searcher.getCooldown() - cooldown) + "s");
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 -> {
cooldowns.put(searcher.getId(), e.getUniqueId(), new AbstractMap.SimpleImmutableEntry<>(System.currentTimeMillis(), searcher.getCooldown()));
if (e instanceof Player) {
Location belowLoc = targetLoc.clone().subtract(0, 1, 0);
Block belowBlock = belowLoc.getBlock();
@ -375,8 +405,13 @@ public class RandomTeleport extends JavaPlugin implements RandomTeleportAPI {
targetLoc.setX(targetLoc.getBlockX() + 0.5);
targetLoc.setY(targetLoc.getY() + 0.1);
targetLoc.setZ(targetLoc.getBlockZ() + 0.5);
PaperLib.teleportAsync(e, targetLoc).thenAccept(success -> {
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()),
@ -402,6 +437,9 @@ public class RandomTeleport extends JavaPlugin implements RandomTeleportAPI {
"z", String.valueOf(targetLoc.getBlockZ())
);
}
if (ex != null && searcher.isDebug()) {
getLogger().log(Level.SEVERE, "Error while trying to teleport to location!", ex);
}
});
});
return true;
@ -456,4 +494,21 @@ public class RandomTeleport extends JavaPlugin implements RandomTeleportAPI {
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

@ -41,7 +41,14 @@ public class RandomTeleportCommand implements CommandExecutor {
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args.length == 0) {
if (sender instanceof Player) {
runPreset("default", sender, (Player) sender, ((Player) sender).getLocation());
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) {
@ -57,7 +64,7 @@ public class RandomTeleportCommand implements CommandExecutor {
}
} else {
try {
if (sender.hasPermission("randomteleport.manual")){
if (sender.hasPermission("randomteleport.manual")) {
plugin.parseAndRun(sender, getLocation(sender), args);
return true;
} else {
@ -71,7 +78,8 @@ public class RandomTeleportCommand implements CommandExecutor {
plugin.sendMessage(sender, "error.player-not-found", "what", args[1]);
return true;
}
runPreset(args[0].toLowerCase(), sender, target, target.getLocation());
String[] presets = args[0].split(",");
runPreset(presets[RandomTeleport.RANDOM.nextInt(presets.length)].toLowerCase(), sender, target, target.getLocation());
return true;
}
sender.sendMessage(e.getMessage());
@ -88,7 +96,7 @@ public class RandomTeleportCommand implements CommandExecutor {
);
} else if (sender != target && !sender.hasPermission("randomteleport.tpothers")) {
plugin.sendMessage(sender, "error.no-permission.tp-others", "perm", "randomteleport.tpothers");
} else if (plugin.getConfig().getString("presets." + preset) == null) {
} else if (!presetExistsInConfig(preset)) {
plugin.sendMessage(sender, "error.preset-doesnt-exist", "preset", preset);
} else {
if (sender == target) {
@ -109,6 +117,10 @@ public class RandomTeleportCommand implements CommandExecutor {
}
}
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();

View File

@ -48,9 +48,9 @@ public class RandomSearcher {
private final CommandSender initiator;
private final UUID uniqueId = UUID.randomUUID();
private ValidatorRegistry validators = new ValidatorRegistry();
private final ValidatorRegistry validators = new ValidatorRegistry();
private static final List<int[]> RANDOM_LIST = new ArrayList<int[]>();
private static final List<int[]> RANDOM_LIST = new ArrayList<>();
static {
for (int x = 0; x < 16; x++) {
@ -64,13 +64,16 @@ public class RandomSearcher {
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 int minY = 0;
private boolean minYWasProvided = false;
private int minY;
private boolean maxYWasProvided = false;
private int maxY;
private boolean loadedOnly = false;
private boolean generatedOnly = false;
@ -80,7 +83,7 @@ public class RandomSearcher {
private long lastCheck;
private int checks = 0;
private Multimap<Integer, Integer> checked = MultimapBuilder.hashKeys().hashSetValues().build();
private final Multimap<Integer, Integer> checked = MultimapBuilder.hashKeys().hashSetValues().build();
private CompletableFuture<Location> future = null;
@ -90,8 +93,9 @@ public class RandomSearcher {
setCenter(center);
setMinRadius(minRadius);
setMaxRadius(maxRadius);
minY = plugin.getMinHeight(center.getWorld());
if (center.getWorld().getEnvironment() == World.Environment.NETHER) {
maxY = 127;
maxY = 126;
} else {
maxY = center.getWorld().getMaxHeight();
}
@ -119,6 +123,22 @@ public class RandomSearcher {
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
@ -243,6 +263,33 @@ public class RandomSearcher {
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!
@ -256,8 +303,10 @@ public class RandomSearcher {
* @param minY The min Y; has to be positive and less than the max Y!
*/
public void setMinY(int minY) {
Validate.isTrue(minY >= 0 && minY < maxY, "Min Y has to be positive and less than the max Y!");
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;
}
/**
@ -273,8 +322,9 @@ public class RandomSearcher {
* @param maxY The max Y; has to be greater than the min Y!
*/
public void setMaxY(int maxY) {
Validate.isTrue(maxY > minY, "Max Y has to be greater than the min Y!");
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;
}
/**
@ -346,6 +396,9 @@ public class RandomSearcher {
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;
@ -361,7 +414,7 @@ public class RandomSearcher {
}
lastCheck = center.getWorld().getTime();
Location randomLoc = center.clone();
randomLoc.setY(0);
randomLoc.setY(plugin.getMinHeight(center.getWorld()));
int minChunk = minRadius >> 4;
int maxChunk = maxRadius >> 4;
int randChunkX;
@ -402,41 +455,46 @@ public class RandomSearcher {
checkRandom(future);
return false;
}
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]);
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;
}
if (!inRadius(loc)) {
continue;
}
for (LocationValidator validator : getValidators().getAll()) {
if (!validator.validate(this, loc)) {
validated = false;
for (LocationValidator validator : getValidators().getAll()) {
if (!validator.validate(this, loc)) {
validated = false;
break;
}
}
if (validated) {
foundLoc = loc;
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;
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);
}
long diff = center.getWorld().getTime() - lastCheck;
if (diff < checkDelay) {
plugin.getServer().getScheduler().runTaskLater(plugin, () -> checkRandom(future), checkDelay - diff);
} else {
checkRandom(future);
}
return false;
}).exceptionally(future::completeExceptionally);
}

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

@ -58,7 +58,7 @@ public class SimpleOptionParser implements OptionParser {
}
if (aliases.contains(option)) {
if (!hasAccess(searcher.getInitiator())) {
throw new IllegalArgumentException(searcher.getPlugin().getMessage(
throw new IllegalArgumentException(searcher.getPlugin().getTextMessage(
searcher.getInitiator(), "error.no-permission.option",
"option", option,
"perm", "randomteleport.manual.option." + aliases.iterator().next()));

View File

@ -20,13 +20,21 @@ package de.themoep.randomteleport.searcher.validators;
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 {
public HeightValidator() {
private final EnumSet<Material> unsafeBlocks;
public HeightValidator(Material[] unsafeBlocks) {
super("height");
this.unsafeBlocks = EnumSet.noneOf(Material.class);
Collections.addAll(this.unsafeBlocks, unsafeBlocks);
}
@Override
@ -46,6 +54,10 @@ public class HeightValidator extends LocationValidator {
}
}
location.setY(block.getY());
return !block.getRelative(BlockFace.UP).getType().isSolid() && !block.getRelative(BlockFace.UP, 2).getType().isSolid();
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

@ -4,8 +4,11 @@ lang: en
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
save-blocks:
safe-blocks:
- sand
- sandstone
- gravel
@ -21,9 +24,8 @@ save-blocks:
- end_stone
- netherrack
# Blocks unsave when in "--force blocks" mode
unsave-blocks:
- air
# Blocks not to teleport on or into
unsafe-blocks:
- water
- lava
- oak_sapling
@ -96,6 +98,7 @@ unsave-blocks:
- dark_oak_door
- end_rod
- end_gateway
- powder_snow
sign-variables:
- "[RTP]"

View File

@ -12,7 +12,7 @@ sign:
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} before using this RandomTeleport again!"
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!"

View File

@ -1,10 +1,12 @@
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]
@ -12,13 +14,13 @@ commands:
permission: randomteleport.use
usage: |
/<command> - uses the default preset
/<command> <preset> [<playername>] - uses a specific 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 <worldname> - teleports the player in a specific world
> -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