Merge branch 'master' into vertical-stargates
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit

This commit is contained in:
Kristian Knarvik 2022-06-25 23:25:25 +02:00
commit fbabe7b117
41 changed files with 1193 additions and 495 deletions

19
HEADER Normal file
View File

@ -0,0 +1,19 @@
Stargate - A portal plugin for Bukkit
Copyright (C) 2011 Shaun (sturmeh)
Copyright (C) 2011 Dinnerbone
Copyright (C) 2011-2013 Steven "Drakia" Scott <Contact@TheDgtl.net>
Copyright (C) 2015-2020 Michael Smith (PseudoKnight)
Copyright (C) 2021-2022 Kristian Knarvik (EpicKnarvik97)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

View File

@ -7,7 +7,7 @@ can share a network or be split into clusters; they can be hidden on a network o
- **Vault economy support** -- can add costs for create, destroy and use. - **Vault economy support** -- can add costs for create, destroy and use.
- **Ability to create custom gate configurations**. Four different default gate configurations are available. - **Ability to create custom gate configurations**. Four different default gate configurations are available.
- **Message customization** - **Message customization**
- **Multiple built-in languages** (de, en, es, fr, hu, it, nb-no, nl, nn-no, pt-br, ru) - **Multiple built-in languages** (de, en, es, fr, hu, it, ja, nb-no, nl, nn-no, pt-br, ru, zh_cn)
- **Teleport across worlds or servers** (BungeeCord supported) - **Teleport across worlds or servers** (BungeeCord supported)
- **Vehicle teleportation** -- teleport minecarts, boats, horses, pigs and striders - **Vehicle teleportation** -- teleport minecarts, boats, horses, pigs and striders
- **Leashed teleportation** -- teleport any creature in a leash with the player - **Leashed teleportation** -- teleport any creature in a leash with the player
@ -26,6 +26,11 @@ This was originally TheDgtl's Bukkit port of the Stargate plugin for hMod by Din
of [PseudoKnight's fork](https://github.com/PseudoKnight/Stargate-Bukkit). This fork's main purpose is to create a clean of [PseudoKnight's fork](https://github.com/PseudoKnight/Stargate-Bukkit). This fork's main purpose is to create a clean
version of Stargate compliant with Spigot 1.17, even if it means changing the entire project's previous structure. version of Stargate compliant with Spigot 1.17, even if it means changing the entire project's previous structure.
## License
Stargate is licensed under the GNU Lesser General Public License Version 3.0. This includes every source and resource
file. See the HEADER file for a more detailed license description.
## Migration ## Migration
This plugin should be compatible with configurations from the Stargate plugin all the way back. The nethergate.gate This plugin should be compatible with configurations from the Stargate plugin all the way back. The nethergate.gate
@ -298,7 +303,7 @@ while the per-gate costs re defined in the .gate files. To define a certain cost
# Configuration # Configuration
``` ```
language - The language to use (Included languages: en, de, es, fr, hu, it, nb-no, nl, nn-no, pt-br, ru) language - The language to use (Included languages: en, de, es, fr, hu, it, ja, nb-no, nl, nn-no, pt-br, ru, zh_cn)
adminUpdateAlert - Whether to alert admins about an available update when joining the server adminUpdateAlert - Whether to alert admins about an available update when joining the server
folders: folders:
portalFolder - The folder your portal databases are saved in portalFolder - The folder your portal databases are saved in
@ -306,6 +311,7 @@ folders:
gates: gates:
maxGatesEachNetwork - If non-zero, will define the maximum amount of gates allowed on any network. maxGatesEachNetwork - If non-zero, will define the maximum amount of gates allowed on any network.
defaultGateNetwork - The default gate network defaultGateNetwork - The default gate network
exitVelocity - The velocity to give players exiting stargates, relative to the entry velocity (1 = same as entry velocity)
cosmetic: cosmetic:
rememberDestination - Whether to set the first destination as the last used destination for all gates rememberDestination - Whether to set the first destination as the last used destination for all gates
sortNetworkDestinations - If true, network lists will be sorted alphabetically. sortNetworkDestinations - If true, network lists will be sorted alphabetically.
@ -323,6 +329,7 @@ gates:
handleCreatureTransportation - Whether or not to handle players that transport creatures by sending vehicles (minecarts, boats) through gates. handleCreatureTransportation - Whether or not to handle players that transport creatures by sending vehicles (minecarts, boats) through gates.
handleNonPlayerVehicles - Whether or not to handle vehicles with a passenger which is not a player going through gates (pigs, horses, villagers, creepers, etc.). handleCreatureTransportation must be enabled. handleNonPlayerVehicles - Whether or not to handle vehicles with a passenger which is not a player going through gates (pigs, horses, villagers, creepers, etc.). handleCreatureTransportation must be enabled.
handleLeashedCreatures - Whether or not to handle creatures leashed by a player going through gates. Set to false to disallow leashed creatures going through gates. handleLeashedCreatures - Whether or not to handle creatures leashed by a player going through gates. Set to false to disallow leashed creatures going through gates.
enableCraftBookRemoveOnEjectFix - Whether to enable a fix that causes loss of NBT data, but allows vehicle teleportation to work when CraftBook's remove minecart/boat on eject setting is enabled
economy: economy:
useEconomy - Whether or not to enable Economy using Vault (must have the Vault plugin) useEconomy - Whether or not to enable Economy using Vault (must have the Vault plugin)
createCost - The cost to create a stargate createCost - The cost to create a stargate
@ -335,11 +342,13 @@ economy:
debugging: debugging:
debug - Whether to show massive debug output debug - Whether to show massive debug output
permissionDebug - Whether to show massive permission debug output permissionDebug - Whether to show massive permission debug output
advanced:
waitForPlayerAfterTeleportDelay - The amount of ticks to wait before adding a player as passenger of a vehicle. On slow servers, a value of 6 is required to avoid client glitches after teleporting on a vehicle.
``` ```
# Message Customization # Message Customization
It is possible to customize all the messages Stargate displays, including the [Stargate] prefix. You can find the It is possible to customize all the messages Stargate displays, including the \[Stargate] prefix. You can find the
strings in plugins/Stargate/lang/chosenLanguage.txt. strings in plugins/Stargate/lang/chosenLanguage.txt.
If a string is removed, or left blank, it will default to the default english string. There are some special cases If a string is removed, or left blank, it will default to the default english string. There are some special cases
@ -396,6 +405,38 @@ portalInfoServer=Server: %server%
# Changes # Changes
#### \[Version 0.9.3.7] EpicKnarvik97 fork
- Adds the Japanese language file provided by spigot user furplag
#### \[Version 0.9.3.6] EpicKnarvik97 fork
- Adds the simplified Chinese language file provided by spigot user YKDZ
#### \[Version 0.9.3.5] EpicKnarvik97 fork
- Fixes the wait for player delay being too low by default
- Performs some minor code optimizations and restructuring
#### \[Version 0.9.3.4] EpicKnarvik97 fork
- Includes passengers of passengers when teleporting entities
- Fixes a bug which caused Stargate to use more CPU for no reason
- Teleports boats/minecarts like other vehicles unless *enableCraftBookRemoveOnEjectFix* is enabled
- Adds the *waitForPlayerAfterTeleportDelay* config option which allows changing the delay between vehicle teleportation
and the player being teleported to the vehicle
- Makes boats keep their wood type even when re-created
#### \[Version 0.9.3.3] EpicKnarvik97 fork
- Prevents Zombified Piglins from randomly spawning at Stargates
#### \[Version 0.9.3.2] EpicKnarvik97 fork
- Adds a config option to set the exit velocity of any players exiting a stargate
- Adjusts vehicle teleportation a bit to prevent passengers' exit rotation from being wrong
- Improves the checking for buggy double-clicks on non-button blocks
#### \[Version 0.9.3.1] EpicKnarvik97 fork #### \[Version 0.9.3.1] EpicKnarvik97 fork
- Ignores the type of air when checking if a stargate is valid - Ignores the type of air when checking if a stargate is valid

21
pom.xml
View File

@ -4,7 +4,7 @@
<groupId>net.knarcraft</groupId> <groupId>net.knarcraft</groupId>
<artifactId>Stargate</artifactId> <artifactId>Stargate</artifactId>
<version>0.9.3.1</version> <version>0.9.4.1</version>
<licenses> <licenses>
<license> <license>
@ -28,13 +28,17 @@
<id>vault-repo</id> <id>vault-repo</id>
<url>http://nexus.hc.to/content/repositories/pub_releases</url> <url>http://nexus.hc.to/content/repositories/pub_releases</url>
</repository> </repository>
<repository>
<id>dynmap</id>
<url>https://repo.mikeprimm.com/</url>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId> <artifactId>spigot-api</artifactId>
<version>1.18.1-R0.1-SNAPSHOT</version> <version>1.19-R0.1-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.milkbowl.vault</groupId> <groupId>net.milkbowl.vault</groupId>
@ -44,27 +48,32 @@
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId> <artifactId>junit-jupiter-api</artifactId>
<version>5.8.0-M1</version> <version>5.8.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.seeseemelk</groupId> <groupId>com.github.seeseemelk</groupId>
<artifactId>MockBukkit-v1.18</artifactId> <artifactId>MockBukkit-v1.18</artifactId>
<version>1.14.0</version> <version>1.15.5</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jetbrains</groupId> <groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId> <artifactId>annotations</artifactId>
<version>19.0.0</version> <version>22.0.0</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.13.1</version> <version>4.13.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>us.dynmap</groupId>
<artifactId>dynmap-api</artifactId>
<version>3.1-beta-2</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -10,6 +10,7 @@ import net.knarcraft.stargate.container.BlockChangeRequest;
import net.knarcraft.stargate.container.ChunkUnloadRequest; import net.knarcraft.stargate.container.ChunkUnloadRequest;
import net.knarcraft.stargate.listener.BlockEventListener; import net.knarcraft.stargate.listener.BlockEventListener;
import net.knarcraft.stargate.listener.EntityEventListener; import net.knarcraft.stargate.listener.EntityEventListener;
import net.knarcraft.stargate.listener.EntitySpawnListener;
import net.knarcraft.stargate.listener.PlayerEventListener; import net.knarcraft.stargate.listener.PlayerEventListener;
import net.knarcraft.stargate.listener.PluginEventListener; import net.knarcraft.stargate.listener.PluginEventListener;
import net.knarcraft.stargate.listener.PortalEventListener; import net.knarcraft.stargate.listener.PortalEventListener;
@ -38,24 +39,44 @@ import java.util.Queue;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
/*
Stargate - A portal plugin for Bukkit
Copyright (C) 2011 Shaun (sturmeh)
Copyright (C) 2011 Dinnerbone
Copyright (C) 2011-2013 Steven "Drakia" Scott <Contact@TheDgtl.net>
Copyright (C) 2015-2020 Michael Smith (PseudoKnight)
Copyright (C) 2021-2022 Kristian Knarvik (EpicKnarvik97)
The following license notice applies to all source and resource files in the Stargate project:
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** /**
* The main class of the Stargate plugin * The main class of the Stargate plugin
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class Stargate extends JavaPlugin { public class Stargate extends JavaPlugin {
//Used for changing gate open/closed material.
private static final Queue<BlockChangeRequest> blockChangeRequestQueue = new LinkedList<>(); private static final Queue<BlockChangeRequest> blockChangeRequestQueue = new LinkedList<>();
private static final Queue<ChunkUnloadRequest> chunkUnloadQueue = new PriorityQueue<>(); private static final Queue<ChunkUnloadRequest> chunkUnloadQueue = new PriorityQueue<>();
private static Logger logger; private static Logger logger;
private static Stargate stargate; private static Stargate stargate;
private static String pluginVersion; private static String pluginVersion;
private static PluginManager pluginManager; private static PluginManager pluginManager;
private static StargateConfig stargateConfig; private static StargateConfig stargateConfig;
private static String updateAvailable = null; private static String updateAvailable = null;
/** /**
@ -388,6 +409,7 @@ public class Stargate extends JavaPlugin {
pluginManager.registerEvents(new WorldEventListener(), this); pluginManager.registerEvents(new WorldEventListener(), this);
pluginManager.registerEvents(new PluginEventListener(this), this); pluginManager.registerEvents(new PluginEventListener(this), this);
pluginManager.registerEvents(new TeleportEventListener(), this); pluginManager.registerEvents(new TeleportEventListener(), this);
pluginManager.registerEvents(new EntitySpawnListener(), this);
} }
/** /**
@ -428,4 +450,5 @@ public class Stargate extends JavaPlugin {
public static StargateConfig getStargateConfig() { public static StargateConfig getStargateConfig() {
return stargateConfig; return stargateConfig;
} }
} }

View File

@ -23,8 +23,9 @@ public class CommandAbout implements CommandExecutor {
commandSender.sendMessage(textColor + "Go to " + highlightColor + commandSender.sendMessage(textColor + "Go to " + highlightColor +
"https://git.knarcraft.net/EpicKnarvik97/Stargate " + textColor + "for the official repository"); "https://git.knarcraft.net/EpicKnarvik97/Stargate " + textColor + "for the official repository");
String author = Stargate.getStargateConfig().getLanguageLoader().getString("author"); String author = Stargate.getStargateConfig().getLanguageLoader().getString("author");
if (!author.isEmpty()) if (!author.isEmpty()) {
commandSender.sendMessage(textColor + "Language created by " + highlightColor + author); commandSender.sendMessage(textColor + "Language created by " + highlightColor + author);
}
return true; return true;
} }

View File

@ -3,12 +3,12 @@ package net.knarcraft.stargate.command;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.ConfigOption; import net.knarcraft.stargate.config.ConfigOption;
import net.knarcraft.stargate.config.ConfigTag; import net.knarcraft.stargate.config.ConfigTag;
import net.knarcraft.stargate.config.DynmapManager;
import net.knarcraft.stargate.config.OptionDataType; import net.knarcraft.stargate.config.OptionDataType;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalRegistry; import net.knarcraft.stargate.portal.PortalRegistry;
import net.knarcraft.stargate.portal.PortalSignDrawer; import net.knarcraft.stargate.portal.PortalSignDrawer;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
@ -90,6 +90,15 @@ public class CommandConfig implements CommandExecutor {
configuration.set(selectedOption.getConfigNode(), intValue); configuration.set(selectedOption.getConfigNode(), intValue);
} }
} }
case DOUBLE -> {
Double doubleValue = getDouble(commandSender, selectedOption, value);
if (doubleValue == null) {
return;
} else {
Stargate.getStargateConfig().getConfigOptionsReference().put(selectedOption, doubleValue);
configuration.set(selectedOption.getConfigNode(), doubleValue);
}
}
case STRING -> { case STRING -> {
updateStringConfigValue(selectedOption, commandSender, value); updateStringConfigValue(selectedOption, commandSender, value);
configuration.set(selectedOption.getConfigNode(), value); configuration.set(selectedOption.getConfigNode(), value);
@ -314,6 +323,30 @@ public class CommandConfig implements CommandExecutor {
} }
} }
/**
* Gets a double from a string
*
* @param commandSender <p>The command sender that sent the config command</p>
* @param selectedOption <p>The option the command sender is trying to change</p>
* @param value <p>The value given</p>
* @return <p>A double, or null if it was invalid</p>
*/
private Double getDouble(CommandSender commandSender, ConfigOption selectedOption, String value) {
try {
double doubleValue = Double.parseDouble(value);
if (selectedOption == ConfigOption.EXIT_VELOCITY && doubleValue < 0) {
commandSender.sendMessage(ChatColor.RED + "This config option cannot be negative.");
return null;
}
return doubleValue;
} catch (NumberFormatException exception) {
commandSender.sendMessage(ChatColor.RED + "Invalid number given");
return null;
}
}
/** /**
* Reloads the config if necessary * Reloads the config if necessary
* *
@ -345,6 +378,10 @@ public class CommandConfig implements CommandExecutor {
//Load or unload Vault and Economy as necessary //Load or unload Vault and Economy as necessary
Stargate.getStargateConfig().reloadEconomy(); Stargate.getStargateConfig().reloadEconomy();
} }
if (ConfigTag.requiresDynmapReload(configOption)) {
//Regenerate all Dynmap markers
DynmapManager.addAllPortalMarkers();
}
} }
} }
@ -383,7 +420,7 @@ public class CommandConfig implements CommandExecutor {
Object defaultValue = option.getDefaultValue(); Object defaultValue = option.getDefaultValue();
String stringValue = String.valueOf(defaultValue); String stringValue = String.valueOf(defaultValue);
if (option.getDataType() == OptionDataType.STRING_LIST) { if (option.getDataType() == OptionDataType.STRING_LIST) {
stringValue = "[" + StringUtils.join((String[]) defaultValue, ",") + "]"; stringValue = "[" + String.join(",", (String[]) defaultValue) + "]";
} }
return ChatColor.GOLD + option.getName() + ChatColor.WHITE + " - " + ChatColor.GREEN + option.getDescription() + return ChatColor.GOLD + option.getName() + ChatColor.WHITE + " - " + ChatColor.GREEN + option.getDescription() +
ChatColor.DARK_GRAY + " (Default: " + ChatColor.GRAY + stringValue + ChatColor.DARK_GRAY + ")"; ChatColor.DARK_GRAY + " (Default: " + ChatColor.GRAY + stringValue + ChatColor.DARK_GRAY + ")";

View File

@ -2,12 +2,13 @@ package net.knarcraft.stargate.command;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import org.apache.commons.lang.ArrayUtils;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
/** /**
* This command represents any command which starts with stargate * This command represents any command which starts with stargate
* *
@ -25,7 +26,7 @@ public class CommandStarGate implements CommandExecutor {
} else if (args[0].equalsIgnoreCase("reload")) { } else if (args[0].equalsIgnoreCase("reload")) {
return new CommandReload().onCommand(commandSender, command, s, args); return new CommandReload().onCommand(commandSender, command, s, args);
} else if (args[0].equalsIgnoreCase("config")) { } else if (args[0].equalsIgnoreCase("config")) {
String[] subArgs = (String[]) ArrayUtils.remove(args, 0); String[] subArgs = Arrays.copyOfRange(args, 1, args.length);
return new CommandConfig().onCommand(commandSender, command, s, subArgs); return new CommandConfig().onCommand(commandSender, command, s, subArgs);
} }
return false; return false;
@ -35,4 +36,5 @@ public class CommandStarGate implements CommandExecutor {
return true; return true;
} }
} }
} }

View File

@ -21,16 +21,17 @@ public class ConfigTabCompleter implements TabCompleter {
private List<String> signTypes; private List<String> signTypes;
private List<String> booleans; private List<String> booleans;
private List<String> numbers; private List<String> integers;
private List<String> chatColors; private List<String> chatColors;
private List<String> languages; private List<String> languages;
private List<String> extendedColors; private List<String> extendedColors;
private List<String> doubles;
@Nullable @Nullable
@Override @Override
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] args) { @NotNull String[] args) {
if (signTypes == null || booleans == null || numbers == null || chatColors == null || languages == null) { if (signTypes == null || booleans == null || integers == null || chatColors == null || languages == null) {
initializeAutoCompleteLists(); initializeAutoCompleteLists();
} }
if (args.length > 1) { if (args.length > 1) {
@ -104,7 +105,16 @@ public class ConfigTabCompleter implements TabCompleter {
//If the config value is an integer, display some valid numbers //If the config value is an integer, display some valid numbers
if (selectedOption.getDataType() == OptionDataType.INTEGER) { if (selectedOption.getDataType() == OptionDataType.INTEGER) {
if (typedText.trim().isEmpty()) { if (typedText.trim().isEmpty()) {
return numbers; return integers;
} else {
return new ArrayList<>();
}
}
//If the config value is a double, display some valid numbers
if (selectedOption.getDataType() == OptionDataType.DOUBLE) {
if (typedText.trim().isEmpty()) {
return doubles;
} else { } else {
return new ArrayList<>(); return new ArrayList<>();
} }
@ -164,9 +174,9 @@ public class ConfigTabCompleter implements TabCompleter {
booleans.add("true"); booleans.add("true");
booleans.add("false"); booleans.add("false");
numbers = new ArrayList<>(); integers = new ArrayList<>();
numbers.add("0"); integers.add("0");
numbers.add("5"); integers.add("5");
signTypes = new ArrayList<>(); signTypes = new ArrayList<>();
for (Material material : Material.values()) { for (Material material : Material.values()) {
@ -181,6 +191,12 @@ public class ConfigTabCompleter implements TabCompleter {
extendedColors = new ArrayList<>(chatColors); extendedColors = new ArrayList<>(chatColors);
extendedColors.add("default"); extendedColors.add("default");
extendedColors.add("inverted"); extendedColors.add("inverted");
doubles = new ArrayList<>();
doubles.add("5");
doubles.add("1");
doubles.add("0.5");
doubles.add("0.1");
} }
@ -201,22 +217,10 @@ public class ConfigTabCompleter implements TabCompleter {
*/ */
private List<ChatColor> getChatColors() { private List<ChatColor> getChatColors() {
List<ChatColor> chatColors = new ArrayList<>(); List<ChatColor> chatColors = new ArrayList<>();
chatColors.add(ChatColor.WHITE); char[] colors = new char[]{'a', 'b', 'c', 'd', 'e', 'f', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
chatColors.add(ChatColor.BLUE); for (char color : colors) {
chatColors.add(ChatColor.DARK_BLUE); chatColors.add(ChatColor.getByChar(color));
chatColors.add(ChatColor.DARK_PURPLE); }
chatColors.add(ChatColor.LIGHT_PURPLE);
chatColors.add(ChatColor.GOLD);
chatColors.add(ChatColor.GREEN);
chatColors.add(ChatColor.BLACK);
chatColors.add(ChatColor.DARK_GREEN);
chatColors.add(ChatColor.DARK_RED);
chatColors.add(ChatColor.RED);
chatColors.add(ChatColor.AQUA);
chatColors.add(ChatColor.DARK_AQUA);
chatColors.add(ChatColor.DARK_GRAY);
chatColors.add(ChatColor.GRAY);
chatColors.add(ChatColor.YELLOW);
chatColors.add(ChatColor.of("#ed76d9")); chatColors.add(ChatColor.of("#ed76d9"));
chatColors.add(ChatColor.of("#ffecb7")); chatColors.add(ChatColor.of("#ffecb7"));
return chatColors; return chatColors;
@ -233,11 +237,13 @@ public class ConfigTabCompleter implements TabCompleter {
languages.add("fr"); languages.add("fr");
languages.add("hu"); languages.add("hu");
languages.add("it"); languages.add("it");
languages.add("ja");
languages.add("nb-no"); languages.add("nb-no");
languages.add("nl"); languages.add("nl");
languages.add("nn-no"); languages.add("nn-no");
languages.add("pt-br"); languages.add("pt-br");
languages.add("ru"); languages.add("ru");
languages.add("zh_cn");
//TODO: Generate this list dynamically by listing the language files in the jar and adding the user's custom //TODO: Generate this list dynamically by listing the language files in the jar and adding the user's custom
// language files // language files
} }

View File

@ -1,6 +1,5 @@
package net.knarcraft.stargate.command; package net.knarcraft.stargate.command;
import org.apache.commons.lang.ArrayUtils;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter; import org.bukkit.command.TabCompleter;
@ -9,6 +8,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
@ -29,7 +29,7 @@ public class StarGateTabCompleter implements TabCompleter {
} }
return matchingCommands; return matchingCommands;
} else if (args.length > 1 && args[0].equalsIgnoreCase("config")) { } else if (args.length > 1 && args[0].equalsIgnoreCase("config")) {
String[] subArgs = (String[]) ArrayUtils.remove(args, 0); String[] subArgs = Arrays.copyOfRange(args, 1, args.length);
return new ConfigTabCompleter().onTabComplete(commandSender, command, s, subArgs); return new ConfigTabCompleter().onTabComplete(commandSender, command, s, subArgs);
} else { } else {
return new ArrayList<>(); return new ArrayList<>();

View File

@ -50,6 +50,9 @@ public enum ConfigOption {
*/ */
HIGHLIGHT_SIGN_COLOR("gates.cosmetic.highlightSignColor", "The text color used for highlighting stargate signs", "WHITE"), HIGHLIGHT_SIGN_COLOR("gates.cosmetic.highlightSignColor", "The text color used for highlighting stargate signs", "WHITE"),
/**
* The colors to use for each type of sign
*/
PER_SIGN_COLORS("gates.cosmetic.perSignColors", "The per-sign color specification", new String[]{ PER_SIGN_COLORS("gates.cosmetic.perSignColors", "The per-sign color specification", new String[]{
"'ACACIA:default,default'", "'BIRCH:default,default'", "'CRIMSON:inverted,inverted'", "'DARK_OAK:inverted,inverted'", "'ACACIA:default,default'", "'BIRCH:default,default'", "'CRIMSON:inverted,inverted'", "'DARK_OAK:inverted,inverted'",
"'JUNGLE:default,default'", "'OAK:default,default'", "'SPRUCE:inverted,inverted'", "'WARPED:inverted,inverted'"}), "'JUNGLE:default,default'", "'OAK:default,default'", "'SPRUCE:inverted,inverted'", "'WARPED:inverted,inverted'"}),
@ -102,6 +105,20 @@ public enum ConfigOption {
HANDLE_LEASHED_CREATURES("gates.functionality.handleLeashedCreatures", HANDLE_LEASHED_CREATURES("gates.functionality.handleLeashedCreatures",
"Whether to enable players to teleport a creature on a leash", true), "Whether to enable players to teleport a creature on a leash", true),
/**
* Whether to enable a fix that makes teleportation of minecarts/boats work even with craftbook's vehicle removal
*/
ENABLE_CRAFT_BOOK_REMOVE_ON_EJECT_FIX("gates.functionality.enableCraftBookRemoveOnEjectFix",
"Whether to enable a fix that causes loss of NBT data, but allows vehicle teleportation to work " +
"when CraftBook's remove minecart/boat on eject setting is enabled", false),
/**
* The delay between teleporting a vehicle and adding the player as passenger
*/
WAIT_FOR_PLAYER_AFTER_TELEPORT_DELAY("advanced.waitForPlayerAfterTeleportDelay",
"The amount of ticks to wait before adding a player as passenger of a vehicle. On slow servers, " +
"a value of 6 is required to avoid client glitches after teleporting on a vehicle.", 6),
/** /**
* Whether to enable economy support for taking payment from players creating/destroying/using stargates * Whether to enable economy support for taking payment from players creating/destroying/using stargates
*/ */
@ -156,8 +173,23 @@ public enum ConfigOption {
/** /**
* Whether to alert admins about new updates * Whether to alert admins about new updates
*/ */
ADMIN_UPDATE_ALERT("adminUpdateAlert", "Whether to alert admins about new plugin updates", true); ADMIN_UPDATE_ALERT("adminUpdateAlert", "Whether to alert admins about new plugin updates", true),
/**
* The velocity of players exiting a stargate, relative to the entry velocity
*/
EXIT_VELOCITY("gates.exitVelocity", "The velocity of players exiting stargates, relative to the entry velocity", 0.1D),
/**
* Whether to enable showing Stargates in Dynmap
*/
ENABLE_DYNMAP("dynmap.enableDynmap", "Whether to display Stargates in Dynmap's map", true),
/**
* Whether to hide Dynmap icons by default
*/
DYNMAP_ICONS_DEFAULT_HIDDEN("dynmap.dynmapIconsHiddenByDefault",
"Whether to hide Stargate's Dynmap icons by default, requiring the user to enable them.", true);
private final String configNode; private final String configNode;
private final String description; private final String description;
@ -184,6 +216,8 @@ public enum ConfigOption {
this.dataType = OptionDataType.BOOLEAN; this.dataType = OptionDataType.BOOLEAN;
} else if (defaultValue instanceof Integer) { } else if (defaultValue instanceof Integer) {
this.dataType = OptionDataType.INTEGER; this.dataType = OptionDataType.INTEGER;
} else if (defaultValue instanceof Double) {
this.dataType = OptionDataType.DOUBLE;
} else { } else {
throw new IllegalArgumentException("Unknown config data type encountered: " + defaultValue); throw new IllegalArgumentException("Unknown config data type encountered: " + defaultValue);
} }

View File

@ -9,7 +9,8 @@ public enum ConfigTag {
COLOR(new ConfigOption[]{ConfigOption.FREE_GATES_COLOR, ConfigOption.MAIN_SIGN_COLOR, COLOR(new ConfigOption[]{ConfigOption.FREE_GATES_COLOR, ConfigOption.MAIN_SIGN_COLOR,
ConfigOption.HIGHLIGHT_SIGN_COLOR, ConfigOption.PER_SIGN_COLORS}), ConfigOption.HIGHLIGHT_SIGN_COLOR, ConfigOption.PER_SIGN_COLORS}),
FOLDER(new ConfigOption[]{ConfigOption.GATE_FOLDER, ConfigOption.PORTAL_FOLDER}); FOLDER(new ConfigOption[]{ConfigOption.GATE_FOLDER, ConfigOption.PORTAL_FOLDER}),
DYNMAP(new ConfigOption[]{ConfigOption.ENABLE_DYNMAP, ConfigOption.DYNMAP_ICONS_DEFAULT_HIDDEN});
private final ConfigOption[] taggedOptions; private final ConfigOption[] taggedOptions;
@ -52,6 +53,16 @@ public enum ConfigTag {
return FOLDER.isTagged(option); return FOLDER.isTagged(option);
} }
/**
* Checks whether a given config option requires a re-load of all Dynmap markers
*
* @param configOption <p>The config option to check</p>
* @return <p>True if changing the config option requires a reload of all dynmap markers</p>
*/
public static boolean requiresDynmapReload(ConfigOption configOption) {
return DYNMAP.isTagged(configOption);
}
/** /**
* Checks whether a given config option requires a portal reload to take effect * Checks whether a given config option requires a portal reload to take effect
* *

View File

@ -0,0 +1,134 @@
package net.knarcraft.stargate.config;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalRegistry;
import org.bukkit.Location;
import org.bukkit.World;
import org.dynmap.DynmapAPI;
import org.dynmap.markers.GenericMarker;
import org.dynmap.markers.Marker;
import org.dynmap.markers.MarkerIcon;
import org.dynmap.markers.MarkerSet;
/**
* A manager for dealing with everything Dynmap
*/
public final class DynmapManager {
private static MarkerSet markerSet;
private static MarkerIcon portalIcon;
private DynmapManager() {
}
/**
* Initializes the dynmap manager
*
* @param dynmapAPI <p>A reference</p>
*/
public static void initialize(DynmapAPI dynmapAPI) {
if (dynmapAPI == null || dynmapAPI.getMarkerAPI() == null) {
markerSet = null;
portalIcon = null;
} else {
markerSet = dynmapAPI.getMarkerAPI().createMarkerSet("stargate", "Stargate", null, false);
if (markerSet != null) {
markerSet.setHideByDefault(Stargate.getStargateConfig().hideDynmapIcons());
}
portalIcon = dynmapAPI.getMarkerAPI().getMarkerIcon("portal");
}
}
/**
* Adds all portal markers for all current portals
*/
public static void addAllPortalMarkers() {
if (markerSet == null || Stargate.getStargateConfig().isDynmapDisabled()) {
//Remove any existing markers if dynmap has been disabled after startup
if (markerSet != null) {
markerSet.getMarkers().forEach(GenericMarker::deleteMarker);
}
return;
}
markerSet.setHideByDefault(Stargate.getStargateConfig().hideDynmapIcons());
//Remove all existing markers for a clean start
markerSet.getMarkers().forEach(GenericMarker::deleteMarker);
for (Portal portal : PortalRegistry.getAllPortals()) {
addPortalMarker(portal);
}
}
/**
* Adds a portal marker for the given portal
*
* @param portal <p>The portal to add a marker for</p>
*/
public static void addPortalMarker(Portal portal) {
if (markerSet == null || Stargate.getStargateConfig().isDynmapDisabled()) {
return;
}
World world = portal.getWorld();
if (portal.getOptions().isHidden() || world == null) {
return;
}
Location location = portal.getBlockAt(portal.getGate().getLayout().getExit());
Marker marker = markerSet.createMarker(getPortalMarkerId(portal), portal.getName(), world.getName(),
location.getX(), location.getY(), location.getZ(), portalIcon, false);
if (marker == null) {
Stargate.logWarning(String.format(
"""
Unable to create marker for portal
Portal marker id: %s
Portal name: %s
Portal world: %s
Portal location: %s,%s,%s""",
getPortalMarkerId(portal), portal.getName(), world.getName(), location.getX(), location.getY(),
location.getZ()));
return;
}
String networkPrompt;
if (portal.getOptions().isBungee()) {
networkPrompt = "Server";
} else {
networkPrompt = "Network";
}
String markerDescription = String.format("<b>Name:</b> %s<br /><b>%s:</b> %s<br /><b>Destination:</b> " +
"%s<br /><b>Owner:</b> %s<br />", portal.getName(), networkPrompt, portal.getNetwork(),
portal.getDestinationName(), portal.getOwner().getName());
marker.setDescription(markerDescription);
marker.setLabel(portal.getName(), true);
if (portalIcon != null) {
marker.setMarkerIcon(portalIcon);
}
}
/**
* Removes the portal marker for the given portal
*
* @param portal <p>The portal to remove the marker for</p>
*/
public static void removePortalMarker(Portal portal) {
if (markerSet == null || Stargate.getStargateConfig().isDynmapDisabled()) {
return;
}
Marker marker = markerSet.findMarker(getPortalMarkerId(portal));
if (marker != null) {
marker.deleteMarker();
}
}
/**
* Gets the id used for the given portal's marker
*
* @param portal <p>The portal to get a marker id for</p>
* @return <p></p>
*/
private static String getPortalMarkerId(Portal portal) {
return portal.getNetwork() + "-:-" + portal.getName();
}
}

View File

@ -6,17 +6,28 @@ package net.knarcraft.stargate.config;
public enum OptionDataType { public enum OptionDataType {
/** /**
* The data type for the option is a String * The data type if the option is a String
*/ */
STRING, STRING,
/** /**
* The data type for the option is a Boolean * The data type if the option is a Boolean
*/ */
BOOLEAN, BOOLEAN,
STRING_LIST,
/** /**
* The data type for the option is an Integer * The data type if the option is a string list
*/ */
INTEGER STRING_LIST,
/**
* The data type if the option is an Integer
*/
INTEGER,
/**
* The data type if the option is a double
*/
DOUBLE
} }

View File

@ -15,6 +15,7 @@ import org.bukkit.World;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.messaging.Messenger; import org.bukkit.plugin.messaging.Messenger;
import org.dynmap.DynmapAPI;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -101,6 +102,11 @@ public final class StargateConfig {
//Set up vault economy if vault has been loaded //Set up vault economy if vault has been loaded
setupVaultEconomy(); setupVaultEconomy();
DynmapAPI dynmapAPI = (DynmapAPI) Bukkit.getPluginManager().getPlugin("dynmap");
if (dynmapAPI != null) {
DynmapManager.initialize(dynmapAPI);
DynmapManager.addAllPortalMarkers();
}
} }
/** /**
@ -152,6 +158,24 @@ public final class StargateConfig {
return (boolean) configOptions.get(ConfigOption.PERMISSION_DEBUG); return (boolean) configOptions.get(ConfigOption.PERMISSION_DEBUG);
} }
/**
* Gets whether Dynmap integration is disabled
*
* @return <p>Whether Dynmap integration is disabled</p>
*/
public boolean isDynmapDisabled() {
return !((boolean) configOptions.get(ConfigOption.ENABLE_DYNMAP));
}
/**
* Gets whether Dynmap icons should be hidden by default
*
* @return <p>Whether Dynmap icons should be hidden by default</p>
*/
public boolean hideDynmapIcons() {
return (boolean) configOptions.get(ConfigOption.DYNMAP_ICONS_DEFAULT_HIDDEN);
}
/** /**
* Gets the object containing economy config values * Gets the object containing economy config values
* *
@ -189,6 +213,9 @@ public final class StargateConfig {
startStopBungeeListener(stargateGateConfig.enableBungee()); startStopBungeeListener(stargateGateConfig.enableBungee());
} }
//Reload portal markers
DynmapManager.addAllPortalMarkers();
messageSender.sendErrorMessage(sender, languageLoader.getString("reloaded")); messageSender.sendErrorMessage(sender, languageLoader.getString("reloaded"));
} }
@ -358,6 +385,7 @@ public final class StargateConfig {
} }
case BOOLEAN -> optionValue = newConfig.getBoolean(configNode); case BOOLEAN -> optionValue = newConfig.getBoolean(configNode);
case INTEGER -> optionValue = newConfig.getInt(configNode); case INTEGER -> optionValue = newConfig.getInt(configNode);
case DOUBLE -> optionValue = newConfig.getDouble(configNode);
default -> throw new IllegalArgumentException("Invalid config data type encountered"); default -> throw new IllegalArgumentException("Invalid config data type encountered");
} }
configOptions.put(option, optionValue); configOptions.put(option, optionValue);
@ -519,4 +547,5 @@ public final class StargateConfig {
public LanguageLoader getLanguageLoader() { public LanguageLoader getLanguageLoader() {
return languageLoader; return languageLoader;
} }
} }

View File

@ -16,6 +16,7 @@ import java.util.Map;
* The Stargate gate config keeps track of all global config values related to gates * The Stargate gate config keeps track of all global config values related to gates
*/ */
public final class StargateGateConfig { public final class StargateGateConfig {
private static final int activeTime = 10; private static final int activeTime = 10;
private static final int openTime = 10; private static final int openTime = 10;
private final Map<ConfigOption, Object> configOptions; private final Map<ConfigOption, Object> configOptions;
@ -125,6 +126,29 @@ public final class StargateGateConfig {
return (boolean) configOptions.get(ConfigOption.HANDLE_LEASHED_CREATURES); return (boolean) configOptions.get(ConfigOption.HANDLE_LEASHED_CREATURES);
} }
/**
* Gets whether the CraftBook vehicle removal fix is enabled
*
* <p>If enabled, minecarts and boats should be re-created instead of teleported.</p>
*
* @return <p>True if the CraftBook vehicle removal fix is enabled</p>
*/
public boolean enableCraftBookRemoveOnEjectFix() {
return (boolean) configOptions.get(ConfigOption.ENABLE_CRAFT_BOOK_REMOVE_ON_EJECT_FIX);
}
/**
* Gets the delay to use before adding a player as passenger of a teleported vehicle
*
* @return <p>The delay to use before adding a player as passenger of a teleported vehicle</p>
*/
public int waitForPlayerAfterTeleportDelay() {
if ((int) configOptions.get(ConfigOption.WAIT_FOR_PLAYER_AFTER_TELEPORT_DELAY) < 2) {
configOptions.put(ConfigOption.WAIT_FOR_PLAYER_AFTER_TELEPORT_DELAY, 6);
}
return (int) configOptions.get(ConfigOption.WAIT_FOR_PLAYER_AFTER_TELEPORT_DELAY);
}
/** /**
* Gets whether the list of destinations within a network should be sorted * Gets whether the list of destinations within a network should be sorted
* *
@ -179,6 +203,15 @@ public final class StargateGateConfig {
return (String) configOptions.get(ConfigOption.DEFAULT_GATE_NETWORK); return (String) configOptions.get(ConfigOption.DEFAULT_GATE_NETWORK);
} }
/**
* Gets the exit velocity of players using stargates, relative to the entry velocity
*
* @return <p>The relative exit velocity</p>
*/
public double getExitVelocity() {
return (double) configOptions.get(ConfigOption.EXIT_VELOCITY);
}
/** /**
* Loads all config values related to gates * Loads all config values related to gates
*/ */
@ -253,8 +286,8 @@ public final class StargateGateConfig {
if (colors[colorIndex].equalsIgnoreCase("inverted")) { if (colors[colorIndex].equalsIgnoreCase("inverted")) {
//Convert from ChatColor to awt.Color to Bukkit.Color then invert and convert to ChatColor //Convert from ChatColor to awt.Color to Bukkit.Color then invert and convert to ChatColor
java.awt.Color color = defaultColors[colorIndex].getColor(); java.awt.Color color = defaultColors[colorIndex].getColor();
parsedColor = ColorHelper.fromColor(ColorHelper.invert(Color.fromRGB(color.getRed(), parsedColor = ColorHelper.fromColor(ColorHelper.invert(Color.fromRGB(color.getRed(), color.getGreen(),
color.getGreen(), color.getBlue()))); color.getBlue())));
} else { } else {
try { try {
parsedColor = ChatColor.of(colors[colorIndex]); parsedColor = ChatColor.of(colors[colorIndex]);
@ -291,4 +324,5 @@ public final class StargateGateConfig {
PortalSignDrawer.setHighlightColor(ChatColor.WHITE); PortalSignDrawer.setHighlightColor(ChatColor.WHITE);
} }
} }
} }

View File

@ -60,16 +60,11 @@ public class RelativeBlockVector {
* @return <p>A new relative block vector with the property altered</p> * @return <p>A new relative block vector with the property altered</p>
*/ */
public RelativeBlockVector addToVector(Property propertyToAddTo, int valueToAdd) { public RelativeBlockVector addToVector(Property propertyToAddTo, int valueToAdd) {
switch (propertyToAddTo) { return switch (propertyToAddTo) {
case RIGHT: case RIGHT -> new RelativeBlockVector(this.right + valueToAdd, this.down, this.out);
return new RelativeBlockVector(this.right + valueToAdd, this.down, this.out); case DOWN -> new RelativeBlockVector(this.right, this.down + valueToAdd, this.out);
case DOWN: case OUT -> new RelativeBlockVector(this.right, this.down, this.out + valueToAdd);
return new RelativeBlockVector(this.right, this.down + valueToAdd, this.out); };
case OUT:
return new RelativeBlockVector(this.right, this.down, this.out + valueToAdd);
default:
throw new IllegalArgumentException("Invalid relative block vector property given");
}
} }
/** /**

View File

@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
* <p>This event can be used to overwrite the location the entity is teleported to.</p> * <p>This event can be used to overwrite the location the entity is teleported to.</p>
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class StargateEntityPortalEvent extends StargateEvent { public class StargateEntityPortalEvent extends StargateEvent implements StargateTeleportEvent {
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
final Entity travellingEntity; final Entity travellingEntity;
@ -58,6 +58,7 @@ public class StargateEntityPortalEvent extends StargateEvent {
* *
* @return <p>Location of the exit point</p> * @return <p>Location of the exit point</p>
*/ */
@Override
public Location getExit() { public Location getExit() {
return exit; return exit;
} }

View File

@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
* <p>This event can be used to overwrite the location the player is teleported to.</p> * <p>This event can be used to overwrite the location the player is teleported to.</p>
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class StargatePlayerPortalEvent extends StargatePlayerEvent { public class StargatePlayerPortalEvent extends StargatePlayerEvent implements StargateTeleportEvent {
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
private final Portal destination; private final Portal destination;
@ -47,6 +47,7 @@ public class StargatePlayerPortalEvent extends StargatePlayerEvent {
* *
* @return <p>Location of the exit point</p> * @return <p>Location of the exit point</p>
*/ */
@Override
public Location getExit() { public Location getExit() {
return exit; return exit;
} }

View File

@ -0,0 +1,18 @@
package net.knarcraft.stargate.event;
import org.bukkit.Location;
import org.bukkit.event.Cancellable;
/**
* A generic teleportation event
*/
public interface StargateTeleportEvent extends Cancellable {
/**
* Return the location of the players exit point
*
* @return <p>Location of the exit point</p>
*/
Location getExit();
}

View File

@ -0,0 +1,25 @@
package net.knarcraft.stargate.listener;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.PortalHandler;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent;
/**
* A listener that listens for any relevant events causing entities to spawn
*/
public class EntitySpawnListener implements Listener {
@EventHandler
public void onCreatureSpawn(CreatureSpawnEvent event) {
//Prevent Zombified Piglins and other creatures form spawning at stargates
if (event.getSpawnReason() == CreatureSpawnEvent.SpawnReason.NETHER_PORTAL) {
if (PortalHandler.getByEntrance(event.getLocation()) != null) {
event.setCancelled(true);
Stargate.debug("EntitySpawnListener", "Prevented creature from spawning at Stargate");
}
}
}
}

View File

@ -7,16 +7,17 @@ import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalActivator; import net.knarcraft.stargate.portal.PortalActivator;
import net.knarcraft.stargate.portal.PortalHandler; import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter; import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter;
import net.knarcraft.stargate.portal.teleporter.Teleporter;
import net.knarcraft.stargate.portal.teleporter.VehicleTeleporter; import net.knarcraft.stargate.portal.teleporter.VehicleTeleporter;
import net.knarcraft.stargate.utility.BungeeHelper; import net.knarcraft.stargate.utility.BungeeHelper;
import net.knarcraft.stargate.utility.MaterialHelper; import net.knarcraft.stargate.utility.MaterialHelper;
import net.knarcraft.stargate.utility.PermissionHelper; import net.knarcraft.stargate.utility.PermissionHelper;
import net.knarcraft.stargate.utility.TeleportHelper;
import net.knarcraft.stargate.utility.UUIDMigrationHelper; import net.knarcraft.stargate.utility.UUIDMigrationHelper;
import net.knarcraft.stargate.utility.UpdateChecker; import net.knarcraft.stargate.utility.UpdateChecker;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.data.type.WallSign; import org.bukkit.block.data.type.WallSign;
import org.bukkit.entity.AbstractHorse; import org.bukkit.entity.AbstractHorse;
@ -33,6 +34,10 @@ import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import java.util.HashMap;
import java.util.Map;
/** /**
* This listener listens to any player-related events related to stargates * This listener listens to any player-related events related to stargates
@ -40,8 +45,7 @@ import org.bukkit.inventory.ItemStack;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class PlayerEventListener implements Listener { public class PlayerEventListener implements Listener {
private static long eventTime; private static final Map<Player, Long> previousEventTimes = new HashMap<>();
private static PlayerInteractEvent previousEvent;
/** /**
* This event handler handles detection of any player teleporting through a bungee gate * This event handler handles detection of any player teleporting through a bungee gate
@ -101,6 +105,11 @@ public class PlayerEventListener implements Listener {
return; return;
} }
Portal entrancePortal = PortalHandler.getByEntrance(toLocation); Portal entrancePortal = PortalHandler.getByEntrance(toLocation);
//Check an additional block away in case the portal is a bungee portal using END_PORTAL
if (entrancePortal == null) {
entrancePortal = PortalHandler.getByAdjacentEntrance(toLocation);
}
Portal destination = entrancePortal.getPortalActivator().getDestination(player); Portal destination = entrancePortal.getPortalActivator().getDestination(player);
Entity playerVehicle = player.getVehicle(); Entity playerVehicle = player.getVehicle();
@ -129,10 +138,11 @@ public class PlayerEventListener implements Listener {
horse.setOwner(player); horse.setOwner(player);
} }
//Teleport the player's vehicle //Teleport the player's vehicle
new VehicleTeleporter(destination, (Vehicle) playerVehicle).teleport(entrancePortal); player.setVelocity(new Vector());
new VehicleTeleporter(destination, (Vehicle) playerVehicle).teleportEntity(entrancePortal);
} else { } else {
//Just teleport the player like normal //Just teleport the player like normal
new PlayerTeleporter(destination, player).teleport(entrancePortal, event); new PlayerTeleporter(destination, player).teleportPlayer(entrancePortal, event);
} }
if (!entrancePortal.getOptions().isSilent()) { if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg")); Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
@ -159,7 +169,12 @@ public class PlayerEventListener implements Listener {
//Check if the player moved from a portal //Check if the player moved from a portal
Portal entrancePortal = PortalHandler.getByEntrance(toLocation); Portal entrancePortal = PortalHandler.getByEntrance(toLocation);
if (entrancePortal == null) { if (entrancePortal == null) {
return false; //Check an additional block away for BungeeCord portals using END_PORTAL as its material
entrancePortal = PortalHandler.getByAdjacentEntrance(toLocation);
if (entrancePortal == null || !entrancePortal.getOptions().isBungee() ||
entrancePortal.getGate().getPortalOpenBlock() != Material.END_PORTAL) {
return false;
}
} }
Portal destination = entrancePortal.getPortalActivator().getDestination(player); Portal destination = entrancePortal.getPortalActivator().getDestination(player);
@ -183,7 +198,7 @@ public class PlayerEventListener implements Listener {
} }
//Make sure to check if the player has any leashed creatures, even though leashed teleportation is disabled //Make sure to check if the player has any leashed creatures, even though leashed teleportation is disabled
return Teleporter.noLeashedCreaturesPreventTeleportation(player); return TeleportHelper.noLeashedCreaturesPreventTeleportation(player);
} }
/** /**
@ -226,11 +241,14 @@ public class PlayerEventListener implements Listener {
EquipmentSlot hand = event.getHand(); EquipmentSlot hand = event.getHand();
if (hand != null && (PermissionHelper.hasPermission(player, "stargate.admin.dye") || if (hand != null && (PermissionHelper.hasPermission(player, "stargate.admin.dye") ||
portal.isOwner(player))) { portal.isOwner(player))) {
String itemName = player.getInventory().getItem(hand).getType().toString(); ItemStack item = player.getInventory().getItem(hand);
if (itemName.endsWith("DYE") || itemName.endsWith("INK_SAC")) { if (item != null) {
event.setUseInteractedBlock(Event.Result.ALLOW); String itemName = item.getType().toString();
Bukkit.getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(), portal::drawSign, 1); if (itemName.endsWith("DYE") || itemName.endsWith("INK_SAC")) {
return; event.setUseInteractedBlock(Event.Result.ALLOW);
Bukkit.getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(), portal::drawSign, 1);
return;
}
} }
} }
@ -295,7 +313,7 @@ public class PlayerEventListener implements Listener {
} }
//Prevent a double click caused by a Spigot bug //Prevent a double click caused by a Spigot bug
if (clickIsBug(event, block)) { if (clickIsBug(event.getPlayer(), block)) {
return; return;
} }
@ -321,7 +339,7 @@ public class PlayerEventListener implements Listener {
} else { } else {
//Display information about the portal if it has no sign //Display information about the portal if it has no sign
ItemStack heldItem = player.getInventory().getItem(hand); ItemStack heldItem = player.getInventory().getItem(hand);
if (heldItem.getType().isAir() || !heldItem.getType().isBlock()) { if (heldItem != null && (heldItem.getType().isAir() || !heldItem.getType().isBlock())) {
displayPortalInfo(block, player); displayPortalInfo(block, player);
} }
} }
@ -366,19 +384,17 @@ public class PlayerEventListener implements Listener {
* immediately, or causing portal information printing twice. This fix should detect the bug without breaking * immediately, or causing portal information printing twice. This fix should detect the bug without breaking
* clicking once the bug is fixed.</p> * clicking once the bug is fixed.</p>
* *
* @param event <p>The event causing the right click</p> * @param player <p>The player performing the right-click</p>
* @param block <p>The block to check</p> * @param block <p>The block to check</p>
* @return <p>True if the click is a bug and should be cancelled</p> * @return <p>True if the click is a bug and should be cancelled</p>
*/ */
private boolean clickIsBug(PlayerInteractEvent event, Block block) { private boolean clickIsBug(Player player, Block block) {
if (previousEvent != null && Long previousEventTime = previousEventTimes.get(player);
event.getPlayer() == previousEvent.getPlayer() && eventTime + 15 > System.currentTimeMillis()) { if (previousEventTime != null && previousEventTime + 50 > System.currentTimeMillis()) {
previousEvent = null; previousEventTimes.put(player, null);
eventTime = 0;
return true; return true;
} }
previousEvent = event; previousEventTimes.put(player, System.currentTimeMillis());
eventTime = System.currentTimeMillis();
return false; return false;
} }

View File

@ -49,4 +49,5 @@ public class PluginEventListener implements Listener {
Stargate.logInfo("Vault plugin lost."); Stargate.logInfo("Vault plugin lost.");
} }
} }
} }

View File

@ -6,6 +6,7 @@ import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler; import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter; import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter;
import net.knarcraft.stargate.utility.PermissionHelper; import net.knarcraft.stargate.utility.PermissionHelper;
import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
@ -67,14 +68,23 @@ public class PortalEventListener implements Listener {
return; return;
} }
Stargate.debug("PortalEventListener::onEntityPortalEnter",
"Found player " + player + " entering END_PORTAL " + portal);
//Remove any old player teleportations in case weird things happen //Remove any old player teleportations in case weird things happen
playersFromTheEnd.removeIf((teleportation -> teleportation.getPlayer() == player)); playersFromTheEnd.removeIf((teleportation -> teleportation.getPlayer() == player));
//Decide if the anything stops the player from teleporting //Decide if the anything stops the player from teleporting
if (PermissionHelper.playerCannotTeleport(portal, portal.getPortalActivator().getDestination(), player, null)) { if (PermissionHelper.playerCannotTeleport(portal, portal.getPortalActivator().getDestination(), player, null) ||
portal.getOptions().isBungee()) {
//Teleport the player back to the portal they came in, just in case //Teleport the player back to the portal they came in, just in case
playersFromTheEnd.add(new FromTheEndTeleportation(player, portal)); playersFromTheEnd.add(new FromTheEndTeleportation(player, portal));
Stargate.debug("PortalEventListener::onEntityPortalEnter",
"Sending player back to the entrance");
} else {
playersFromTheEnd.add(new FromTheEndTeleportation(player, portal.getPortalActivator().getDestination()));
Stargate.debug("PortalEventListener::onEntityPortalEnter",
"Sending player to destination");
} }
playersFromTheEnd.add(new FromTheEndTeleportation(player, portal.getPortalActivator().getDestination()));
} }
} }
@ -95,10 +105,18 @@ public class PortalEventListener implements Listener {
Portal exitPortal = teleportation.getExit(); Portal exitPortal = teleportation.getExit();
//Overwrite respawn location to respawn in front of the portal //Overwrite respawn location to respawn in front of the portal
event.setRespawnLocation(new PlayerTeleporter(exitPortal, respawningPlayer).getExit(respawningPlayer, PlayerTeleporter teleporter = new PlayerTeleporter(exitPortal, respawningPlayer);
respawningPlayer.getLocation())); Location respawnLocation = teleporter.getExit();
event.setRespawnLocation(respawnLocation);
//Try and force the player if for some reason the changing of respawn location isn't properly handled
Bukkit.getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(), () ->
respawningPlayer.teleport(respawnLocation), 1);
//Properly close the portal to prevent it from staying in a locked state until it times out //Properly close the portal to prevent it from staying in a locked state until it times out
exitPortal.getPortalOpener().closePortal(false); exitPortal.getPortalOpener().closePortal(false);
Stargate.debug("PortalEventListener::onRespawn", "Overwriting respawn for " + respawningPlayer +
" to " + respawnLocation.getWorld() + ":" + respawnLocation);
} }
} }

View File

@ -3,11 +3,10 @@ package net.knarcraft.stargate.listener;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler; import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.teleporter.Teleporter;
import net.knarcraft.stargate.portal.teleporter.VehicleTeleporter; import net.knarcraft.stargate.portal.teleporter.VehicleTeleporter;
import net.knarcraft.stargate.utility.EconomyHelper; import net.knarcraft.stargate.utility.EconomyHelper;
import net.knarcraft.stargate.utility.EntityHelper; import net.knarcraft.stargate.utility.EntityHelper;
import net.knarcraft.stargate.utility.PermissionHelper; import net.knarcraft.stargate.utility.TeleportHelper;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Vehicle; import org.bukkit.entity.Vehicle;
@ -62,11 +61,11 @@ public class VehicleEventListener implements Listener {
private static void teleportVehicle(List<Entity> passengers, Portal entrancePortal, Vehicle vehicle) { private static void teleportVehicle(List<Entity> passengers, Portal entrancePortal, Vehicle vehicle) {
String route = "VehicleEventListener::teleportVehicle"; String route = "VehicleEventListener::teleportVehicle";
if (!passengers.isEmpty() && passengers.get(0) instanceof Player) { if (!passengers.isEmpty() && TeleportHelper.containsPlayer(passengers)) {
Stargate.debug(route, "Found passenger vehicle"); Stargate.debug(route, "Found passenger vehicle");
teleportPlayerAndVehicle(entrancePortal, vehicle, passengers); teleportPlayerAndVehicle(entrancePortal, vehicle);
} else { } else {
Stargate.debug(route, "Found empty vehicle"); Stargate.debug(route, "Found vehicle without players");
Portal destinationPortal = entrancePortal.getPortalActivator().getDestination(); Portal destinationPortal = entrancePortal.getPortalActivator().getDestination();
if (destinationPortal == null) { if (destinationPortal == null) {
Stargate.debug(route, "Unable to find portal destination"); Stargate.debug(route, "Unable to find portal destination");
@ -74,7 +73,7 @@ public class VehicleEventListener implements Listener {
} }
Stargate.debug("vehicleTeleport", destinationPortal.getWorld() + " " + Stargate.debug("vehicleTeleport", destinationPortal.getWorld() + " " +
destinationPortal.getSignLocation()); destinationPortal.getSignLocation());
new VehicleTeleporter(destinationPortal, vehicle).teleport(entrancePortal); new VehicleTeleporter(destinationPortal, vehicle).teleportEntity(entrancePortal);
} }
} }
@ -83,98 +82,66 @@ public class VehicleEventListener implements Listener {
* *
* @param entrancePortal <p>The portal the minecart entered</p> * @param entrancePortal <p>The portal the minecart entered</p>
* @param vehicle <p>The vehicle to teleport</p> * @param vehicle <p>The vehicle to teleport</p>
* @param passengers <p>Any entities sitting in the minecart</p>
*/ */
private static void teleportPlayerAndVehicle(Portal entrancePortal, Vehicle vehicle, List<Entity> passengers) { private static void teleportPlayerAndVehicle(Portal entrancePortal, Vehicle vehicle) {
Player player = (Player) passengers.get(0); Entity rootEntity = vehicle;
//On the assumption that a non-player cannot sit in the driver's seat and since some portals can only be open while (rootEntity.getVehicle() != null) {
// to one player at a time, we only need to check if the portal is open to the driver. rootEntity = rootEntity.getVehicle();
if (!entrancePortal.getPortalOpener().isOpenFor(player)) { }
if (!entrancePortal.getOptions().isSilent()) { List<Player> players = TeleportHelper.getPlayers(rootEntity.getPassengers());
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg")); Portal destinationPortal = null;
for (Player player : players) {
//The entrance portal must be open for one player for the teleportation to happen
if (!entrancePortal.getPortalOpener().isOpenFor(player)) {
continue;
} }
return;
}
//If no destination exists, the teleportation cannot happen //Check if any of the players has selected the destination
Portal destinationPortal = entrancePortal.getPortalActivator().getDestination(player); Portal possibleDestinationPortal = entrancePortal.getPortalActivator().getDestination(player);
if (destinationPortal == null) { if (possibleDestinationPortal != null) {
return; destinationPortal = possibleDestinationPortal;
}
//Make sure all player passengers are allowed to, and can afford to, enter the portal
for (Entity entity : passengers) {
if (entity instanceof Player && !playerCanTeleport((Player) entity, entrancePortal, destinationPortal)) {
return;
} }
} }
//To prevent the case where the first passenger pays and then the second passenger is denied, this has to be //Cancel the teleport if no players activated the portal, or if any players are denied access
// run after it has been confirmed that all passengers are able to pay boolean cancelTeleport = false;
int cost = EconomyHelper.getUseCost(player, entrancePortal, destinationPortal); for (Player player : players) {
if (cost > 0) { if (destinationPortal == null) {
if (!takePlayerPayment(passengers, entrancePortal, cost)) { cancelTeleport = true;
return; if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("invalidMsg"));
}
} else if (!TeleportHelper.playerCanTeleport(player, entrancePortal, destinationPortal)) {
cancelTeleport = true;
}
}
if (cancelTeleport) {
return;
}
//Take payment from all players
for (Player player : players) {
//To prevent the case where the first passenger pays and then the second passenger is denied, this has to be
// run after it has been confirmed that all passengers are able to pay
int cost = EconomyHelper.getUseCost(player, entrancePortal, destinationPortal);
if (cost > 0) {
if (EconomyHelper.cannotPayTeleportFee(entrancePortal, player, cost)) {
return;
}
} }
} }
//Teleport the vehicle and inform the user if the vehicle was teleported //Teleport the vehicle and inform the user if the vehicle was teleported
boolean teleported = new VehicleTeleporter(destinationPortal, vehicle).teleport(entrancePortal); boolean teleported = new VehicleTeleporter(destinationPortal, vehicle).teleportEntity(entrancePortal);
if (teleported) { if (teleported) {
if (!entrancePortal.getOptions().isSilent()) { if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg")); for (Player player : players) {
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
}
} }
entrancePortal.getPortalOpener().closePortal(false); entrancePortal.getPortalOpener().closePortal(false);
} }
} }
/**
* Takes payment from all player passengers
*
* @param passengers <p>All passengers in the teleporting vehicle</p>
* @param entrancePortal <p>The portal the vehicle is entering from</p>
* @param cost <p>The cost each player has to pay</p>
* @return <p>True if all player passengers paid successfully</p>
*/
private static boolean takePlayerPayment(List<Entity> passengers, Portal entrancePortal, int cost) {
for (Entity entity : passengers) {
//If the passenger is a player, make it pay
if (entity instanceof Player && EconomyHelper.cannotPayTeleportFee(entrancePortal, (Player) entity, cost)) {
return false;
}
}
return true;
}
/**
* Checks whether the given player is allowed to and can afford to teleport
*
* @param player <p>The player trying to teleport</p>
* @param entrancePortal <p>The portal the player is entering</p>
* @param destinationPortal <p>The portal the player is to exit from</p>
* @return <p>True if the player is allowed to teleport and is able to pay necessary fees</p>
*/
private static boolean playerCanTeleport(Player player, Portal entrancePortal, Portal destinationPortal) {
//Make sure the user can access the portal
if (PermissionHelper.cannotAccessPortal(player, entrancePortal, destinationPortal)) {
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
}
entrancePortal.getPortalOpener().closePortal(false);
return false;
}
//Check if the player is able to afford the teleport fee
int cost = EconomyHelper.getUseCost(player, entrancePortal, destinationPortal);
boolean canAffordFee = cost <= 0 || Stargate.getEconomyConfig().canAffordFee(player, cost);
if (!canAffordFee) {
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("ecoInFunds"));
}
return false;
}
return Teleporter.noLeashedCreaturesPreventTeleportation(player);
}
} }

View File

@ -46,4 +46,5 @@ public class WorldEventListener implements Listener {
PortalRegistry.clearPortals(world); PortalRegistry.clearPortals(world);
} }
} }
} }

View File

@ -349,4 +349,5 @@ public class Portal {
return cleanNetwork.equalsIgnoreCase(other.cleanNetwork); return cleanNetwork.equalsIgnoreCase(other.cleanNetwork);
} }
} }
} }

View File

@ -448,4 +448,5 @@ public class PortalHandler {
} }
return input.replaceAll("[|:#]", "").trim(); return input.replaceAll("[|:#]", "").trim();
} }
} }

View File

@ -1,6 +1,7 @@
package net.knarcraft.stargate.portal; package net.knarcraft.stargate.portal;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.DynmapManager;
import net.knarcraft.stargate.container.BlockLocation; import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.utility.PortalFileHelper; import net.knarcraft.stargate.utility.PortalFileHelper;
import org.bukkit.World; import org.bukkit.World;
@ -224,6 +225,7 @@ public class PortalRegistry {
PortalFileHelper.saveAllPortals(portal.getWorld()); PortalFileHelper.saveAllPortals(portal.getWorld());
portal.setRegistered(false); portal.setRegistered(false);
DynmapManager.removePortalMarker(portal);
} }
/** /**
@ -289,6 +291,7 @@ public class PortalRegistry {
allPortals.add(portal); allPortals.add(portal);
portal.setRegistered(true); portal.setRegistered(true);
DynmapManager.addPortalMarker(portal);
} }
} }

View File

@ -1,9 +1,7 @@
package net.knarcraft.stargate.portal.teleporter; package net.knarcraft.stargate.portal.teleporter;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.event.StargateEntityPortalEvent; import net.knarcraft.stargate.event.StargateEntityPortalEvent;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import org.bukkit.Location;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
/** /**
@ -16,10 +14,10 @@ public class EntityTeleporter extends Teleporter {
/** /**
* Instantiates a new portal teleporter * Instantiates a new portal teleporter
* *
* @param portal <p>The portal which is the target of the teleportation</p> * @param targetPortal <p>The portal which is the target of the teleportation</p>
*/ */
public EntityTeleporter(Portal portal, Entity teleportingEntity) { public EntityTeleporter(Portal targetPortal, Entity teleportingEntity) {
super(portal); super(targetPortal, teleportingEntity);
this.teleportingEntity = teleportingEntity; this.teleportingEntity = teleportingEntity;
} }
@ -29,44 +27,8 @@ public class EntityTeleporter extends Teleporter {
* @param origin <p>The portal the entity is teleporting from</p> * @param origin <p>The portal the entity is teleporting from</p>
* @return <p>True if the entity was teleported. False otherwise</p> * @return <p>True if the entity was teleported. False otherwise</p>
*/ */
public boolean teleport(Portal origin) { public boolean teleportEntity(Portal origin) {
Location traveller = teleportingEntity.getLocation(); return teleport(origin, new StargateEntityPortalEvent(teleportingEntity, origin, portal, exit));
Location exit = getExit(teleportingEntity, traveller);
//Rotate the entity to face out from the portal
adjustRotation(exit);
//Call the StargateEntityPortalEvent to allow plugins to change destination
if (!origin.equals(portal)) {
exit = triggerEntityPortalEvent(origin, exit);
if (exit == null) {
return false;
}
}
//Load chunks to make sure not to teleport to the void
loadChunks();
teleportingEntity.teleport(exit);
return true;
} }
/**
* Triggers the entity portal event to allow plugins to change the exit location
*
* @param origin <p>The origin portal teleported from</p>
* @param exit <p>The exit location to teleport the entity to</p>
* @return <p>The location the entity should be teleported to, or null if the event was cancelled</p>
*/
protected Location triggerEntityPortalEvent(Portal origin, Location exit) {
StargateEntityPortalEvent stargateEntityPortalEvent = new StargateEntityPortalEvent(teleportingEntity, origin,
portal, exit);
Stargate.getInstance().getServer().getPluginManager().callEvent(stargateEntityPortalEvent);
//Teleport is cancelled. Teleport the entity back to where it came from just for sanity's sake
if (stargateEntityPortalEvent.isCancelled()) {
new EntityTeleporter(origin, teleportingEntity).teleport(origin);
return null;
}
return stargateEntityPortalEvent.getExit();
}
} }

View File

@ -3,9 +3,15 @@ package net.knarcraft.stargate.portal.teleporter;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.event.StargatePlayerPortalEvent; import net.knarcraft.stargate.event.StargatePlayerPortalEvent;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import org.bukkit.Location; import net.knarcraft.stargate.utility.DirectionHelper;
import net.knarcraft.stargate.utility.TeleportHelper;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.util.Vector;
import java.util.List;
/** /**
* The portal teleporter takes care of the actual portal teleportation for any players * The portal teleporter takes care of the actual portal teleportation for any players
@ -17,11 +23,11 @@ public class PlayerTeleporter extends Teleporter {
/** /**
* Instantiates a new player teleporter * Instantiates a new player teleporter
* *
* @param portal <p>The portal which is the target of the teleportation</p> * @param targetPortal <p>The portal which is the target of the teleportation</p>
* @param player <p>The teleporting player</p> * @param player <p>The teleporting player</p>
*/ */
public PlayerTeleporter(Portal portal, Player player) { public PlayerTeleporter(Portal targetPortal, Player player) {
super(portal); super(targetPortal, player);
this.player = player; this.player = player;
} }
@ -31,53 +37,42 @@ public class PlayerTeleporter extends Teleporter {
* @param origin <p>The portal the player teleports from</p> * @param origin <p>The portal the player teleports from</p>
* @param event <p>The player move event triggering the event</p> * @param event <p>The player move event triggering the event</p>
*/ */
public void teleport(Portal origin, PlayerMoveEvent event) { public void teleportPlayer(Portal origin, PlayerMoveEvent event) {
Location traveller = player.getLocation(); double velocity = player.getVelocity().length();
Location exit = getExit(player, traveller); List<Entity> passengers = player.getPassengers();
//Rotate the player to face out from the portal
adjustRotation(exit);
//Call the StargatePlayerPortalEvent to allow plugins to change destination //Call the StargatePlayerPortalEvent to allow plugins to change destination
if (!origin.equals(portal)) { if (!origin.equals(portal)) {
exit = triggerPlayerPortalEvent(origin, exit, event); exit = triggerPortalEvent(origin, new StargatePlayerPortalEvent(player, origin, portal, exit));
if (exit == null) { if (exit == null) {
return; return;
} }
} }
//Calculate the exit velocity of the player
Vector newVelocityDirection = DirectionHelper.getDirectionVectorFromYaw(portal.getYaw());
Vector newVelocity = newVelocityDirection.multiply(velocity * Stargate.getGateConfig().getExitVelocity());
//Load chunks to make sure not to teleport to the void //Load chunks to make sure not to teleport to the void
loadChunks(); loadChunks();
//Teleport any creatures leashed by the player in a 15-block range //Teleport any creatures leashed by the player in a 15-block range
teleportLeashedCreatures(player, origin); TeleportHelper.teleportLeashedCreatures(player, origin, portal);
if (player.eject()) {
TeleportHelper.handleEntityPassengers(passengers, player, origin, portal, exit.getDirection(), newVelocity);
}
//If no event is passed in, assume it's a teleport, and act as such //If no event is passed in, assume it's a teleport, and act as such
if (event == null) { if (event == null) {
player.teleport(exit); player.teleport(exit);
} else { } else {
//The new method to teleport in a move event is set the "to" field. //Set the exit location of the event
event.setTo(exit); event.setTo(exit);
} }
}
/** //Set the velocity of the teleported player after the teleportation is finished
* Triggers the player portal event to allow plugins to change the exit location Bukkit.getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(), () -> player.setVelocity(newVelocity), 1);
*
* @param origin <p>The origin portal teleported from</p>
* @param exit <p>The exit location to teleport the player to</p>
* @param event <p>The player move event which triggered the teleportation</p>
* @return <p>The location the player should be teleported to, or null if the event was cancelled</p>
*/
private Location triggerPlayerPortalEvent(Portal origin, Location exit, PlayerMoveEvent event) {
StargatePlayerPortalEvent stargatePlayerPortalEvent = new StargatePlayerPortalEvent(player, origin, portal, exit);
Stargate.getInstance().getServer().getPluginManager().callEvent(stargatePlayerPortalEvent);
//Teleport is cancelled. Teleport the player back to where it came from
if (stargatePlayerPortalEvent.isCancelled()) {
new PlayerTeleporter(origin, player).teleport(origin, event);
return null;
}
return stargatePlayerPortalEvent.getExit();
} }
} }

View File

@ -4,9 +4,11 @@ import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.BlockLocation; import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.container.ChunkUnloadRequest; import net.knarcraft.stargate.container.ChunkUnloadRequest;
import net.knarcraft.stargate.container.RelativeBlockVector; import net.knarcraft.stargate.container.RelativeBlockVector;
import net.knarcraft.stargate.event.StargateTeleportEvent;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.utility.DirectionHelper; import net.knarcraft.stargate.utility.DirectionHelper;
import net.knarcraft.stargate.utility.EntityHelper; import net.knarcraft.stargate.utility.EntityHelper;
import net.knarcraft.stargate.utility.TeleportHelper;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
@ -14,10 +16,10 @@ import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Slab; import org.bukkit.block.data.type.Slab;
import org.bukkit.entity.AbstractHorse; import org.bukkit.entity.AbstractHorse;
import org.bukkit.entity.Creature;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.event.Event;
import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.util.Vector;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -31,71 +33,114 @@ public abstract class Teleporter {
* The portal the entity is teleporting to * The portal the entity is teleporting to
*/ */
protected final Portal portal; protected final Portal portal;
/** /**
* The scheduler to use for delaying tasks * The scheduler to use for delaying tasks
*/ */
protected final BukkitScheduler scheduler; protected final BukkitScheduler scheduler;
/**
* The exit location any entities will be teleported to
*/
protected Location exit;
/**
* The entity being teleported by this teleporter
*/
protected final Entity teleportedEntity;
/** /**
* Instantiates a new portal teleporter * Instantiates a new portal teleporter
* *
* @param portal <p>The portal which is the target of the teleportation</p> * @param portal <p>The portal which is the target of the teleportation</p>
* @param teleportedEntity <p>The entity teleported by this teleporter</p>
*/ */
public Teleporter(Portal portal) { public Teleporter(Portal portal, Entity teleportedEntity) {
this.portal = portal; this.portal = portal;
this.scheduler = Stargate.getInstance().getServer().getScheduler(); this.scheduler = Stargate.getInstance().getServer().getScheduler();
this.teleportedEntity = teleportedEntity;
this.exit = getExit(teleportedEntity);
} }
/**
* Teleports an entity
*
* @param origin <p>The portal the entity teleported from</p>
* @param stargateTeleportEvent <p>The event to call to make sure the teleportation is valid</p>
* @return <p>True if the teleportation was successfully performed</p>
*/
public boolean teleport(Portal origin, StargateTeleportEvent stargateTeleportEvent) {
List<Entity> passengers = teleportedEntity.getPassengers();
//Call the StargateEntityPortalEvent to allow plugins to change destination
if (!origin.equals(portal)) {
exit = triggerPortalEvent(origin, stargateTeleportEvent);
if (exit == null) {
return false;
}
}
//Load chunks to make sure not to teleport to the void
loadChunks();
if (teleportedEntity.eject()) {
TeleportHelper.handleEntityPassengers(passengers, teleportedEntity, origin, portal, exit.getDirection(),
new Vector());
}
teleportedEntity.teleport(exit);
return true;
}
/**
* Gets the exit location of this teleporter
*
* @return <p>The exit location of this teleporter</p>
*/
public Location getExit() {
return exit.clone();
}
/**
* Triggers the entity portal event to allow plugins to change the exit location
*
* @param origin <p>The origin portal teleported from</p>
* @param stargateTeleportEvent <p>The exit location to teleport the entity to</p>
* @return <p>The location the entity should be teleported to, or null if the event was cancelled</p>
*/
protected Location triggerPortalEvent(Portal origin, StargateTeleportEvent stargateTeleportEvent) {
Stargate.getInstance().getServer().getPluginManager().callEvent((Event) stargateTeleportEvent);
//Teleport is cancelled. Teleport the entity back to where it came from just for sanity's sake
if (stargateTeleportEvent.isCancelled()) {
new EntityTeleporter(origin, teleportedEntity).teleportEntity(origin);
return null;
}
return stargateTeleportEvent.getExit();
}
/** /**
* Adjusts the rotation of the exit to make the teleporting entity face directly out from the portal * Adjusts the rotation of the exit to make the teleporting entity face directly out from the portal
* *
* @param exit <p>The location the entity will exit from</p> * @param exit <p>The location the entity will exit from</p>
*/ */
protected void adjustRotation(Location exit) { protected void adjustExitLocationRotation(Location exit) {
int adjust = 0; int adjust = 0;
if (portal.getOptions().isBackwards()) { if (portal.getOptions().isBackwards()) {
adjust = 180; adjust = 180;
} }
float newYaw = (portal.getYaw() + adjust) % 360; float newYaw = (portal.getYaw() + adjust) % 360;
Stargate.debug("Portal::adjustRotation", "Setting exit yaw to " + newYaw); Stargate.debug("Portal::adjustRotation", "Setting exit yaw to " + newYaw);
exit.setYaw(newYaw); exit.setDirection(DirectionHelper.getDirectionVectorFromYaw(newYaw));
} }
/** /**
* Gets the exit location for a given entity and current location * Loads the chunks outside the portal's entrance
*
* @param entity <p>The entity to teleport (used to determine distance from portal to avoid suffocation)</p>
* @param traveller <p>The location of the entity travelling</p>
* @return <p>The location the entity should be teleported to.</p>
*/ */
public Location getExit(Entity entity, Location traveller) { protected void loadChunks() {
Location exitLocation = null; for (Chunk chunk : getChunksToLoad()) {
RelativeBlockVector relativeExit = portal.getGate().getLayout().getExit(); chunk.addPluginChunkTicket(Stargate.getInstance());
if (relativeExit != null) { //Allow the chunk to unload after 10 seconds
BlockLocation exit = portal.getBlockAt(relativeExit); Stargate.addChunkUnloadRequest(new ChunkUnloadRequest(chunk, 10000L));
//Move one block out to prevent exiting inside the portal
float portalYaw = portal.getYaw();
if (portal.getOptions().isBackwards()) {
portalYaw += 180;
}
exitLocation = exit.getRelativeLocation(0D, 0D, 1, portalYaw);
if (entity != null) {
double entitySize = EntityHelper.getEntityMaxSize(entity);
//Prevent exit suffocation for players riding horses or similar
if (entitySize > 1) {
exitLocation = preventExitSuffocation(relativeExit, exitLocation, entity);
}
}
} else {
Stargate.logWarning(String.format("Missing destination point in .gate file %s",
portal.getGate().getFilename()));
} }
//Adjust pitch and height
return adjustExitLocation(traveller, exitLocation);
} }
/** /**
@ -141,7 +186,7 @@ public abstract class Teleporter {
if (entitySize > 1) { if (entitySize > 1) {
double entityOffset; double entityOffset;
if (portal.getOptions().isAlwaysOn()) { if (portal.getOptions().isAlwaysOn()) {
entityOffset = entityBoxSize / 2D; entityOffset = (entityBoxSize / 2D);
} else { } else {
entityOffset = (entitySize / 2D) - 1; entityOffset = (entitySize / 2D) - 1;
} }
@ -185,41 +230,62 @@ public abstract class Teleporter {
* slab check is necessary to prevent the player from clipping through the slab and spawning beneath it. The water * slab check is necessary to prevent the player from clipping through the slab and spawning beneath it. The water
* check is necessary when teleporting boats to prevent it from becoming a submarine.</p> * check is necessary when teleporting boats to prevent it from becoming a submarine.</p>
* *
* @param traveller <p>The location of the travelling entity</p> * @param entity <p>The travelling entity</p>
* @param exitLocation <p>The exit location generated</p> * @param exitLocation <p>The exit location generated</p>
* @return <p>The location the travelling entity should be teleported to</p> * @return <p>The location the travelling entity should be teleported to</p>
*/ */
private Location adjustExitLocation(Location traveller, Location exitLocation) { private Location adjustExitLocationHeight(Entity entity, Location exitLocation) {
if (exitLocation != null) { if (exitLocation != null) {
BlockData blockData = exitLocation.getBlock().getBlockData(); BlockData blockData = exitLocation.getBlock().getBlockData();
if ((blockData instanceof Bisected bisected && bisected.getHalf() == Bisected.Half.BOTTOM) || if ((blockData instanceof Bisected bisected && bisected.getHalf() == Bisected.Half.BOTTOM) ||
(blockData instanceof Slab slab && slab.getType() == Slab.Type.BOTTOM)) { (blockData instanceof Slab slab && slab.getType() == Slab.Type.BOTTOM) ||
//Prevent traveller from spawning inside a slab blockData.getMaterial() == Material.WATER) {
Stargate.debug("adjustExitLocation", "Added a block to get above a slab"); //Prevent traveller from spawning inside a slab, or a boat from spawning inside water
exitLocation.add(0, 1, 0); Stargate.debug("adjustExitLocation", "Added a block to get above a slab or a block of water");
} else if (blockData.getMaterial() == Material.WATER) {
//If there's water outside, go one up to allow for boat teleportation
Stargate.debug("adjustExitLocation", "Added a block to get above a block of water");
exitLocation.add(0, 1, 0); exitLocation.add(0, 1, 0);
} }
exitLocation.setPitch(traveller.getPitch());
return exitLocation; return exitLocation;
} else { } else {
Stargate.logWarning("Unable to generate exit location"); Stargate.logWarning("Unable to generate exit location");
return traveller; return entity.getLocation();
} }
} }
/** /**
* Loads the chunks outside the portal's entrance * Gets the exit location for a given entity and current location
*
* @param entity <p>The entity to teleport (used to determine distance from portal to avoid suffocation)</p>
* @return <p>The location the entity should be teleported to.</p>
*/ */
protected void loadChunks() { private Location getExit(Entity entity) {
for (Chunk chunk : getChunksToLoad()) { Location exitLocation = null;
chunk.addPluginChunkTicket(Stargate.getInstance()); RelativeBlockVector relativeExit = portal.getGate().getLayout().getExit();
//Allow the chunk to unload after 3 seconds if (relativeExit != null) {
Stargate.addChunkUnloadRequest(new ChunkUnloadRequest(chunk, 3000L)); BlockLocation exit = portal.getBlockAt(relativeExit);
//Move one block out to prevent exiting inside the portal
float portalYaw = portal.getYaw();
if (portal.getOptions().isBackwards()) {
portalYaw += 180;
}
exitLocation = exit.getRelativeLocation(0D, 0D, 1, portalYaw);
if (entity != null) {
double entitySize = EntityHelper.getEntityMaxSize(entity);
//Prevent exit suffocation for players riding horses or similar
if (entitySize > 1) {
exitLocation = preventExitSuffocation(relativeExit, exitLocation, entity);
}
}
} else {
Stargate.logWarning(String.format("Missing destination point in .gate file %s",
portal.getGate().getFilename()));
} }
//Adjust height and rotation
Location adjusted = adjustExitLocationHeight(entity, exitLocation);
adjustExitLocationRotation(adjusted);
return adjusted;
} }
/** /**
@ -250,76 +316,4 @@ public abstract class Teleporter {
return chunksToLoad; return chunksToLoad;
} }
/**
* Checks whether a player has leashed creatures that block the teleportation
*
* @param player <p>The player trying to teleport</p>
* @return <p>False if the player has leashed any creatures that cannot go through the portal</p>
*/
public static boolean noLeashedCreaturesPreventTeleportation(Player player) {
//Find any nearby leashed entities to teleport with the player
List<Creature> nearbyCreatures = getLeashedCreatures(player);
//Disallow creatures with passengers to prevent smuggling
for (Creature creature : nearbyCreatures) {
if (!creature.getPassengers().isEmpty()) {
return false;
}
}
//If it's enabled, there is no problem
if (Stargate.getGateConfig().handleLeashedCreatures()) {
return true;
} else {
return nearbyCreatures.isEmpty();
}
}
/**
* Teleports any creatures leashed by the player
*
* <p>Will return false if the teleportation should be aborted because the player has leashed creatures that
* aren't allowed to be teleported with the player.</p>
*
* @param player <p>The player which is teleported</p>
* @param origin <p>The portal the player is teleporting from</p>
*/
protected void teleportLeashedCreatures(Player player, Portal origin) {
//If this feature is disabled, just return
if (!Stargate.getGateConfig().handleLeashedCreatures()) {
return;
}
//Find any nearby leashed entities to teleport with the player
List<Creature> nearbyEntities = getLeashedCreatures(player);
//Teleport all creatures leashed by the player to the portal the player is to exit from
for (Creature creature : nearbyEntities) {
creature.setLeashHolder(null);
scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> {
new EntityTeleporter(portal, creature).teleport(origin);
scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> creature.setLeashHolder(player), 6);
}, 2);
}
}
/**
* Gets all creatures leashed by a player within the given range
*
* @param player <p>The player to check</p>
* @return <p>A list of all creatures the player is holding in a leash (lead)</p>
*/
protected static List<Creature> getLeashedCreatures(Player player) {
List<Creature> leashedCreatures = new ArrayList<>();
//Find any nearby leashed entities to teleport with the player
List<Entity> nearbyEntities = player.getNearbyEntities(15, 15, 15);
//Teleport all creatures leashed by the player to the portal the player is to exit from
for (Entity entity : nearbyEntities) {
if (entity instanceof Creature creature && creature.isLeashed() && creature.getLeashHolder() == player) {
leashedCreatures.add(creature);
}
}
return leashedCreatures;
}
} }

View File

@ -2,14 +2,17 @@ package net.knarcraft.stargate.portal.teleporter;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.StargateGateConfig; import net.knarcraft.stargate.config.StargateGateConfig;
import net.knarcraft.stargate.event.StargateEntityPortalEvent;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.utility.DirectionHelper; import net.knarcraft.stargate.utility.DirectionHelper;
import net.knarcraft.stargate.utility.TeleportHelper;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.entity.Boat;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Vehicle; import org.bukkit.entity.Vehicle;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import java.util.List; import java.util.List;
@ -24,11 +27,11 @@ public class VehicleTeleporter extends EntityTeleporter {
/** /**
* Instantiates a new vehicle teleporter * Instantiates a new vehicle teleporter
* *
* @param portal <p>The portal which is the target of the teleportation</p> * @param targetPortal <p>The targetPortal which is the target of the teleportation</p>
* @param teleportingVehicle <p>The teleporting vehicle</p> * @param teleportingVehicle <p>The teleporting vehicle</p>
*/ */
public VehicleTeleporter(Portal portal, Vehicle teleportingVehicle) { public VehicleTeleporter(Portal targetPortal, Vehicle teleportingVehicle) {
super(portal, teleportingVehicle); super(targetPortal, teleportingVehicle);
this.teleportingVehicle = teleportingVehicle; this.teleportingVehicle = teleportingVehicle;
} }
@ -42,28 +45,22 @@ public class VehicleTeleporter extends EntityTeleporter {
* @return <p>True if the vehicle was teleported. False otherwise</p> * @return <p>True if the vehicle was teleported. False otherwise</p>
*/ */
@Override @Override
public boolean teleport(Portal origin) { public boolean teleportEntity(Portal origin) {
Location traveller = teleportingVehicle.getLocation(); Stargate.debug("VehicleTeleporter::teleport", "Preparing to teleport: " + teleportingVehicle);
Location exit = getExit(teleportingVehicle, traveller);
double velocity = teleportingVehicle.getVelocity().length(); double velocity = teleportingVehicle.getVelocity().length();
//Stop and teleport //Stop the vehicle before teleporting
teleportingVehicle.setVelocity(new Vector()); teleportingVehicle.setVelocity(new Vector());
//Get new velocity //Get new velocity
Vector newVelocityDirection = DirectionHelper.getDirectionVectorFromYaw(portal.getYaw()); Vector newVelocityDirection = DirectionHelper.getDirectionVectorFromYaw(portal.getYaw());
Vector newVelocity = newVelocityDirection.multiply(velocity); Vector newVelocity = newVelocityDirection.multiply(velocity);
//Make sure the vehicle points out from the portal
adjustRotation(exit);
//Call the StargateEntityPortalEvent to allow plugins to change destination //Call the StargateEntityPortalEvent to allow plugins to change destination
if (!origin.equals(portal)) { exit = triggerPortalEvent(origin, new StargateEntityPortalEvent(teleportingVehicle, origin, portal, exit));
exit = triggerEntityPortalEvent(origin, exit); if (exit == null) {
if (exit == null) { return false;
return false;
}
} }
//Teleport the vehicle //Teleport the vehicle
@ -89,12 +86,13 @@ public class VehicleTeleporter extends EntityTeleporter {
return false; return false;
} }
if (!(teleportingVehicle instanceof LivingEntity)) { if (!(teleportingVehicle instanceof LivingEntity) &&
Stargate.getGateConfig().enableCraftBookRemoveOnEjectFix()) {
//Teleport a normal vehicle with passengers (minecart or boat) //Teleport a normal vehicle with passengers (minecart or boat)
putPassengersInNewVehicle(passengers, exit, newVelocity, origin); putPassengersInNewVehicle(passengers, exit, newVelocity, origin);
} else { } else {
//Teleport a living vehicle with passengers (pig, horse, donkey, strider) //Teleport a living vehicle with passengers (pig, horse, donkey, strider)
teleportLivingVehicle(exit, passengers, origin); teleportVehicle(passengers, exit, newVelocity, origin);
} }
} else { } else {
//Check if teleportation of empty vehicles is enabled //Check if teleportation of empty vehicles is enabled
@ -118,54 +116,35 @@ public class VehicleTeleporter extends EntityTeleporter {
private boolean vehiclePassengersAllowed(List<Entity> passengers) { private boolean vehiclePassengersAllowed(List<Entity> passengers) {
StargateGateConfig config = Stargate.getGateConfig(); StargateGateConfig config = Stargate.getGateConfig();
//Don't teleport if the vehicle contains a creature and creature transportation is disabled //Don't teleport if the vehicle contains a creature and creature transportation is disabled
if (containsNonPlayer(passengers) && !config.handleCreatureTransportation()) { if (TeleportHelper.containsNonPlayer(passengers) && !config.handleCreatureTransportation()) {
return false; return false;
} }
//Don't teleport if the player does not contain a player and non-player vehicles is disabled //Don't teleport if the player does not contain a player and non-player vehicles is disabled
return containsPlayer(passengers) || config.handleNonPlayerVehicles(); return TeleportHelper.containsPlayer(passengers) || config.handleNonPlayerVehicles();
}
/**
* Checks whether a list of entities contains any non-players
*
* @param entities <p>The list of entities to check</p>
* @return <p>True if at least one entity is not a player</p>
*/
private boolean containsNonPlayer(List<Entity> entities) {
for (Entity entity : entities) {
if (!(entity instanceof Player)) {
return true;
}
}
return false;
}
/**
* Checks whether a list of entities contains at least one player
*
* @param entities <p>The list of entities to check</p>
* @return <p>True if at least one player is present among the passengers</p>
*/
private boolean containsPlayer(List<Entity> entities) {
for (Entity entity : entities) {
if (entity instanceof Player) {
return true;
}
}
return false;
} }
/** /**
* Teleport a vehicle which is not a minecart or a boat * Teleport a vehicle which is not a minecart or a boat
* *
* @param exit <p>The location the vehicle will exit</p> * @param passengers <p>The passengers of the vehicle</p>
* @param passengers <p>The passengers of the vehicle</p> * @param exit <p>The location the vehicle will exit</p>
* @param origin <p>The portal the vehicle teleported from</p> * @param newVelocity <p>The new velocity of the teleported vehicle</p>
* @param origin <p>The portal the vehicle teleported from</p>
*/ */
private void teleportLivingVehicle(Location exit, List<Entity> passengers, Portal origin) { private void teleportVehicle(List<Entity> passengers, Location exit, Vector newVelocity, Portal origin) {
teleportingVehicle.eject(); if (teleportingVehicle.eject()) {
teleportingVehicle.teleport(exit); TeleportHelper.handleEntityPassengers(passengers, teleportingVehicle, origin, portal, exit.getDirection(),
handleVehiclePassengers(passengers, teleportingVehicle, 2, origin); newVelocity);
}
Stargate.debug("VehicleTeleporter::teleportVehicle", "Teleporting " + teleportingVehicle +
" to final location " + exit + " with direction " + exit.getDirection());
teleportingVehicle.teleport(exit, PlayerTeleportEvent.TeleportCause.PLUGIN);
scheduler.scheduleSyncDelayedTask(Stargate.getInstance(),
() -> {
Stargate.debug("VehicleTeleporter::teleportVehicle", "Setting velocity " + newVelocity +
" for vehicle " + teleportingVehicle);
teleportingVehicle.setVelocity(newVelocity);
}, 1);
} }
/** /**
@ -189,52 +168,16 @@ public class VehicleTeleporter extends EntityTeleporter {
} }
//Spawn a new vehicle //Spawn a new vehicle
Vehicle newVehicle = vehicleWorld.spawn(exit, teleportingVehicle.getClass()); Vehicle newVehicle = vehicleWorld.spawn(exit, teleportingVehicle.getClass());
if (teleportingVehicle instanceof Boat boat) {
((Boat) newVehicle).setWoodType(boat.getWoodType());
}
//Remove the old vehicle //Remove the old vehicle
teleportingVehicle.eject(); if (teleportingVehicle.eject()) {
TeleportHelper.handleEntityPassengers(passengers, newVehicle, origin, portal, exit.getDirection(),
newVelocity);
}
teleportingVehicle.remove(); teleportingVehicle.remove();
//Set rotation, add passengers and restore velocity
newVehicle.setRotation(exit.getYaw(), exit.getPitch());
handleVehiclePassengers(passengers, newVehicle, 1, origin);
scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> newVehicle.setVelocity(newVelocity), 1); scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> newVehicle.setVelocity(newVelocity), 1);
} }
/**
* Ejects, teleports and adds all passengers to the target vehicle
*
* @param passengers <p>The passengers to handle</p>
* @param vehicle <p>The vehicle the passengers should be put into</p>
* @param delay <p>The amount of milliseconds to wait before adding the vehicle passengers</p>
* @param origin <p>The portal the vehicle teleported from</p>
*/
private void handleVehiclePassengers(List<Entity> passengers, Vehicle vehicle, long delay, Portal origin) {
for (Entity passenger : passengers) {
passenger.eject();
scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> {
if (passenger instanceof Player player) {
//Teleport any creatures leashed by the player in a 15-block range
teleportLeashedCreatures(player, origin);
}
teleportAndAddPassenger(vehicle, passenger);
}, delay);
}
}
/**
* Teleports and adds a passenger to a vehicle
*
* <p>Teleportation of living vehicles is really buggy if you wait between the teleportation and passenger adding,
* but there needs to be a delay between teleporting the vehicle and teleporting and adding the passenger.</p>
*
* @param targetVehicle <p>The vehicle to add the passenger to</p>
* @param passenger <p>The passenger to teleport and add</p>
*/
private void teleportAndAddPassenger(Vehicle targetVehicle, Entity passenger) {
if (!passenger.teleport(targetVehicle.getLocation())) {
Stargate.debug("handleVehiclePassengers", "Failed to teleport passenger");
}
if (!targetVehicle.addPassenger(passenger)) {
Stargate.debug("handleVehiclePassengers", "Failed to add passenger");
}
}
} }

View File

@ -21,18 +21,22 @@ public class BlockChangeThread implements Runnable {
long sTime = System.nanoTime(); long sTime = System.nanoTime();
//Repeat for at most 0.025 seconds //Repeat for at most 0.025 seconds
while (System.nanoTime() - sTime < 25000000) { while (System.nanoTime() - sTime < 25000000) {
pollQueue(); if (pollQueue()) {
break;
}
} }
} }
/** /**
* Polls the block change request queue for any waiting requests * Polls the block change request queue for any waiting requests
*
* @return <p>True if the queue is empty and it's safe to quit</p>
*/ */
public static void pollQueue() { public static boolean pollQueue() {
//Abort if there's no work to be done //Abort if there's no work to be done
BlockChangeRequest blockChangeRequest = Stargate.getBlockChangeRequestQueue().poll(); BlockChangeRequest blockChangeRequest = Stargate.getBlockChangeRequestQueue().poll();
if (blockChangeRequest == null) { if (blockChangeRequest == null) {
return; return true;
} }
//Change the material of the pulled block //Change the material of the pulled block
@ -46,6 +50,7 @@ public class BlockChangeThread implements Runnable {
//If orientation is relevant, adjust the block's orientation //If orientation is relevant, adjust the block's orientation
orientBlock(block, blockChangeRequest.getAxis()); orientBlock(block, blockChangeRequest.getAxis());
} }
return false;
} }
/** /**

View File

@ -190,7 +190,7 @@ public final class BungeeHelper {
} }
//Teleport the player back to this gate, for sanity's sake //Teleport the player back to this gate, for sanity's sake
new PlayerTeleporter(entrancePortal, player).teleport(entrancePortal, event); new PlayerTeleporter(entrancePortal, player).teleportPlayer(entrancePortal, event);
//Send the SGBungee packet first, it will be queued by BC if required //Send the SGBungee packet first, it will be queued by BC if required
if (!BungeeHelper.sendTeleportationMessage(player, entrancePortal)) { if (!BungeeHelper.sendTeleportationMessage(player, entrancePortal)) {

View File

@ -6,7 +6,14 @@ import org.bukkit.Color;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class ColorHelper { /**
* A helper class for dealing with colors
*/
public final class ColorHelper {
private ColorHelper() {
}
/** /**
* Inverts the given color * Inverts the given color

View File

@ -387,7 +387,7 @@ public final class PermissionHelper {
if (!entrancePortal.getOptions().isSilent()) { if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg")); Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
} }
new PlayerTeleporter(entrancePortal, player).teleport(entrancePortal, event); new PlayerTeleporter(entrancePortal, player).teleportPlayer(entrancePortal, event);
return true; return true;
} }
@ -401,7 +401,7 @@ public final class PermissionHelper {
if (!entrancePortal.getOptions().isSilent()) { if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg")); Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
} }
new PlayerTeleporter(entrancePortal, player).teleport(entrancePortal, event); new PlayerTeleporter(entrancePortal, player).teleportPlayer(entrancePortal, event);
entrancePortal.getPortalOpener().closePortal(false); entrancePortal.getPortalOpener().closePortal(false);
return true; return true;
} }

View File

@ -0,0 +1,247 @@
package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.teleporter.EntityTeleporter;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Creature;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.List;
/**
* A helper class with methods for various teleportation tasks
*
* <p>The teleport helper mainly helps with passengers and leashed creatures</p>
*/
public final class TeleportHelper {
private TeleportHelper() {
}
/**
* Checks whether a player has leashed creatures that block the teleportation
*
* @param player <p>The player trying to teleport</p>
* @return <p>False if the player has leashed any creatures that cannot go through the portal</p>
*/
public static boolean noLeashedCreaturesPreventTeleportation(Player player) {
//Find any nearby leashed entities to teleport with the player
List<Creature> nearbyCreatures = getLeashedCreatures(player);
//Disallow creatures with passengers to prevent smuggling
for (Creature creature : nearbyCreatures) {
if (!creature.getPassengers().isEmpty()) {
return false;
}
}
//TODO: Improve this to account for any players sitting on any of the lead creatures
//If it's enabled, there is no problem
if (Stargate.getGateConfig().handleLeashedCreatures()) {
return true;
} else {
return nearbyCreatures.isEmpty();
}
}
/**
* Gets all creatures leashed by a player within the given range
*
* @param player <p>The player to check</p>
* @return <p>A list of all creatures the player is holding in a leash (lead)</p>
*/
public static List<Creature> getLeashedCreatures(Player player) {
List<Creature> leashedCreatures = new ArrayList<>();
//Find any nearby leashed entities to teleport with the player
List<Entity> nearbyEntities = player.getNearbyEntities(15, 15, 15);
//Teleport all creatures leashed by the player to the portal the player is to exit from
for (Entity entity : nearbyEntities) {
if (entity instanceof Creature creature && creature.isLeashed() && creature.getLeashHolder() == player) {
leashedCreatures.add(creature);
}
}
return leashedCreatures;
}
/**
* Teleports and adds a passenger to an entity
*
* <p>Teleportation of living vehicles is really buggy if you wait between the teleportation and passenger adding,
* but there needs to be a delay between teleporting the vehicle and teleporting and adding the passenger.</p>
*
* @param targetVehicle <p>The entity to add the passenger to</p>
* @param passenger <p>The passenger to teleport and add</p>
* @param exitDirection <p>The direction of any passengers exiting the stargate</p>
* @param newVelocity <p>The new velocity of the teleported passenger</p>
*/
public static void teleportAndAddPassenger(Entity targetVehicle, Entity passenger, Vector exitDirection,
Vector newVelocity) {
Location passengerExit = targetVehicle.getLocation().clone().setDirection(exitDirection);
if (!passenger.teleport(passengerExit)) {
Stargate.debug("TeleportHelper::handleVehiclePassengers", "Failed to teleport passenger" +
passenger);
} else {
Stargate.debug("TeleportHelper::handleVehiclePassengers", "Teleported " + passenger +
" to " + passengerExit);
}
if (!targetVehicle.addPassenger(passenger)) {
Stargate.debug("TeleportHelper::handleVehiclePassengers", "Failed to add passenger" +
passenger);
} else {
Stargate.debug("TeleportHelper::handleVehiclePassengers", "Added passenger " + passenger +
" to " + targetVehicle);
}
Stargate.debug("VehicleTeleporter::teleportVehicle", "Setting velocity " + newVelocity +
" for passenger " + passenger);
passenger.setVelocity(newVelocity);
}
/**
* Ejects, teleports and adds all passengers to the target entity
*
* @param passengers <p>The passengers to handle</p>
* @param entity <p>The entity the passengers should be put into</p
* @param origin <p>The portal the entity teleported from</p>
* @param target <p>The portal the entity is teleporting to</p>
* @param exitRotation <p>The rotation of any passengers exiting the stargate</p>
* @param newVelocity <p>The new velocity of the teleported passengers</p>
*/
public static void handleEntityPassengers(List<Entity> passengers, Entity entity, Portal origin, Portal target,
Vector exitRotation, Vector newVelocity) {
for (Entity passenger : passengers) {
List<Entity> passengerPassengers = passenger.getPassengers();
if (!passengerPassengers.isEmpty()) {
Stargate.debug("Teleporter::handleEntityPassengers", "Found the entities: " +
passengerPassengers + " as passengers of " + entity);
}
if (passenger.eject()) {
//Teleport any passengers of the passenger
handleEntityPassengers(passengerPassengers, passenger, origin, target, exitRotation, newVelocity);
}
Bukkit.getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(), () -> {
if (passenger instanceof Player player) {
//Teleport any creatures leashed by the player in a 15-block range
teleportLeashedCreatures(player, origin, target);
}
teleportAndAddPassenger(entity, passenger, exitRotation, newVelocity);
}, passenger instanceof Player ? Stargate.getGateConfig().waitForPlayerAfterTeleportDelay() : 0);
}
}
/**
* Teleports any creatures leashed by the player
*
* <p>Will return false if the teleportation should be aborted because the player has leashed creatures that
* aren't allowed to be teleported with the player.</p>
*
* @param player <p>The player which is teleported</p>
* @param origin <p>The portal the player is teleporting from</p>
* @param target <p>The portal the player is teleporting to</p>
*/
public static void teleportLeashedCreatures(Player player, Portal origin, Portal target) {
//If this feature is disabled, just return
if (!Stargate.getGateConfig().handleLeashedCreatures()) {
return;
}
BukkitScheduler scheduler = Bukkit.getScheduler();
//Find any nearby leashed entities to teleport with the player
List<Creature> nearbyEntities = TeleportHelper.getLeashedCreatures(player);
//Teleport all creatures leashed by the player to the portal the player is to exit from
for (Creature creature : nearbyEntities) {
creature.setLeashHolder(null);
scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> {
new EntityTeleporter(target, creature).teleportEntity(origin);
scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> creature.setLeashHolder(player),
Stargate.getGateConfig().waitForPlayerAfterTeleportDelay());
}, 2);
}
}
/**
* Checks whether a list of entities or any of their passengers contains any non-players
*
* @param entities <p>The list of entities to check</p>
* @return <p>True if at least one entity is not a player</p>
*/
public static boolean containsNonPlayer(List<Entity> entities) {
for (Entity entity : entities) {
if (!(entity instanceof Player) || containsNonPlayer(entity.getPassengers())) {
return true;
}
}
return false;
}
/**
* Checks whether a list of entities of their passengers contains at least one player
*
* @param entities <p>The list of entities to check</p>
* @return <p>True if at least one player is present among the passengers</p>
*/
public static boolean containsPlayer(List<Entity> entities) {
for (Entity entity : entities) {
if (entity instanceof Player || containsPlayer(entity.getPassengers())) {
return true;
}
}
return false;
}
/**
* Gets all players recursively from a list of entities
*
* @param entities <p>The entities to check for players</p>
* @return <p>The found players</p>
*/
public static List<Player> getPlayers(List<Entity> entities) {
List<Player> players = new ArrayList<>(5);
for (Entity entity : entities) {
if (entity instanceof Player) {
players.add((Player) entity);
}
players.addAll(getPlayers(entity.getPassengers()));
}
return players;
}
/**
* Checks whether the given player is allowed to and can afford to teleport
*
* @param player <p>The player trying to teleport</p>
* @param entrancePortal <p>The portal the player is entering</p>
* @param destinationPortal <p>The portal the player is to exit from</p>
* @return <p>True if the player is allowed to teleport and is able to pay necessary fees</p>
*/
public static boolean playerCanTeleport(Player player, Portal entrancePortal, Portal destinationPortal) {
//Make sure the user can access the portal
if (PermissionHelper.cannotAccessPortal(player, entrancePortal, destinationPortal)) {
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
}
entrancePortal.getPortalOpener().closePortal(false);
return false;
}
//Check if the player is able to afford the teleport fee
int cost = EconomyHelper.getUseCost(player, entrancePortal, destinationPortal);
boolean canAffordFee = cost <= 0 || Stargate.getEconomyConfig().canAffordFee(player, cost);
if (!canAffordFee) {
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("ecoInFunds"));
}
return false;
}
return TeleportHelper.noLeashedCreaturesPreventTeleportation(player);
}
}

View File

@ -1,7 +1,7 @@
# stargate Configuration File # stargate Configuration File
# Main stargate config # Main stargate config
# language - The language file to load for messages # language - The language file to load for messages (de,en,es,fr,hu,it,ja,nb-no,nl,nn-no,pt-br,ru,zh_cn)
language: en language: en
# adminUpdateAlert - Whether to alert admins about new plugin updates # adminUpdateAlert - Whether to alert admins about new plugin updates
adminUpdateAlert: true adminUpdateAlert: true
@ -15,6 +15,8 @@ gates:
maxGatesEachNetwork: 0 maxGatesEachNetwork: 0
# defaultGateNetwork - The default gate network # defaultGateNetwork - The default gate network
defaultGateNetwork: central defaultGateNetwork: central
# exitVelocity - The velocity to give players exiting stargates, relative to the entry velocity
exitVelocity: 0.1
cosmetic: cosmetic:
# rememberDestination - Whether to remember the cursor location between uses # rememberDestination - Whether to remember the cursor location between uses
rememberDestination: false rememberDestination: false
@ -38,7 +40,8 @@ gates:
destroyedByExplosion: false destroyedByExplosion: false
# verifyPortals - Whether all the non-sign blocks are checked to match the gate layout when a stargate is loaded. # verifyPortals - Whether all the non-sign blocks are checked to match the gate layout when a stargate is loaded.
verifyPortals: false verifyPortals: false
# protectEntrance - Whether to protect gate entrance material (More resource intensive. Only enable if using destroyable open/closed material) # protectEntrance - Whether to protect gate entrance material (More resource intensive. Only enable if using
# destroyable open/closed material)
protectEntrance: false protectEntrance: false
functionality: functionality:
enableBungee: false enableBungee: false
@ -46,16 +49,21 @@ gates:
handleVehicles: true handleVehicles: true
# handleEmptyVehicles - Whether to allow empty vehicles through gates (chest/hopper/tnt/furnace minecarts included) # handleEmptyVehicles - Whether to allow empty vehicles through gates (chest/hopper/tnt/furnace minecarts included)
handleEmptyVehicles: true handleEmptyVehicles: true
# handleCreatureTransportation - Whether to allow players to transport creatures by sending vehicles (minecarts, boats) through gates # handleCreatureTransportation - Whether to allow players to transport creatures by sending vehicles (minecarts,
# boats) through gates
handleCreatureTransportation: true handleCreatureTransportation: true
# handleNonPlayerVehicles - Whether to allow vehicles with a passenger which is not a player through gates. handleCreatureTransportation must be enabled # handleNonPlayerVehicles - Whether to allow vehicles with a passenger which is not a player through gates.
# handleCreatureTransportation must be enabled
handleNonPlayerVehicles: true handleNonPlayerVehicles: true
# handleLeashedCreatures - Whether to allow creatures lead by a player to teleport with the player # handleLeashedCreatures - Whether to allow creatures lead by a player to teleport with the player
handleLeashedCreatures: true handleLeashedCreatures: true
# enableCraftBookRemoveOnEjectFix - Whether to enable a fix that causes loss of NBT data, but allows vehicle
# teleportation to work when CraftBook's remove minecart/boat on eject setting is enabled
enableCraftBookRemoveOnEjectFix: false
# I------------I-------------I # # ######################## #
# stargate economy options # # stargate economy options #
# I------------I-------------I # # ######################## #
economy: economy:
# useEconomy - Whether to use an economy plugin # useEconomy - Whether to use an economy plugin
useEconomy: false useEconomy: false
@ -74,11 +82,26 @@ economy:
# freeGatesColor - The color to use for marking free gates # freeGatesColor - The color to use for marking free gates
freeGatesColor: DARK_GREEN freeGatesColor: DARK_GREEN
# I-------I-------I # # ############# #
# Debug options # # Debug options #
# I-------I-------I # # ############# #
debugging: debugging:
# debug - Debug -- Only enable if you have issues, massive console output # debug - Debug -- Only enable if you have issues, massive console output
debug: false debug: false
# permissionDebug - This will output any and all Permissions checks to console, used for permissions debugging (Requires debug: true) # permissionDebug - This will output any and all Permissions checks to console, used for permissions debugging
permissionDebug: false # (Requires debug: true)
permissionDebug: false
advanced:
# waitForPlayerAfterTeleportDelay - The amount of ticks to wait before adding a player as passenger of a vehicle.
# On slow servers, a value of 6 is required to avoid client glitches after teleporting on a vehicle.
waitForPlayerAfterTeleportDelay: 6
# ############## #
# Dynmap options #
# ############## #
dynmap:
# enableDynmap - Whether to display Stargates in Dynmap's map
enableDynmap: true
# dynmapIconsHiddenByDefault - Whether to hide the set of Stargate icons by default, requiring users to
# manually enable them with a checkbox.
dynmapIconsHiddenByDefault: true

View File

@ -0,0 +1,44 @@
author=furplag
prefix=[Stargate]
teleportMsg=テレポート
destroyMsg=ゲートが破壊されました
invalidMsg=無効な行き先
blockMsg=ブロックされた行き先
destEmpty=行き先リストが空です
denyMsg=アクセスが拒否されました
reloaded= Stargate をリロードしました
ecoDeduct=cost の値引き
ecoRefund=cost の返金
ecoObtain= Stargate portal から cost を得ました
ecoInFunds=資金の不足
ecoLoadError= Vault が読み込まれましたが、Economy プラグインをフックできませんでした
vaultLoadError=Economy は有効になっていますが、Vault をロードできないため Economy は無効化されました
vaultLoaded= Vault vversion が見つかりました
createMsg=ゲートが作成されました
createNetDeny=対象のネットワークにアクセスできません
createGateDeny=対象のゲートレイアウトにアクセスできません
createPersonal=パーソナルネットワーク上にゲートを作成する
createNameLength=ゲート名が短すぎるか長すぎます
createExists=すでに存在するゲート名です
createFull=対象のネットワークはいっぱいです
createWorldDeny=あなたはその世界にアクセスできません
createConflict=ゲートが既存のゲートと競合しています
signRightClick=右クリック
signToUse=ゲートを使用する
signRandom=ランダム
signDisconnected=切断
signInvalidGate=無効なゲート
bungeeDisabled=BungeeCord サポートは無効になっています
bungeeDeny=BungeeCord ゲートを作成する権限がありません
bungeeEmpty=BungeeCord ゲートには、行き先とネットワークの両方が必要です
bungeeSign=テレポート先:
portalInfoTitle=[STARGATE INFO]
portalInfoName=ゲート名: name
portalInfoDestination=行き先: destination
portalInfoNetwork=ネットワーク: network
portalInfoServer=サーバー: server

View File

@ -0,0 +1,39 @@
author=YKDZ
signRightClick=右键
ecoLoadError=Vault 已加载, 但未检测到合适的经济插件
createConflict=星门与现有星门冲突
invalidMsg=无效的目的地
prefix=[星门]
ecoObtain=从星门 %portal% 收取了 %cost%
vaultLoaded=检测到 Vault v%version%
reloaded=星门插件已重载
bungeeDeny=你没有创建跨服星门的权限.
signToUse=以使用星门
signInvalidGate=未知星门
bungeeEmpty=跨服星门需要提供目的地和网络.
createMsg=星门已创建
bungeeDisabled=跨服功能已被禁用.
blockMsg=目的地被阻挡
ecoInFunds=余额不足
createNameLength=名称过短或过长.
vaultLoadError=未检测到Vault. 经济模块已禁用
denyMsg=访问被拒
ecoDeduct=花费 %cost%
signDisconnected=已取消链接
createNetDeny=你没有这个星门网络的许可
bungeeSign=传送到
portalInfoName=名称: %name%
destroyMsg=星门已被破坏
portalInfoTitle=[星门信息]
createExists=与已有星门重名
teleportMsg=已传送
createGateDeny=你没有使用这个星门结构的权限
signRandom=随机
portalInfoServer=服务器: %server%
createWorldDeny=你没有链接这个世界的权限
portalInfoDestination=目的地: %destination%
portalInfoNetwork=星门网络: %network%
destEmpty=目的地列表为空
createPersonal=在私人网络中创建星门
ecoRefund=退款 %cost%
createFull=此星门网络已满

View File

@ -1,12 +1,12 @@
name: Stargate name: Stargate
main: net.knarcraft.stargate.Stargate main: net.knarcraft.stargate.Stargate
version: 0.9.3.1 version: 0.9.4.1
description: Stargate mod for Bukkit Revived description: Stargate mod for Bukkit Revived
author: EpicKnarvik97 author: EpicKnarvik97
authors: [ Drakia, PseudoKnight, EpicKnarvik97 ] authors: [ Drakia, PseudoKnight, EpicKnarvik97 ]
website: https://git.knarcraft.net/EpicKnarvik97/Stargate website: https://git.knarcraft.net/EpicKnarvik97/Stargate
api-version: 1.18 api-version: 1.18
softdepend: [ Vault ] softdepend: [ Vault, dynmap ]
commands: commands:
stargate: stargate:
aliases: aliases: