diff --git a/HEADER b/HEADER
new file mode 100644
index 0000000..126ab6a
--- /dev/null
+++ b/HEADER
@@ -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
+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 .
\ No newline at end of file
diff --git a/README.md b/README.md
index ae308f4..05785ef 100644
--- a/README.md
+++ b/README.md
@@ -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.
- **Ability to create custom gate configurations**. Four different default gate configurations are available.
- **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)
- **Vehicle teleportation** -- teleport minecarts, boats, horses, pigs and striders
- **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
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
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
```
-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
folders:
portalFolder - The folder your portal databases are saved in
@@ -306,6 +311,7 @@ folders:
gates:
maxGatesEachNetwork - If non-zero, will define the maximum amount of gates allowed on any 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:
rememberDestination - Whether to set the first destination as the last used destination for all gates
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.
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.
+ 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:
useEconomy - Whether or not to enable Economy using Vault (must have the Vault plugin)
createCost - The cost to create a stargate
@@ -335,11 +342,13 @@ economy:
debugging:
debug - Whether to show massive 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
-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.
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
+#### \[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
- Ignores the type of air when checking if a stargate is valid
diff --git a/pom.xml b/pom.xml
index 2dfda2c..313190c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
net.knarcraft
Stargate
- 0.9.3.1
+ 0.9.4.1
@@ -28,13 +28,17 @@
vault-repo
http://nexus.hc.to/content/repositories/pub_releases
+
+ dynmap
+ https://repo.mikeprimm.com/
+
org.spigotmc
spigot-api
- 1.18.1-R0.1-SNAPSHOT
+ 1.19-R0.1-SNAPSHOT
net.milkbowl.vault
@@ -44,27 +48,32 @@
org.junit.jupiter
junit-jupiter-api
- 5.8.0-M1
+ 5.8.2
test
com.github.seeseemelk
MockBukkit-v1.18
- 1.14.0
+ 1.15.5
test
org.jetbrains
annotations
- 19.0.0
+ 22.0.0
compile
junit
junit
- 4.13.1
+ 4.13.2
test
+
+ us.dynmap
+ dynmap-api
+ 3.1-beta-2
+
diff --git a/src/main/java/net/knarcraft/stargate/Stargate.java b/src/main/java/net/knarcraft/stargate/Stargate.java
index 7b4355f..b9ed27d 100644
--- a/src/main/java/net/knarcraft/stargate/Stargate.java
+++ b/src/main/java/net/knarcraft/stargate/Stargate.java
@@ -10,6 +10,7 @@ import net.knarcraft.stargate.container.BlockChangeRequest;
import net.knarcraft.stargate.container.ChunkUnloadRequest;
import net.knarcraft.stargate.listener.BlockEventListener;
import net.knarcraft.stargate.listener.EntityEventListener;
+import net.knarcraft.stargate.listener.EntitySpawnListener;
import net.knarcraft.stargate.listener.PlayerEventListener;
import net.knarcraft.stargate.listener.PluginEventListener;
import net.knarcraft.stargate.listener.PortalEventListener;
@@ -38,24 +39,44 @@ import java.util.Queue;
import java.util.logging.Level;
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
+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 .
+ */
+
/**
* The main class of the Stargate plugin
*/
@SuppressWarnings("unused")
public class Stargate extends JavaPlugin {
- //Used for changing gate open/closed material.
private static final Queue blockChangeRequestQueue = new LinkedList<>();
private static final Queue chunkUnloadQueue = new PriorityQueue<>();
private static Logger logger;
private static Stargate stargate;
-
private static String pluginVersion;
-
private static PluginManager pluginManager;
private static StargateConfig stargateConfig;
-
private static String updateAvailable = null;
/**
@@ -388,6 +409,7 @@ public class Stargate extends JavaPlugin {
pluginManager.registerEvents(new WorldEventListener(), this);
pluginManager.registerEvents(new PluginEventListener(this), this);
pluginManager.registerEvents(new TeleportEventListener(), this);
+ pluginManager.registerEvents(new EntitySpawnListener(), this);
}
/**
@@ -428,4 +450,5 @@ public class Stargate extends JavaPlugin {
public static StargateConfig getStargateConfig() {
return stargateConfig;
}
+
}
diff --git a/src/main/java/net/knarcraft/stargate/command/CommandAbout.java b/src/main/java/net/knarcraft/stargate/command/CommandAbout.java
index 3e5b441..f0acd50 100644
--- a/src/main/java/net/knarcraft/stargate/command/CommandAbout.java
+++ b/src/main/java/net/knarcraft/stargate/command/CommandAbout.java
@@ -23,8 +23,9 @@ public class CommandAbout implements CommandExecutor {
commandSender.sendMessage(textColor + "Go to " + highlightColor +
"https://git.knarcraft.net/EpicKnarvik97/Stargate " + textColor + "for the official repository");
String author = Stargate.getStargateConfig().getLanguageLoader().getString("author");
- if (!author.isEmpty())
+ if (!author.isEmpty()) {
commandSender.sendMessage(textColor + "Language created by " + highlightColor + author);
+ }
return true;
}
diff --git a/src/main/java/net/knarcraft/stargate/command/CommandConfig.java b/src/main/java/net/knarcraft/stargate/command/CommandConfig.java
index 0f6dccb..6374518 100644
--- a/src/main/java/net/knarcraft/stargate/command/CommandConfig.java
+++ b/src/main/java/net/knarcraft/stargate/command/CommandConfig.java
@@ -3,12 +3,12 @@ package net.knarcraft.stargate.command;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.ConfigOption;
import net.knarcraft.stargate.config.ConfigTag;
+import net.knarcraft.stargate.config.DynmapManager;
import net.knarcraft.stargate.config.OptionDataType;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalRegistry;
import net.knarcraft.stargate.portal.PortalSignDrawer;
import net.md_5.bungee.api.ChatColor;
-import org.apache.commons.lang.StringUtils;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
@@ -90,6 +90,15 @@ public class CommandConfig implements CommandExecutor {
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 -> {
updateStringConfigValue(selectedOption, commandSender, value);
configuration.set(selectedOption.getConfigNode(), value);
@@ -314,6 +323,30 @@ public class CommandConfig implements CommandExecutor {
}
}
+ /**
+ * Gets a double from a string
+ *
+ * @param commandSender The command sender that sent the config command
+ * @param selectedOption The option the command sender is trying to change
+ * @param value The value given
+ * @return A double, or null if it was invalid
+ */
+ 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
*
@@ -345,6 +378,10 @@ public class CommandConfig implements CommandExecutor {
//Load or unload Vault and Economy as necessary
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();
String stringValue = String.valueOf(defaultValue);
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() +
ChatColor.DARK_GRAY + " (Default: " + ChatColor.GRAY + stringValue + ChatColor.DARK_GRAY + ")";
diff --git a/src/main/java/net/knarcraft/stargate/command/CommandStarGate.java b/src/main/java/net/knarcraft/stargate/command/CommandStarGate.java
index bd82080..2185b54 100644
--- a/src/main/java/net/knarcraft/stargate/command/CommandStarGate.java
+++ b/src/main/java/net/knarcraft/stargate/command/CommandStarGate.java
@@ -2,12 +2,13 @@ package net.knarcraft.stargate.command;
import net.knarcraft.stargate.Stargate;
import net.md_5.bungee.api.ChatColor;
-import org.apache.commons.lang.ArrayUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
+import java.util.Arrays;
+
/**
* This command represents any command which starts with stargate
*
@@ -25,7 +26,7 @@ public class CommandStarGate implements CommandExecutor {
} else if (args[0].equalsIgnoreCase("reload")) {
return new CommandReload().onCommand(commandSender, command, s, args);
} 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 false;
@@ -35,4 +36,5 @@ public class CommandStarGate implements CommandExecutor {
return true;
}
}
+
}
diff --git a/src/main/java/net/knarcraft/stargate/command/ConfigTabCompleter.java b/src/main/java/net/knarcraft/stargate/command/ConfigTabCompleter.java
index c37de81..cb5447d 100644
--- a/src/main/java/net/knarcraft/stargate/command/ConfigTabCompleter.java
+++ b/src/main/java/net/knarcraft/stargate/command/ConfigTabCompleter.java
@@ -21,16 +21,17 @@ public class ConfigTabCompleter implements TabCompleter {
private List signTypes;
private List booleans;
- private List numbers;
+ private List integers;
private List chatColors;
private List languages;
private List extendedColors;
+ private List doubles;
@Nullable
@Override
public List onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@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();
}
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 (selectedOption.getDataType() == OptionDataType.INTEGER) {
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 {
return new ArrayList<>();
}
@@ -164,9 +174,9 @@ public class ConfigTabCompleter implements TabCompleter {
booleans.add("true");
booleans.add("false");
- numbers = new ArrayList<>();
- numbers.add("0");
- numbers.add("5");
+ integers = new ArrayList<>();
+ integers.add("0");
+ integers.add("5");
signTypes = new ArrayList<>();
for (Material material : Material.values()) {
@@ -181,6 +191,12 @@ public class ConfigTabCompleter implements TabCompleter {
extendedColors = new ArrayList<>(chatColors);
extendedColors.add("default");
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 getChatColors() {
List chatColors = new ArrayList<>();
- chatColors.add(ChatColor.WHITE);
- chatColors.add(ChatColor.BLUE);
- chatColors.add(ChatColor.DARK_BLUE);
- 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);
+ char[] colors = new char[]{'a', 'b', 'c', 'd', 'e', 'f', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
+ for (char color : colors) {
+ chatColors.add(ChatColor.getByChar(color));
+ }
chatColors.add(ChatColor.of("#ed76d9"));
chatColors.add(ChatColor.of("#ffecb7"));
return chatColors;
@@ -233,11 +237,13 @@ public class ConfigTabCompleter implements TabCompleter {
languages.add("fr");
languages.add("hu");
languages.add("it");
+ languages.add("ja");
languages.add("nb-no");
languages.add("nl");
languages.add("nn-no");
languages.add("pt-br");
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
// language files
}
diff --git a/src/main/java/net/knarcraft/stargate/command/StarGateTabCompleter.java b/src/main/java/net/knarcraft/stargate/command/StarGateTabCompleter.java
index d67b4db..96ecd3d 100644
--- a/src/main/java/net/knarcraft/stargate/command/StarGateTabCompleter.java
+++ b/src/main/java/net/knarcraft/stargate/command/StarGateTabCompleter.java
@@ -1,6 +1,5 @@
package net.knarcraft.stargate.command;
-import org.apache.commons.lang.ArrayUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
@@ -9,6 +8,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -29,7 +29,7 @@ public class StarGateTabCompleter implements TabCompleter {
}
return matchingCommands;
} 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);
} else {
return new ArrayList<>();
diff --git a/src/main/java/net/knarcraft/stargate/config/ConfigOption.java b/src/main/java/net/knarcraft/stargate/config/ConfigOption.java
index 76d3870..e12ea59 100644
--- a/src/main/java/net/knarcraft/stargate/config/ConfigOption.java
+++ b/src/main/java/net/knarcraft/stargate/config/ConfigOption.java
@@ -50,6 +50,9 @@ public enum ConfigOption {
*/
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[]{
"'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'"}),
@@ -102,6 +105,20 @@ public enum ConfigOption {
HANDLE_LEASHED_CREATURES("gates.functionality.handleLeashedCreatures",
"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
*/
@@ -156,8 +173,23 @@ public enum ConfigOption {
/**
* 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 description;
@@ -184,6 +216,8 @@ public enum ConfigOption {
this.dataType = OptionDataType.BOOLEAN;
} else if (defaultValue instanceof Integer) {
this.dataType = OptionDataType.INTEGER;
+ } else if (defaultValue instanceof Double) {
+ this.dataType = OptionDataType.DOUBLE;
} else {
throw new IllegalArgumentException("Unknown config data type encountered: " + defaultValue);
}
diff --git a/src/main/java/net/knarcraft/stargate/config/ConfigTag.java b/src/main/java/net/knarcraft/stargate/config/ConfigTag.java
index 49c9083..024b205 100644
--- a/src/main/java/net/knarcraft/stargate/config/ConfigTag.java
+++ b/src/main/java/net/knarcraft/stargate/config/ConfigTag.java
@@ -9,7 +9,8 @@ public enum ConfigTag {
COLOR(new ConfigOption[]{ConfigOption.FREE_GATES_COLOR, ConfigOption.MAIN_SIGN_COLOR,
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;
@@ -52,6 +53,16 @@ public enum ConfigTag {
return FOLDER.isTagged(option);
}
+ /**
+ * Checks whether a given config option requires a re-load of all Dynmap markers
+ *
+ * @param configOption The config option to check
+ * @return True if changing the config option requires a reload of all dynmap markers
+ */
+ public static boolean requiresDynmapReload(ConfigOption configOption) {
+ return DYNMAP.isTagged(configOption);
+ }
+
/**
* Checks whether a given config option requires a portal reload to take effect
*
diff --git a/src/main/java/net/knarcraft/stargate/config/DynmapManager.java b/src/main/java/net/knarcraft/stargate/config/DynmapManager.java
new file mode 100644
index 0000000..5eaa0c9
--- /dev/null
+++ b/src/main/java/net/knarcraft/stargate/config/DynmapManager.java
@@ -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 A reference
+ */
+ 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 The portal to add a marker for
+ */
+ 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("Name: %s
%s: %s
Destination: " +
+ "%s
Owner: %s
", 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 The portal to remove the marker for
+ */
+ 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 The portal to get a marker id for
+ * @return
+ */
+ private static String getPortalMarkerId(Portal portal) {
+ return portal.getNetwork() + "-:-" + portal.getName();
+ }
+
+}
diff --git a/src/main/java/net/knarcraft/stargate/config/OptionDataType.java b/src/main/java/net/knarcraft/stargate/config/OptionDataType.java
index 5cb8bee..25fcf76 100644
--- a/src/main/java/net/knarcraft/stargate/config/OptionDataType.java
+++ b/src/main/java/net/knarcraft/stargate/config/OptionDataType.java
@@ -6,17 +6,28 @@ package net.knarcraft.stargate.config;
public enum OptionDataType {
/**
- * The data type for the option is a String
+ * The data type if the option is a String
*/
STRING,
+
/**
- * The data type for the option is a Boolean
+ * The data type if the option is a 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
}
diff --git a/src/main/java/net/knarcraft/stargate/config/StargateConfig.java b/src/main/java/net/knarcraft/stargate/config/StargateConfig.java
index 346bb4d..b718d8b 100644
--- a/src/main/java/net/knarcraft/stargate/config/StargateConfig.java
+++ b/src/main/java/net/knarcraft/stargate/config/StargateConfig.java
@@ -15,6 +15,7 @@ import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.messaging.Messenger;
+import org.dynmap.DynmapAPI;
import java.io.File;
import java.io.IOException;
@@ -101,6 +102,11 @@ public final class StargateConfig {
//Set up vault economy if vault has been loaded
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);
}
+ /**
+ * Gets whether Dynmap integration is disabled
+ *
+ * @return Whether Dynmap integration is disabled
+ */
+ public boolean isDynmapDisabled() {
+ return !((boolean) configOptions.get(ConfigOption.ENABLE_DYNMAP));
+ }
+
+ /**
+ * Gets whether Dynmap icons should be hidden by default
+ *
+ * @return Whether Dynmap icons should be hidden by default
+ */
+ public boolean hideDynmapIcons() {
+ return (boolean) configOptions.get(ConfigOption.DYNMAP_ICONS_DEFAULT_HIDDEN);
+ }
+
/**
* Gets the object containing economy config values
*
@@ -189,6 +213,9 @@ public final class StargateConfig {
startStopBungeeListener(stargateGateConfig.enableBungee());
}
+ //Reload portal markers
+ DynmapManager.addAllPortalMarkers();
+
messageSender.sendErrorMessage(sender, languageLoader.getString("reloaded"));
}
@@ -358,6 +385,7 @@ public final class StargateConfig {
}
case BOOLEAN -> optionValue = newConfig.getBoolean(configNode);
case INTEGER -> optionValue = newConfig.getInt(configNode);
+ case DOUBLE -> optionValue = newConfig.getDouble(configNode);
default -> throw new IllegalArgumentException("Invalid config data type encountered");
}
configOptions.put(option, optionValue);
@@ -519,4 +547,5 @@ public final class StargateConfig {
public LanguageLoader getLanguageLoader() {
return languageLoader;
}
+
}
diff --git a/src/main/java/net/knarcraft/stargate/config/StargateGateConfig.java b/src/main/java/net/knarcraft/stargate/config/StargateGateConfig.java
index 001ced9..053d4b6 100644
--- a/src/main/java/net/knarcraft/stargate/config/StargateGateConfig.java
+++ b/src/main/java/net/knarcraft/stargate/config/StargateGateConfig.java
@@ -16,6 +16,7 @@ import java.util.Map;
* The Stargate gate config keeps track of all global config values related to gates
*/
public final class StargateGateConfig {
+
private static final int activeTime = 10;
private static final int openTime = 10;
private final Map configOptions;
@@ -125,6 +126,29 @@ public final class StargateGateConfig {
return (boolean) configOptions.get(ConfigOption.HANDLE_LEASHED_CREATURES);
}
+ /**
+ * Gets whether the CraftBook vehicle removal fix is enabled
+ *
+ * If enabled, minecarts and boats should be re-created instead of teleported.
+ *
+ * @return True if the CraftBook vehicle removal fix is enabled
+ */
+ 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 The delay to use before adding a player as passenger of a teleported vehicle
+ */
+ 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
*
@@ -179,6 +203,15 @@ public final class StargateGateConfig {
return (String) configOptions.get(ConfigOption.DEFAULT_GATE_NETWORK);
}
+ /**
+ * Gets the exit velocity of players using stargates, relative to the entry velocity
+ *
+ * @return The relative exit velocity
+ */
+ public double getExitVelocity() {
+ return (double) configOptions.get(ConfigOption.EXIT_VELOCITY);
+ }
+
/**
* Loads all config values related to gates
*/
@@ -253,8 +286,8 @@ public final class StargateGateConfig {
if (colors[colorIndex].equalsIgnoreCase("inverted")) {
//Convert from ChatColor to awt.Color to Bukkit.Color then invert and convert to ChatColor
java.awt.Color color = defaultColors[colorIndex].getColor();
- parsedColor = ColorHelper.fromColor(ColorHelper.invert(Color.fromRGB(color.getRed(),
- color.getGreen(), color.getBlue())));
+ parsedColor = ColorHelper.fromColor(ColorHelper.invert(Color.fromRGB(color.getRed(), color.getGreen(),
+ color.getBlue())));
} else {
try {
parsedColor = ChatColor.of(colors[colorIndex]);
@@ -291,4 +324,5 @@ public final class StargateGateConfig {
PortalSignDrawer.setHighlightColor(ChatColor.WHITE);
}
}
+
}
diff --git a/src/main/java/net/knarcraft/stargate/container/RelativeBlockVector.java b/src/main/java/net/knarcraft/stargate/container/RelativeBlockVector.java
index 81bddef..8cb6942 100644
--- a/src/main/java/net/knarcraft/stargate/container/RelativeBlockVector.java
+++ b/src/main/java/net/knarcraft/stargate/container/RelativeBlockVector.java
@@ -60,16 +60,11 @@ public class RelativeBlockVector {
* @return A new relative block vector with the property altered
*/
public RelativeBlockVector addToVector(Property propertyToAddTo, int valueToAdd) {
- switch (propertyToAddTo) {
- case RIGHT:
- return new RelativeBlockVector(this.right + valueToAdd, this.down, this.out);
- case DOWN:
- 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");
- }
+ return switch (propertyToAddTo) {
+ case RIGHT -> new RelativeBlockVector(this.right + valueToAdd, this.down, this.out);
+ case DOWN -> new RelativeBlockVector(this.right, this.down + valueToAdd, this.out);
+ case OUT -> new RelativeBlockVector(this.right, this.down, this.out + valueToAdd);
+ };
}
/**
diff --git a/src/main/java/net/knarcraft/stargate/event/StargateEntityPortalEvent.java b/src/main/java/net/knarcraft/stargate/event/StargateEntityPortalEvent.java
index 0cf3448..cd34504 100644
--- a/src/main/java/net/knarcraft/stargate/event/StargateEntityPortalEvent.java
+++ b/src/main/java/net/knarcraft/stargate/event/StargateEntityPortalEvent.java
@@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
* This event can be used to overwrite the location the entity is teleported to.
*/
@SuppressWarnings("unused")
-public class StargateEntityPortalEvent extends StargateEvent {
+public class StargateEntityPortalEvent extends StargateEvent implements StargateTeleportEvent {
private static final HandlerList handlers = new HandlerList();
final Entity travellingEntity;
@@ -58,6 +58,7 @@ public class StargateEntityPortalEvent extends StargateEvent {
*
* @return Location of the exit point
*/
+ @Override
public Location getExit() {
return exit;
}
diff --git a/src/main/java/net/knarcraft/stargate/event/StargatePlayerPortalEvent.java b/src/main/java/net/knarcraft/stargate/event/StargatePlayerPortalEvent.java
index 05d474b..3d2526a 100644
--- a/src/main/java/net/knarcraft/stargate/event/StargatePlayerPortalEvent.java
+++ b/src/main/java/net/knarcraft/stargate/event/StargatePlayerPortalEvent.java
@@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
* This event can be used to overwrite the location the player is teleported to.
*/
@SuppressWarnings("unused")
-public class StargatePlayerPortalEvent extends StargatePlayerEvent {
+public class StargatePlayerPortalEvent extends StargatePlayerEvent implements StargateTeleportEvent {
private static final HandlerList handlers = new HandlerList();
private final Portal destination;
@@ -47,6 +47,7 @@ public class StargatePlayerPortalEvent extends StargatePlayerEvent {
*
* @return Location of the exit point
*/
+ @Override
public Location getExit() {
return exit;
}
diff --git a/src/main/java/net/knarcraft/stargate/event/StargateTeleportEvent.java b/src/main/java/net/knarcraft/stargate/event/StargateTeleportEvent.java
new file mode 100644
index 0000000..e440828
--- /dev/null
+++ b/src/main/java/net/knarcraft/stargate/event/StargateTeleportEvent.java
@@ -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 Location of the exit point
+ */
+ Location getExit();
+
+}
diff --git a/src/main/java/net/knarcraft/stargate/listener/EntitySpawnListener.java b/src/main/java/net/knarcraft/stargate/listener/EntitySpawnListener.java
new file mode 100644
index 0000000..b4c0b2c
--- /dev/null
+++ b/src/main/java/net/knarcraft/stargate/listener/EntitySpawnListener.java
@@ -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");
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/net/knarcraft/stargate/listener/PlayerEventListener.java b/src/main/java/net/knarcraft/stargate/listener/PlayerEventListener.java
index b182690..82438a8 100644
--- a/src/main/java/net/knarcraft/stargate/listener/PlayerEventListener.java
+++ b/src/main/java/net/knarcraft/stargate/listener/PlayerEventListener.java
@@ -7,16 +7,17 @@ import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalActivator;
import net.knarcraft.stargate.portal.PortalHandler;
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.utility.BungeeHelper;
import net.knarcraft.stargate.utility.MaterialHelper;
import net.knarcraft.stargate.utility.PermissionHelper;
+import net.knarcraft.stargate.utility.TeleportHelper;
import net.knarcraft.stargate.utility.UUIDMigrationHelper;
import net.knarcraft.stargate.utility.UpdateChecker;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
+import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.data.type.WallSign;
import org.bukkit.entity.AbstractHorse;
@@ -33,6 +34,10 @@ import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.inventory.EquipmentSlot;
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
@@ -40,8 +45,7 @@ import org.bukkit.inventory.ItemStack;
@SuppressWarnings("unused")
public class PlayerEventListener implements Listener {
- private static long eventTime;
- private static PlayerInteractEvent previousEvent;
+ private static final Map previousEventTimes = new HashMap<>();
/**
* This event handler handles detection of any player teleporting through a bungee gate
@@ -101,6 +105,11 @@ public class PlayerEventListener implements Listener {
return;
}
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);
Entity playerVehicle = player.getVehicle();
@@ -129,10 +138,11 @@ public class PlayerEventListener implements Listener {
horse.setOwner(player);
}
//Teleport the player's vehicle
- new VehicleTeleporter(destination, (Vehicle) playerVehicle).teleport(entrancePortal);
+ player.setVelocity(new Vector());
+ new VehicleTeleporter(destination, (Vehicle) playerVehicle).teleportEntity(entrancePortal);
} else {
//Just teleport the player like normal
- new PlayerTeleporter(destination, player).teleport(entrancePortal, event);
+ new PlayerTeleporter(destination, player).teleportPlayer(entrancePortal, event);
}
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
@@ -159,7 +169,12 @@ public class PlayerEventListener implements Listener {
//Check if the player moved from a portal
Portal entrancePortal = PortalHandler.getByEntrance(toLocation);
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);
@@ -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
- return Teleporter.noLeashedCreaturesPreventTeleportation(player);
+ return TeleportHelper.noLeashedCreaturesPreventTeleportation(player);
}
/**
@@ -226,11 +241,14 @@ public class PlayerEventListener implements Listener {
EquipmentSlot hand = event.getHand();
if (hand != null && (PermissionHelper.hasPermission(player, "stargate.admin.dye") ||
portal.isOwner(player))) {
- String itemName = player.getInventory().getItem(hand).getType().toString();
- if (itemName.endsWith("DYE") || itemName.endsWith("INK_SAC")) {
- event.setUseInteractedBlock(Event.Result.ALLOW);
- Bukkit.getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(), portal::drawSign, 1);
- return;
+ ItemStack item = player.getInventory().getItem(hand);
+ if (item != null) {
+ String itemName = item.getType().toString();
+ if (itemName.endsWith("DYE") || itemName.endsWith("INK_SAC")) {
+ 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
- if (clickIsBug(event, block)) {
+ if (clickIsBug(event.getPlayer(), block)) {
return;
}
@@ -321,7 +339,7 @@ public class PlayerEventListener implements Listener {
} else {
//Display information about the portal if it has no sign
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);
}
}
@@ -366,19 +384,17 @@ public class PlayerEventListener implements Listener {
* immediately, or causing portal information printing twice. This fix should detect the bug without breaking
* clicking once the bug is fixed.
*
- * @param event The event causing the right click
- * @param block The block to check
+ * @param player The player performing the right-click
+ * @param block The block to check
* @return True if the click is a bug and should be cancelled
*/
- private boolean clickIsBug(PlayerInteractEvent event, Block block) {
- if (previousEvent != null &&
- event.getPlayer() == previousEvent.getPlayer() && eventTime + 15 > System.currentTimeMillis()) {
- previousEvent = null;
- eventTime = 0;
+ private boolean clickIsBug(Player player, Block block) {
+ Long previousEventTime = previousEventTimes.get(player);
+ if (previousEventTime != null && previousEventTime + 50 > System.currentTimeMillis()) {
+ previousEventTimes.put(player, null);
return true;
}
- previousEvent = event;
- eventTime = System.currentTimeMillis();
+ previousEventTimes.put(player, System.currentTimeMillis());
return false;
}
diff --git a/src/main/java/net/knarcraft/stargate/listener/PluginEventListener.java b/src/main/java/net/knarcraft/stargate/listener/PluginEventListener.java
index a6e0dba..2f70de3 100644
--- a/src/main/java/net/knarcraft/stargate/listener/PluginEventListener.java
+++ b/src/main/java/net/knarcraft/stargate/listener/PluginEventListener.java
@@ -49,4 +49,5 @@ public class PluginEventListener implements Listener {
Stargate.logInfo("Vault plugin lost.");
}
}
+
}
diff --git a/src/main/java/net/knarcraft/stargate/listener/PortalEventListener.java b/src/main/java/net/knarcraft/stargate/listener/PortalEventListener.java
index 8510b9e..c81640f 100644
--- a/src/main/java/net/knarcraft/stargate/listener/PortalEventListener.java
+++ b/src/main/java/net/knarcraft/stargate/listener/PortalEventListener.java
@@ -6,6 +6,7 @@ import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter;
import net.knarcraft.stargate.utility.PermissionHelper;
+import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
@@ -67,14 +68,23 @@ public class PortalEventListener implements Listener {
return;
}
+ Stargate.debug("PortalEventListener::onEntityPortalEnter",
+ "Found player " + player + " entering END_PORTAL " + portal);
+
//Remove any old player teleportations in case weird things happen
playersFromTheEnd.removeIf((teleportation -> teleportation.getPlayer() == player));
//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
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();
//Overwrite respawn location to respawn in front of the portal
- event.setRespawnLocation(new PlayerTeleporter(exitPortal, respawningPlayer).getExit(respawningPlayer,
- respawningPlayer.getLocation()));
+ PlayerTeleporter teleporter = new PlayerTeleporter(exitPortal, respawningPlayer);
+ 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
exitPortal.getPortalOpener().closePortal(false);
+
+ Stargate.debug("PortalEventListener::onRespawn", "Overwriting respawn for " + respawningPlayer +
+ " to " + respawnLocation.getWorld() + ":" + respawnLocation);
}
}
diff --git a/src/main/java/net/knarcraft/stargate/listener/VehicleEventListener.java b/src/main/java/net/knarcraft/stargate/listener/VehicleEventListener.java
index 0b263a2..42c1102 100644
--- a/src/main/java/net/knarcraft/stargate/listener/VehicleEventListener.java
+++ b/src/main/java/net/knarcraft/stargate/listener/VehicleEventListener.java
@@ -3,11 +3,10 @@ package net.knarcraft.stargate.listener;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler;
-import net.knarcraft.stargate.portal.teleporter.Teleporter;
import net.knarcraft.stargate.portal.teleporter.VehicleTeleporter;
import net.knarcraft.stargate.utility.EconomyHelper;
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.Player;
import org.bukkit.entity.Vehicle;
@@ -62,11 +61,11 @@ public class VehicleEventListener implements Listener {
private static void teleportVehicle(List passengers, Portal entrancePortal, Vehicle vehicle) {
String route = "VehicleEventListener::teleportVehicle";
- if (!passengers.isEmpty() && passengers.get(0) instanceof Player) {
+ if (!passengers.isEmpty() && TeleportHelper.containsPlayer(passengers)) {
Stargate.debug(route, "Found passenger vehicle");
- teleportPlayerAndVehicle(entrancePortal, vehicle, passengers);
+ teleportPlayerAndVehicle(entrancePortal, vehicle);
} else {
- Stargate.debug(route, "Found empty vehicle");
+ Stargate.debug(route, "Found vehicle without players");
Portal destinationPortal = entrancePortal.getPortalActivator().getDestination();
if (destinationPortal == null) {
Stargate.debug(route, "Unable to find portal destination");
@@ -74,7 +73,7 @@ public class VehicleEventListener implements Listener {
}
Stargate.debug("vehicleTeleport", destinationPortal.getWorld() + " " +
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 The portal the minecart entered
* @param vehicle The vehicle to teleport
- * @param passengers Any entities sitting in the minecart
*/
- private static void teleportPlayerAndVehicle(Portal entrancePortal, Vehicle vehicle, List passengers) {
- Player player = (Player) passengers.get(0);
- //On the assumption that a non-player cannot sit in the driver's seat and since some portals can only be open
- // to one player at a time, we only need to check if the portal is open to the driver.
- if (!entrancePortal.getPortalOpener().isOpenFor(player)) {
- if (!entrancePortal.getOptions().isSilent()) {
- Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
+ private static void teleportPlayerAndVehicle(Portal entrancePortal, Vehicle vehicle) {
+ Entity rootEntity = vehicle;
+ while (rootEntity.getVehicle() != null) {
+ rootEntity = rootEntity.getVehicle();
+ }
+ List players = TeleportHelper.getPlayers(rootEntity.getPassengers());
+ 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
- Portal destinationPortal = entrancePortal.getPortalActivator().getDestination(player);
- if (destinationPortal == null) {
- return;
- }
-
- //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;
+ //Check if any of the players has selected the destination
+ Portal possibleDestinationPortal = entrancePortal.getPortalActivator().getDestination(player);
+ if (possibleDestinationPortal != null) {
+ destinationPortal = possibleDestinationPortal;
}
}
- //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 (!takePlayerPayment(passengers, entrancePortal, cost)) {
- return;
+ //Cancel the teleport if no players activated the portal, or if any players are denied access
+ boolean cancelTeleport = false;
+ for (Player player : players) {
+ if (destinationPortal == null) {
+ cancelTeleport = true;
+ 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
- boolean teleported = new VehicleTeleporter(destinationPortal, vehicle).teleport(entrancePortal);
+ boolean teleported = new VehicleTeleporter(destinationPortal, vehicle).teleportEntity(entrancePortal);
if (teleported) {
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);
}
}
- /**
- * Takes payment from all player passengers
- *
- * @param passengers All passengers in the teleporting vehicle
- * @param entrancePortal The portal the vehicle is entering from
- * @param cost The cost each player has to pay
- * @return True if all player passengers paid successfully
- */
- private static boolean takePlayerPayment(List 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 The player trying to teleport
- * @param entrancePortal The portal the player is entering
- * @param destinationPortal The portal the player is to exit from
- * @return True if the player is allowed to teleport and is able to pay necessary fees
- */
- 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);
- }
-
}
diff --git a/src/main/java/net/knarcraft/stargate/listener/WorldEventListener.java b/src/main/java/net/knarcraft/stargate/listener/WorldEventListener.java
index bd4ccc5..6329d6d 100644
--- a/src/main/java/net/knarcraft/stargate/listener/WorldEventListener.java
+++ b/src/main/java/net/knarcraft/stargate/listener/WorldEventListener.java
@@ -46,4 +46,5 @@ public class WorldEventListener implements Listener {
PortalRegistry.clearPortals(world);
}
}
+
}
diff --git a/src/main/java/net/knarcraft/stargate/portal/Portal.java b/src/main/java/net/knarcraft/stargate/portal/Portal.java
index 9af1838..6c7db86 100644
--- a/src/main/java/net/knarcraft/stargate/portal/Portal.java
+++ b/src/main/java/net/knarcraft/stargate/portal/Portal.java
@@ -349,4 +349,5 @@ public class Portal {
return cleanNetwork.equalsIgnoreCase(other.cleanNetwork);
}
}
+
}
diff --git a/src/main/java/net/knarcraft/stargate/portal/PortalHandler.java b/src/main/java/net/knarcraft/stargate/portal/PortalHandler.java
index cabff97..44ffb81 100644
--- a/src/main/java/net/knarcraft/stargate/portal/PortalHandler.java
+++ b/src/main/java/net/knarcraft/stargate/portal/PortalHandler.java
@@ -448,4 +448,5 @@ public class PortalHandler {
}
return input.replaceAll("[|:#]", "").trim();
}
+
}
diff --git a/src/main/java/net/knarcraft/stargate/portal/PortalRegistry.java b/src/main/java/net/knarcraft/stargate/portal/PortalRegistry.java
index 74faa96..fe07562 100644
--- a/src/main/java/net/knarcraft/stargate/portal/PortalRegistry.java
+++ b/src/main/java/net/knarcraft/stargate/portal/PortalRegistry.java
@@ -1,6 +1,7 @@
package net.knarcraft.stargate.portal;
import net.knarcraft.stargate.Stargate;
+import net.knarcraft.stargate.config.DynmapManager;
import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.utility.PortalFileHelper;
import org.bukkit.World;
@@ -224,6 +225,7 @@ public class PortalRegistry {
PortalFileHelper.saveAllPortals(portal.getWorld());
portal.setRegistered(false);
+ DynmapManager.removePortalMarker(portal);
}
/**
@@ -289,6 +291,7 @@ public class PortalRegistry {
allPortals.add(portal);
portal.setRegistered(true);
+ DynmapManager.addPortalMarker(portal);
}
}
diff --git a/src/main/java/net/knarcraft/stargate/portal/teleporter/EntityTeleporter.java b/src/main/java/net/knarcraft/stargate/portal/teleporter/EntityTeleporter.java
index df12f74..e963c92 100644
--- a/src/main/java/net/knarcraft/stargate/portal/teleporter/EntityTeleporter.java
+++ b/src/main/java/net/knarcraft/stargate/portal/teleporter/EntityTeleporter.java
@@ -1,9 +1,7 @@
package net.knarcraft.stargate.portal.teleporter;
-import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.event.StargateEntityPortalEvent;
import net.knarcraft.stargate.portal.Portal;
-import org.bukkit.Location;
import org.bukkit.entity.Entity;
/**
@@ -16,10 +14,10 @@ public class EntityTeleporter extends Teleporter {
/**
* Instantiates a new portal teleporter
*
- * @param portal The portal which is the target of the teleportation
+ * @param targetPortal The portal which is the target of the teleportation
*/
- public EntityTeleporter(Portal portal, Entity teleportingEntity) {
- super(portal);
+ public EntityTeleporter(Portal targetPortal, Entity teleportingEntity) {
+ super(targetPortal, teleportingEntity);
this.teleportingEntity = teleportingEntity;
}
@@ -29,44 +27,8 @@ public class EntityTeleporter extends Teleporter {
* @param origin The portal the entity is teleporting from
* @return True if the entity was teleported. False otherwise
*/
- public boolean teleport(Portal origin) {
- Location traveller = teleportingEntity.getLocation();
- 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;
+ public boolean teleportEntity(Portal origin) {
+ return teleport(origin, new StargateEntityPortalEvent(teleportingEntity, origin, portal, exit));
}
- /**
- * Triggers the entity portal event to allow plugins to change the exit location
- *
- * @param origin The origin portal teleported from
- * @param exit The exit location to teleport the entity to
- * @return The location the entity should be teleported to, or null if the event was cancelled
- */
- 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();
- }
}
diff --git a/src/main/java/net/knarcraft/stargate/portal/teleporter/PlayerTeleporter.java b/src/main/java/net/knarcraft/stargate/portal/teleporter/PlayerTeleporter.java
index e8232bb..3460340 100644
--- a/src/main/java/net/knarcraft/stargate/portal/teleporter/PlayerTeleporter.java
+++ b/src/main/java/net/knarcraft/stargate/portal/teleporter/PlayerTeleporter.java
@@ -3,9 +3,15 @@ package net.knarcraft.stargate.portal.teleporter;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.event.StargatePlayerPortalEvent;
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.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
@@ -17,11 +23,11 @@ public class PlayerTeleporter extends Teleporter {
/**
* Instantiates a new player teleporter
*
- * @param portal The portal which is the target of the teleportation
- * @param player The teleporting player
+ * @param targetPortal The portal which is the target of the teleportation
+ * @param player The teleporting player
*/
- public PlayerTeleporter(Portal portal, Player player) {
- super(portal);
+ public PlayerTeleporter(Portal targetPortal, Player player) {
+ super(targetPortal, player);
this.player = player;
}
@@ -31,53 +37,42 @@ public class PlayerTeleporter extends Teleporter {
* @param origin The portal the player teleports from
* @param event The player move event triggering the event
*/
- public void teleport(Portal origin, PlayerMoveEvent event) {
- Location traveller = player.getLocation();
- Location exit = getExit(player, traveller);
-
- //Rotate the player to face out from the portal
- adjustRotation(exit);
+ public void teleportPlayer(Portal origin, PlayerMoveEvent event) {
+ double velocity = player.getVelocity().length();
+ List passengers = player.getPassengers();
//Call the StargatePlayerPortalEvent to allow plugins to change destination
if (!origin.equals(portal)) {
- exit = triggerPlayerPortalEvent(origin, exit, event);
+ exit = triggerPortalEvent(origin, new StargatePlayerPortalEvent(player, origin, portal, exit));
if (exit == null) {
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
loadChunks();
//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 (event == null) {
player.teleport(exit);
} 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);
}
- }
- /**
- * Triggers the player portal event to allow plugins to change the exit location
- *
- * @param origin The origin portal teleported from
- * @param exit The exit location to teleport the player to
- * @param event The player move event which triggered the teleportation
- * @return The location the player should be teleported to, or null if the event was cancelled
- */
- 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();
+ //Set the velocity of the teleported player after the teleportation is finished
+ Bukkit.getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(), () -> player.setVelocity(newVelocity), 1);
}
}
diff --git a/src/main/java/net/knarcraft/stargate/portal/teleporter/Teleporter.java b/src/main/java/net/knarcraft/stargate/portal/teleporter/Teleporter.java
index 5ffd9f4..7e1f7ee 100644
--- a/src/main/java/net/knarcraft/stargate/portal/teleporter/Teleporter.java
+++ b/src/main/java/net/knarcraft/stargate/portal/teleporter/Teleporter.java
@@ -4,9 +4,11 @@ import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.container.ChunkUnloadRequest;
import net.knarcraft.stargate.container.RelativeBlockVector;
+import net.knarcraft.stargate.event.StargateTeleportEvent;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.utility.DirectionHelper;
import net.knarcraft.stargate.utility.EntityHelper;
+import net.knarcraft.stargate.utility.TeleportHelper;
import org.bukkit.Chunk;
import org.bukkit.Location;
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.type.Slab;
import org.bukkit.entity.AbstractHorse;
-import org.bukkit.entity.Creature;
import org.bukkit.entity.Entity;
-import org.bukkit.entity.Player;
+import org.bukkit.event.Event;
import org.bukkit.scheduler.BukkitScheduler;
+import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.List;
@@ -31,71 +33,114 @@ public abstract class Teleporter {
* The portal the entity is teleporting to
*/
protected final Portal portal;
+
/**
* The scheduler to use for delaying tasks
*/
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
*
- * @param portal The portal which is the target of the teleportation
+ * @param portal The portal which is the target of the teleportation
+ * @param teleportedEntity The entity teleported by this teleporter
*/
- public Teleporter(Portal portal) {
+ public Teleporter(Portal portal, Entity teleportedEntity) {
this.portal = portal;
this.scheduler = Stargate.getInstance().getServer().getScheduler();
+ this.teleportedEntity = teleportedEntity;
+ this.exit = getExit(teleportedEntity);
}
+ /**
+ * Teleports an entity
+ *
+ * @param origin The portal the entity teleported from
+ * @param stargateTeleportEvent The event to call to make sure the teleportation is valid
+ * @return True if the teleportation was successfully performed
+ */
+ public boolean teleport(Portal origin, StargateTeleportEvent stargateTeleportEvent) {
+ List 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 The exit location of this teleporter
+ */
+ public Location getExit() {
+ return exit.clone();
+ }
+
+ /**
+ * Triggers the entity portal event to allow plugins to change the exit location
+ *
+ * @param origin The origin portal teleported from
+ * @param stargateTeleportEvent The exit location to teleport the entity to
+ * @return The location the entity should be teleported to, or null if the event was cancelled
+ */
+ 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
*
* @param exit The location the entity will exit from
*/
- protected void adjustRotation(Location exit) {
+ protected void adjustExitLocationRotation(Location exit) {
int adjust = 0;
if (portal.getOptions().isBackwards()) {
adjust = 180;
}
float newYaw = (portal.getYaw() + adjust) % 360;
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
- *
- * @param entity The entity to teleport (used to determine distance from portal to avoid suffocation)
- * @param traveller The location of the entity travelling
- * @return The location the entity should be teleported to.
+ * Loads the chunks outside the portal's entrance
*/
- public Location getExit(Entity entity, Location traveller) {
- Location exitLocation = null;
- RelativeBlockVector relativeExit = portal.getGate().getLayout().getExit();
- if (relativeExit != null) {
- 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()));
+ protected void loadChunks() {
+ for (Chunk chunk : getChunksToLoad()) {
+ chunk.addPluginChunkTicket(Stargate.getInstance());
+ //Allow the chunk to unload after 10 seconds
+ Stargate.addChunkUnloadRequest(new ChunkUnloadRequest(chunk, 10000L));
}
-
- //Adjust pitch and height
- return adjustExitLocation(traveller, exitLocation);
}
/**
@@ -141,7 +186,7 @@ public abstract class Teleporter {
if (entitySize > 1) {
double entityOffset;
if (portal.getOptions().isAlwaysOn()) {
- entityOffset = entityBoxSize / 2D;
+ entityOffset = (entityBoxSize / 2D);
} else {
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
* check is necessary when teleporting boats to prevent it from becoming a submarine.
*
- * @param traveller The location of the travelling entity
+ * @param entity The travelling entity
* @param exitLocation The exit location generated
* @return The location the travelling entity should be teleported to
*/
- private Location adjustExitLocation(Location traveller, Location exitLocation) {
+ private Location adjustExitLocationHeight(Entity entity, Location exitLocation) {
if (exitLocation != null) {
BlockData blockData = exitLocation.getBlock().getBlockData();
if ((blockData instanceof Bisected bisected && bisected.getHalf() == Bisected.Half.BOTTOM) ||
- (blockData instanceof Slab slab && slab.getType() == Slab.Type.BOTTOM)) {
- //Prevent traveller from spawning inside a slab
- Stargate.debug("adjustExitLocation", "Added a block to get above a slab");
- exitLocation.add(0, 1, 0);
- } 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");
+ (blockData instanceof Slab slab && slab.getType() == Slab.Type.BOTTOM) ||
+ blockData.getMaterial() == Material.WATER) {
+ //Prevent traveller from spawning inside a slab, or a boat from spawning inside water
+ Stargate.debug("adjustExitLocation", "Added a block to get above a slab or a block of water");
exitLocation.add(0, 1, 0);
}
-
- exitLocation.setPitch(traveller.getPitch());
return exitLocation;
} else {
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 The entity to teleport (used to determine distance from portal to avoid suffocation)
+ * @return The location the entity should be teleported to.
*/
- protected void loadChunks() {
- for (Chunk chunk : getChunksToLoad()) {
- chunk.addPluginChunkTicket(Stargate.getInstance());
- //Allow the chunk to unload after 3 seconds
- Stargate.addChunkUnloadRequest(new ChunkUnloadRequest(chunk, 3000L));
+ private Location getExit(Entity entity) {
+ Location exitLocation = null;
+ RelativeBlockVector relativeExit = portal.getGate().getLayout().getExit();
+ if (relativeExit != null) {
+ 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;
}
- /**
- * Checks whether a player has leashed creatures that block the teleportation
- *
- * @param player The player trying to teleport
- * @return False if the player has leashed any creatures that cannot go through the portal
- */
- public static boolean noLeashedCreaturesPreventTeleportation(Player player) {
- //Find any nearby leashed entities to teleport with the player
- List 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
- *
- * 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.
- *
- * @param player The player which is teleported
- * @param origin The portal the player is teleporting from
- */
- 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 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 The player to check
- * @return A list of all creatures the player is holding in a leash (lead)
- */
- protected static List getLeashedCreatures(Player player) {
- List leashedCreatures = new ArrayList<>();
- //Find any nearby leashed entities to teleport with the player
- List 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;
- }
-
}
diff --git a/src/main/java/net/knarcraft/stargate/portal/teleporter/VehicleTeleporter.java b/src/main/java/net/knarcraft/stargate/portal/teleporter/VehicleTeleporter.java
index 87c3288..20d4353 100644
--- a/src/main/java/net/knarcraft/stargate/portal/teleporter/VehicleTeleporter.java
+++ b/src/main/java/net/knarcraft/stargate/portal/teleporter/VehicleTeleporter.java
@@ -2,14 +2,17 @@ package net.knarcraft.stargate.portal.teleporter;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.StargateGateConfig;
+import net.knarcraft.stargate.event.StargateEntityPortalEvent;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.utility.DirectionHelper;
+import net.knarcraft.stargate.utility.TeleportHelper;
import org.bukkit.Location;
import org.bukkit.World;
+import org.bukkit.entity.Boat;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
-import org.bukkit.entity.Player;
import org.bukkit.entity.Vehicle;
+import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.util.Vector;
import java.util.List;
@@ -24,11 +27,11 @@ public class VehicleTeleporter extends EntityTeleporter {
/**
* Instantiates a new vehicle teleporter
*
- * @param portal The portal which is the target of the teleportation
+ * @param targetPortal The targetPortal which is the target of the teleportation
* @param teleportingVehicle The teleporting vehicle
*/
- public VehicleTeleporter(Portal portal, Vehicle teleportingVehicle) {
- super(portal, teleportingVehicle);
+ public VehicleTeleporter(Portal targetPortal, Vehicle teleportingVehicle) {
+ super(targetPortal, teleportingVehicle);
this.teleportingVehicle = teleportingVehicle;
}
@@ -42,28 +45,22 @@ public class VehicleTeleporter extends EntityTeleporter {
* @return True if the vehicle was teleported. False otherwise
*/
@Override
- public boolean teleport(Portal origin) {
- Location traveller = teleportingVehicle.getLocation();
- Location exit = getExit(teleportingVehicle, traveller);
+ public boolean teleportEntity(Portal origin) {
+ Stargate.debug("VehicleTeleporter::teleport", "Preparing to teleport: " + teleportingVehicle);
double velocity = teleportingVehicle.getVelocity().length();
- //Stop and teleport
+ //Stop the vehicle before teleporting
teleportingVehicle.setVelocity(new Vector());
//Get new velocity
Vector newVelocityDirection = DirectionHelper.getDirectionVectorFromYaw(portal.getYaw());
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
- if (!origin.equals(portal)) {
- exit = triggerEntityPortalEvent(origin, exit);
- if (exit == null) {
- return false;
- }
+ exit = triggerPortalEvent(origin, new StargateEntityPortalEvent(teleportingVehicle, origin, portal, exit));
+ if (exit == null) {
+ return false;
}
//Teleport the vehicle
@@ -89,12 +86,13 @@ public class VehicleTeleporter extends EntityTeleporter {
return false;
}
- if (!(teleportingVehicle instanceof LivingEntity)) {
+ if (!(teleportingVehicle instanceof LivingEntity) &&
+ Stargate.getGateConfig().enableCraftBookRemoveOnEjectFix()) {
//Teleport a normal vehicle with passengers (minecart or boat)
putPassengersInNewVehicle(passengers, exit, newVelocity, origin);
} else {
//Teleport a living vehicle with passengers (pig, horse, donkey, strider)
- teleportLivingVehicle(exit, passengers, origin);
+ teleportVehicle(passengers, exit, newVelocity, origin);
}
} else {
//Check if teleportation of empty vehicles is enabled
@@ -118,54 +116,35 @@ public class VehicleTeleporter extends EntityTeleporter {
private boolean vehiclePassengersAllowed(List passengers) {
StargateGateConfig config = Stargate.getGateConfig();
//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;
}
//Don't teleport if the player does not contain a player and non-player vehicles is disabled
- return containsPlayer(passengers) || config.handleNonPlayerVehicles();
- }
-
- /**
- * Checks whether a list of entities contains any non-players
- *
- * @param entities The list of entities to check
- * @return True if at least one entity is not a player
- */
- private boolean containsNonPlayer(List 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 The list of entities to check
- * @return True if at least one player is present among the passengers
- */
- private boolean containsPlayer(List entities) {
- for (Entity entity : entities) {
- if (entity instanceof Player) {
- return true;
- }
- }
- return false;
+ return TeleportHelper.containsPlayer(passengers) || config.handleNonPlayerVehicles();
}
/**
* Teleport a vehicle which is not a minecart or a boat
*
- * @param exit The location the vehicle will exit
- * @param passengers The passengers of the vehicle
- * @param origin The portal the vehicle teleported from
+ * @param passengers The passengers of the vehicle
+ * @param exit The location the vehicle will exit
+ * @param newVelocity The new velocity of the teleported vehicle
+ * @param origin The portal the vehicle teleported from
*/
- private void teleportLivingVehicle(Location exit, List passengers, Portal origin) {
- teleportingVehicle.eject();
- teleportingVehicle.teleport(exit);
- handleVehiclePassengers(passengers, teleportingVehicle, 2, origin);
+ private void teleportVehicle(List passengers, Location exit, Vector newVelocity, Portal origin) {
+ if (teleportingVehicle.eject()) {
+ TeleportHelper.handleEntityPassengers(passengers, teleportingVehicle, origin, portal, exit.getDirection(),
+ 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
Vehicle newVehicle = vehicleWorld.spawn(exit, teleportingVehicle.getClass());
+ if (teleportingVehicle instanceof Boat boat) {
+ ((Boat) newVehicle).setWoodType(boat.getWoodType());
+ }
//Remove the old vehicle
- teleportingVehicle.eject();
+ if (teleportingVehicle.eject()) {
+ TeleportHelper.handleEntityPassengers(passengers, newVehicle, origin, portal, exit.getDirection(),
+ newVelocity);
+ }
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);
}
- /**
- * Ejects, teleports and adds all passengers to the target vehicle
- *
- * @param passengers The passengers to handle
- * @param vehicle The vehicle the passengers should be put into
- * @param delay The amount of milliseconds to wait before adding the vehicle passengers
- * @param origin The portal the vehicle teleported from
- */
- private void handleVehiclePassengers(List 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
- *
- * 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.
- *
- * @param targetVehicle The vehicle to add the passenger to
- * @param passenger The passenger to teleport and add
- */
- 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");
- }
- }
-
}
diff --git a/src/main/java/net/knarcraft/stargate/thread/BlockChangeThread.java b/src/main/java/net/knarcraft/stargate/thread/BlockChangeThread.java
index d177a0b..faa14fc 100644
--- a/src/main/java/net/knarcraft/stargate/thread/BlockChangeThread.java
+++ b/src/main/java/net/knarcraft/stargate/thread/BlockChangeThread.java
@@ -21,18 +21,22 @@ public class BlockChangeThread implements Runnable {
long sTime = System.nanoTime();
//Repeat for at most 0.025 seconds
while (System.nanoTime() - sTime < 25000000) {
- pollQueue();
+ if (pollQueue()) {
+ break;
+ }
}
}
/**
* Polls the block change request queue for any waiting requests
+ *
+ * @return True if the queue is empty and it's safe to quit
*/
- public static void pollQueue() {
+ public static boolean pollQueue() {
//Abort if there's no work to be done
BlockChangeRequest blockChangeRequest = Stargate.getBlockChangeRequestQueue().poll();
if (blockChangeRequest == null) {
- return;
+ return true;
}
//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
orientBlock(block, blockChangeRequest.getAxis());
}
+ return false;
}
/**
diff --git a/src/main/java/net/knarcraft/stargate/utility/BungeeHelper.java b/src/main/java/net/knarcraft/stargate/utility/BungeeHelper.java
index 00ee6db..677e80f 100644
--- a/src/main/java/net/knarcraft/stargate/utility/BungeeHelper.java
+++ b/src/main/java/net/knarcraft/stargate/utility/BungeeHelper.java
@@ -190,7 +190,7 @@ public final class BungeeHelper {
}
//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
if (!BungeeHelper.sendTeleportationMessage(player, entrancePortal)) {
diff --git a/src/main/java/net/knarcraft/stargate/utility/ColorHelper.java b/src/main/java/net/knarcraft/stargate/utility/ColorHelper.java
index 027bd66..0886b94 100644
--- a/src/main/java/net/knarcraft/stargate/utility/ColorHelper.java
+++ b/src/main/java/net/knarcraft/stargate/utility/ColorHelper.java
@@ -6,7 +6,14 @@ import org.bukkit.Color;
import java.util.regex.Matcher;
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
diff --git a/src/main/java/net/knarcraft/stargate/utility/PermissionHelper.java b/src/main/java/net/knarcraft/stargate/utility/PermissionHelper.java
index 2a8c1ce..f87dc41 100644
--- a/src/main/java/net/knarcraft/stargate/utility/PermissionHelper.java
+++ b/src/main/java/net/knarcraft/stargate/utility/PermissionHelper.java
@@ -387,7 +387,7 @@ public final class PermissionHelper {
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
}
- new PlayerTeleporter(entrancePortal, player).teleport(entrancePortal, event);
+ new PlayerTeleporter(entrancePortal, player).teleportPlayer(entrancePortal, event);
return true;
}
@@ -401,7 +401,7 @@ public final class PermissionHelper {
if (!entrancePortal.getOptions().isSilent()) {
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);
return true;
}
diff --git a/src/main/java/net/knarcraft/stargate/utility/TeleportHelper.java b/src/main/java/net/knarcraft/stargate/utility/TeleportHelper.java
new file mode 100644
index 0000000..97d7868
--- /dev/null
+++ b/src/main/java/net/knarcraft/stargate/utility/TeleportHelper.java
@@ -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
+ *
+ * The teleport helper mainly helps with passengers and leashed creatures
+ */
+public final class TeleportHelper {
+
+ private TeleportHelper() {
+
+ }
+
+ /**
+ * Checks whether a player has leashed creatures that block the teleportation
+ *
+ * @param player The player trying to teleport
+ * @return False if the player has leashed any creatures that cannot go through the portal
+ */
+ public static boolean noLeashedCreaturesPreventTeleportation(Player player) {
+ //Find any nearby leashed entities to teleport with the player
+ List 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 The player to check
+ * @return A list of all creatures the player is holding in a leash (lead)
+ */
+ public static List getLeashedCreatures(Player player) {
+ List leashedCreatures = new ArrayList<>();
+ //Find any nearby leashed entities to teleport with the player
+ List 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
+ *
+ * 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.
+ *
+ * @param targetVehicle The entity to add the passenger to
+ * @param passenger The passenger to teleport and add
+ * @param exitDirection The direction of any passengers exiting the stargate
+ * @param newVelocity The new velocity of the teleported passenger
+ */
+ 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 The passengers to handle
+ * @param entity The entity the passengers should be put into
The portal the entity teleported from
+ * @param target The portal the entity is teleporting to
+ * @param exitRotation The rotation of any passengers exiting the stargate
+ * @param newVelocity The new velocity of the teleported passengers
+ */
+ public static void handleEntityPassengers(List passengers, Entity entity, Portal origin, Portal target,
+ Vector exitRotation, Vector newVelocity) {
+ for (Entity passenger : passengers) {
+ List 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
+ *
+ * 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.
+ *
+ * @param player The player which is teleported
+ * @param origin The portal the player is teleporting from
+ * @param target The portal the player is teleporting to
+ */
+ 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 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 The list of entities to check
+ * @return True if at least one entity is not a player
+ */
+ public static boolean containsNonPlayer(List 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 The list of entities to check
+ * @return True if at least one player is present among the passengers
+ */
+ public static boolean containsPlayer(List 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 The entities to check for players
+ * @return The found players
+ */
+ public static List getPlayers(List entities) {
+ List 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 The player trying to teleport
+ * @param entrancePortal The portal the player is entering
+ * @param destinationPortal The portal the player is to exit from
+ * @return True if the player is allowed to teleport and is able to pay necessary fees
+ */
+ 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);
+ }
+
+}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 46d18d2..b8d6dbc 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -1,7 +1,7 @@
# stargate Configuration File
# 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
# adminUpdateAlert - Whether to alert admins about new plugin updates
adminUpdateAlert: true
@@ -15,6 +15,8 @@ gates:
maxGatesEachNetwork: 0
# defaultGateNetwork - The default gate network
defaultGateNetwork: central
+ # exitVelocity - The velocity to give players exiting stargates, relative to the entry velocity
+ exitVelocity: 0.1
cosmetic:
# rememberDestination - Whether to remember the cursor location between uses
rememberDestination: false
@@ -38,7 +40,8 @@ gates:
destroyedByExplosion: false
# verifyPortals - Whether all the non-sign blocks are checked to match the gate layout when a stargate is loaded.
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
functionality:
enableBungee: false
@@ -46,16 +49,21 @@ gates:
handleVehicles: true
# handleEmptyVehicles - Whether to allow empty vehicles through gates (chest/hopper/tnt/furnace minecarts included)
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
- # 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
# handleLeashedCreatures - Whether to allow creatures lead by a player to teleport with the player
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 #
-# I------------I-------------I #
+# ######################## #
economy:
# useEconomy - Whether to use an economy plugin
useEconomy: false
@@ -74,11 +82,26 @@ economy:
# freeGatesColor - The color to use for marking free gates
freeGatesColor: DARK_GREEN
-# I-------I-------I #
+# ############# #
# Debug options #
-# I-------I-------I #
+# ############# #
debugging:
# debug - Debug -- Only enable if you have issues, massive console output
debug: false
- # permissionDebug - This will output any and all Permissions checks to console, used for permissions debugging (Requires debug: true)
- permissionDebug: false
\ No newline at end of file
+ # permissionDebug - This will output any and all Permissions checks to console, used for permissions debugging
+ # (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
\ No newline at end of file
diff --git a/src/main/resources/lang/ja.txt b/src/main/resources/lang/ja.txt
new file mode 100644
index 0000000..56c2b1d
--- /dev/null
+++ b/src/main/resources/lang/ja.txt
@@ -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 v%version% が見つかりました
+
+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%
diff --git a/src/main/resources/lang/zh_cn.txt b/src/main/resources/lang/zh_cn.txt
new file mode 100644
index 0000000..095fa24
--- /dev/null
+++ b/src/main/resources/lang/zh_cn.txt
@@ -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=此星门网络已满
\ No newline at end of file
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index 6460692..c717434 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -1,12 +1,12 @@
name: Stargate
main: net.knarcraft.stargate.Stargate
-version: 0.9.3.1
+version: 0.9.4.1
description: Stargate mod for Bukkit Revived
author: EpicKnarvik97
authors: [ Drakia, PseudoKnight, EpicKnarvik97 ]
website: https://git.knarcraft.net/EpicKnarvik97/Stargate
api-version: 1.18
-softdepend: [ Vault ]
+softdepend: [ Vault, dynmap ]
commands:
stargate:
aliases: