45 Commits

Author SHA1 Message Date
445638a561 Releases a small hotfix for sign color as version 0.9.2.3 2021-11-25 04:27:36 +01:00
7f9dc6756b Updates version to 0.9.2.2 2021-11-25 03:58:42 +01:00
b2bb995d7e Prevents teleportation of a leashed creature with a passenger 2021-11-25 03:54:09 +01:00
f92fd2de5d Prevents loading of gate files using non-blocks as part of the border 2021-11-25 03:39:15 +01:00
2ed0fe7817 Updates README with recent changes 2021-11-25 03:26:12 +01:00
27b964837f Fixes a potential exception when a portal with an invalid gate type is missing a sign 2021-11-25 03:25:58 +01:00
4b34ea3cf5 Fixes a potential exception when a gate's open-block or closed-block is not a block 2021-11-25 03:25:22 +01:00
0740cd0a66 Removes the error message displayed when teleportation is cancelled because handleLeashedCreatures is disabled
The message should be removed as it's inconsistent with how disabled vehicle teleportation is silent
2021-11-25 02:02:20 +01:00
bab51d76fd Prevents teleportation of players holding one or more creatures on a leash if handleLeashedCreatures is disabled 2021-11-25 01:53:47 +01:00
6ddc15eeef Merge branch 'config-reloading' into dev 2021-11-24 22:39:15 +01:00
14511f558d Updates readme and version to 0.9.2.1
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-24 22:38:44 +01:00
32975ca35d Rewrites a lot of the config command to only do the minimum necessary steps to load the changes
Adds a ConfigTag class for helping to decide the action necessary for updating a given config option
Splits the color setting in PortalSignDrawer as only one color is set at a time when the /config command is used
Updates the configOptions map when a config option is changed
2021-11-24 22:33:45 +01:00
6e7ac5dbb9 Makes the protectEntrance option protect the entrance from all block placement 2021-11-24 22:20:47 +01:00
2b4d15dab4 Adds some boldness to the description and fixes an inaccuracy
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-24 03:06:35 +01:00
22bb75d4df Moves some methods from EconomyConfig to EconomyHelper and tries to simplify EconomyConfig
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-23 07:20:48 +01:00
ab9a118d49 Prevents an empty deny reason from being displayed
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-22 22:01:43 +01:00
a80a8520ce Improves the description of the /sg command 2021-11-22 17:58:56 +01:00
48bb68d665 Adds a missing 'a' in a sentence
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-21 13:34:52 +01:00
1247c54899 Fixes some wrong migration information 2021-11-21 13:10:13 +01:00
37ac3d4877 Fixes a debug route
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-15 17:25:03 +01:00
70495220eb Simplifies some function calls
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-15 17:18:00 +01:00
10c3914a60 Makes the free gate color configurable 2021-11-15 00:35:28 +01:00
4699f717ec Ignores color codes and case when sorting destination names
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-14 14:35:45 +01:00
29c1a00fcd Makes the max portal name and network character limit more easily changeable 2021-11-13 19:28:17 +01:00
51f5420f9e Removes the replacement of spaces to underscores for the cleanString method
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-13 17:04:13 +01:00
e1a3d2d560 Makes a fixed sign always use the destination portal's actual name if possible 2021-11-13 17:02:13 +01:00
a84210d550 Fixes a couple of bugs which prevented portals using spaces in the name from being properly connected 2021-11-13 03:44:27 +01:00
351d1762e7 Updates changelog, and updates version to 0.9.2.0
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-12 15:50:32 +01:00
2c53b7d2a6 Makes portal names and networks case and color-insensitive and increases length limit to 13. #17
Ignores &[0-9a-f] color codes when counting towards the name and network string limits
Makes portal lists store cleaned portal and network names to ignore case and color
Names and networks will now match regardless of case and color
Increases portal name/network limit to 13 characters
2021-11-12 15:33:15 +01:00
42e02eb141 Makes the UUIDMigrationHelper final 2021-11-12 13:46:01 +01:00
ad310ddb9c Allows a sneaking player to see information about a silent stargate (0.9.1.2)
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-10 22:54:20 +01:00
3db630f60e Updates version and changelog
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-09 22:51:11 +01:00
7a03f49fb1 Translates the & character to make sure portal signs are colored on all servers 2021-11-09 22:47:38 +01:00
1c2cad2ec1 Updates version to 0.9.1.0, updates README and adds a permission for changing config values
Adds the stargate.admin.config permission, which is required to use /sg config
2021-11-09 21:16:53 +01:00
b4d908eaa0 Improves tab completion for Stargate commands by taking into account typed text
Sends tab completion for the config command to the config tab completer
2021-11-09 20:58:55 +01:00
8546fd4f78 Fully implements the config command 2021-11-09 20:57:06 +01:00
05328fc456 Adds a tab completer for the config sub-command 2021-11-09 20:56:43 +01:00
aba70b669e Adds a method to be able to read config options 2021-11-09 18:21:25 +01:00
d5f4b87e9b Changes how config values are loaded by using the ConfigOption class 2021-11-09 15:40:10 +01:00
85edaa4657 Adds a new class to represent a data type usable by configs 2021-11-09 15:38:42 +01:00
7c501cefe8 Gives all config options data types to make loading config values work properly 2021-11-09 15:38:10 +01:00
6466c7b0ff Adds the config command to the stargate auto completer
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
Additionally makes the reload command only auto-complete if the command sender can use it
2021-11-09 02:04:59 +01:00
37cf75ada1 Adds the config command as a child to the Stargate command 2021-11-09 02:01:58 +01:00
1ca2d36f5f Adds an unfinished implementation of the config command, which is only able to display config options for now 2021-11-09 02:01:11 +01:00
01b2907b01 Adds an enum containing information about all config options 2021-11-09 01:59:54 +01:00
34 changed files with 1430 additions and 424 deletions

View File

@ -3,17 +3,18 @@
Create gates that allow for instant-teleportation between large distances. Gates can be always-open or triggered; they Create gates that allow for instant-teleportation between large distances. Gates can be always-open or triggered; they
can share a network or be split into clusters; they can be hidden on a network or accessible to everybody. can share a network or be split into clusters; they can be hidden on a network or accessible to everybody.
- Player permissions -- let players build their own networks. - **Player permissions** -- let players build their own networks.
- Vault economy support -- can add costs for create, destroy and use. - **Vault economy support** -- can add costs for create, destroy and use.
- Ability to create custom gate configurations. Three different default gate configurations are available. - **Ability to create custom gate configurations**. Four different default gate configurations are available.
- Message customization - **Message customization**
- Multiple built-in languages (de, en, es, fr, hu, it, nb-no, nl, nn-no, pt-br, ru) - **Multiple built-in languages** (de, en, es, fr, hu, it, nb-no, nl, nn-no, pt-br, ru)
- Teleport across worlds or servers (BungeeCord supported) - **Teleport across worlds or servers** (BungeeCord supported)
- Vehicle teleportation -- teleport minecarts, boats, horses, pigs and striders - **Vehicle teleportation** -- teleport minecarts, boats, horses, pigs and striders
- Leashed teleportation -- teleport any creature in a leash with the player - **Leashed teleportation** -- teleport any creature in a leash with the player
- Underwater portals -- portals can be placed underwater as long as a waterproof button is used - **Underwater portals** -- portals can be placed underwater as long as a waterproof button is used
- API available -- using the API, a lot of behavior can be changed - **API available** -- using the API, a lot of behavior can be changed
- Button customization -- a large amount of materials usable as buttons (buttons, wall corals, shulkers, chests) - **Button customization** -- a large amount of materials usable as buttons (buttons, wall corals, shulkers, chests)
- **Config commands** -- All main config values can be changed from the commandline
## Background ## Background
@ -35,10 +36,8 @@ Permissions have had a few changes, so you should check the permissions section
permissions. permissions.
Payment to owner using Economy, through Vault, is only possible if the portal owner in the portal database is defined by Payment to owner using Economy, through Vault, is only possible if the portal owner in the portal database is defined by
a UUID, and not a username. Right now, there is no automatic upgrade from usernames to UUID. You must either make the a UUID, and not a username. A player name will be upgraded to a UUID when the player with the given name joins the
stargate owner re-create the stargate or edit the file in the portals folder in a text editor. There are various ways to server.
find the UUID of players. You may look in the usercache.json file in the server directory or search for the username on
various websites.
# Permissions # Permissions
@ -80,11 +79,12 @@ stargate.free -- Allow free use/creation/destruction of Stargates
stargate.free.create -- Allow free creation of Stargates stargate.free.create -- Allow free creation of Stargates
stargate.free.destroy -- Allow free destruction of Stargates stargate.free.destroy -- Allow free destruction of Stargates
stargate.admin -- Allow all admin features (Hidden/Private only so far) stargate.admin -- Allow all admin features (Hidden/Private bypass, BungeeCord, Reload, Config)
stargate.admin.private -- Allow use of Private gates not owned by user stargate.admin.private -- Allow use of Private gates not owned by user
stargate.admin.hidden -- Allow access to Hidden gates not ownerd by user stargate.admin.hidden -- Allow access to Hidden gates not ownerd by user
stargate.admin.bungee -- Allow the creation of BungeeCord stargates (U option) stargate.admin.bungee -- Allow the creation of BungeeCord stargates (U option)
stargate.admin.reload -- Allow use of the reload command stargate.admin.reload -- Allow use of the reload command
stargate.admin.config -- Allows the player to change config values from the chat
``` ```
## Default Permissions ## Default Permissions
@ -117,9 +117,9 @@ section). See the Custom Gate Layout section to learn how to add custom gates.
### Sign Layout: ### Sign Layout:
- Line 1: Gate Name (Max 11 characters) - Line 1: Gate Name (Max 13 characters)
- Line 2: Destination Name \[Optional] (Max 11 characters, used for fixed-gates only) - Line 2: Destination Name \[Optional] (Max 13 characters, used for fixed-gates only)
- Line 3: Network name \[Optional] (Max 11 characters) - Line 3: Network name \[Optional] (Max 13 characters)
- Line 4: Options \[Optional] : - Line 4: Options \[Optional] :
- 'A' for always-on fixed gate - 'A' for always-on fixed gate
- 'H' for hidden networked gate - 'H' for hidden networked gate
@ -132,9 +132,11 @@ section). See the Custom Gate Layout section to learn how to add custom gates.
player enters. (Implicitly always on) player enters. (Implicitly always on)
- 'U' is for a gate connecting to another through bungee (Implicitly always on) - 'U' is for a gate connecting to another through bungee (Implicitly always on)
- 'I' is for a silent gate, which does not output anything to the chat while teleporting. Increases immersion - 'I' is for a silent gate, which does not output anything to the chat while teleporting. Increases immersion
- 'E' is for gate without a sign. Only for fixed stargates - 'E' is for a gate without a sign. Only for fixed stargates
The options are the single letter, not the word. So to make a private hidden gate, your 4th line would be 'PH'. The options are the single letter, not the word. So to make a private hidden gate, your 4th line would be 'PH'. The
&\[0-9a-f] color codes are not counted in the character limit, thus allowing a 13-character name with an additional 2
characters used for the color code.
#### Gate networks: #### Gate networks:
@ -321,7 +323,8 @@ economy:
useCost - The cost to use a stargate useCost - The cost to use a stargate
toOwner - Whether the money from gate-use goes to the owner or nobody toOwner - Whether the money from gate-use goes to the owner or nobody
chargeFreeDestination - Enable to make players pay for teleportation even if the destination is free chargeFreeDestination - Enable to make players pay for teleportation even if the destination is free
freeGatesGreen - Enable to make gates that won't cost the player money show up as green freeGatesColored - Enable to make gates that won't cost the player money show up as green
freeGatesColor - This allows you to specify the color of the markings and name of free stargates
debugging: debugging:
debug - Whether to show massive debug output debug - Whether to show massive debug output
permissionDebug - Whether to show massive permission debug output permissionDebug - Whether to show massive permission debug output
@ -386,6 +389,48 @@ portalInfoServer=Server: %server%
# Changes # Changes
#### \[Version 0.9.2.3] EpicKnarvik97 fork
- Fixes a typo which caused both colors to change into the highlightSignColor
#### \[Version 0.9.2.2] EpicKnarvik97 fork
- Prevents teleportation of a player holding creatures on a leash when handleLeashedCreatures is disabled, to prevent
players accidentally losing the creatures during teleportation
- Fixes a potential exception when a gate's open-block or closed-block is set to a material which isn't a block
- Fixes a potential exception when a portal without a sign has an invalid gate type
- Prevents loading of gate files using non-blocks as part of the border
- Prevents a player smuggling another player through a restricted stargate by sitting on a creature held in a lead by
the first player
#### \[Version 0.9.2.1] EpicKnarvik97 fork
- Makes sure to only reload whatever is necessary when config values are changed using commands, instead of reloading
the entire config file every time
- Protects portals from block placement when protectEntrance is enabled
#### \[Version 0.9.2.0] EpicKnarvik97 fork
- Increases max length of names and networks to 13 characters
- Excludes color codes from the counted character length to allow a colored, 13-character name
- Makes portal names and networks case- and color-agnostic to prevent some confusion caused by typos or sloppy
configuration
- Makes the free gate color configurable, and renames freeGatesGreen to freeGatesColored
#### \[Version 0.9.1.2] EpicKnarvik97 fork
- Allows a sneaking player to see information about a silent stargate with no sign
#### \[Version 0.9.1.1] EpicKnarvik97 fork
- Makes sure to translate the `&` character to fix a bug causing portal signs to not be colored on some servers
#### \[Version 0.9.1.0] EpicKnarvik97 fork
- Rewrites config loading as a part of the changes required to implement config commands
- This update adds commands to change all config values from the chat or the console, complete with tab completion
- Adds a new permission "stargate.admin.config" which is required to edit config values from the chat
#### \[Version 0.9.0.7] EpicKnarvik97 fork #### \[Version 0.9.0.7] EpicKnarvik97 fork
- Stops registering the sign as a lookup block for stargates without a sign - Stops registering the sign as a lookup block for stargates without a sign

View File

@ -4,7 +4,7 @@
<groupId>net.knarcraft</groupId> <groupId>net.knarcraft</groupId>
<artifactId>Stargate</artifactId> <artifactId>Stargate</artifactId>
<version>0.9.0.7</version> <version>0.9.2.3</version>
<licenses> <licenses>
<license> <license>

View File

@ -139,6 +139,16 @@ public class Stargate extends JavaPlugin {
return logger; return logger;
} }
/**
* Gets the max length of portal names and networks
*
* @return <p>The max portal name/network length</p>
*/
@SuppressWarnings("SameReturnValue")
public static int getMaxNameNetworkLength() {
return 13;
}
/** /**
* Sends a debug message * Sends a debug message
* *

View File

@ -0,0 +1,249 @@
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.portal.Portal;
import net.knarcraft.stargate.portal.PortalRegistry;
import net.knarcraft.stargate.portal.PortalSignDrawer;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* This command represents the config command for changing config values
*/
public class CommandConfig implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] args) {
if (commandSender instanceof Player player) {
if (!player.hasPermission("stargate.admin.config")) {
Stargate.getMessageSender().sendErrorMessage(commandSender, "Permission Denied");
return true;
}
}
if (args.length > 0) {
ConfigOption selectedOption = ConfigOption.getByName(args[0]);
if (selectedOption == null) {
return false;
}
if (args.length > 1) {
updateConfigValue(selectedOption, commandSender, args[1]);
} else {
//Display info and the current value of the given config value
printConfigOptionValue(commandSender, selectedOption);
}
return true;
} else {
//Display all config options
displayConfigValues(commandSender);
}
return true;
}
/**
* Updates a config value
*
* @param selectedOption <p>The option which should be updated</p>
* @param commandSender <p>The command sender that changed the value</p>
* @param value <p>The new value of the config option</p>
*/
private void updateConfigValue(ConfigOption selectedOption, CommandSender commandSender, String value) {
FileConfiguration configuration = Stargate.getInstance().getConfig();
//Validate any sign colors
if (ConfigTag.COLOR.isTagged(selectedOption)) {
try {
ChatColor.valueOf(value.toUpperCase());
} catch (IllegalArgumentException | NullPointerException ignored) {
commandSender.sendMessage(ChatColor.RED + "Invalid color given");
return;
}
}
//Store the config values, accounting for the data type
switch (selectedOption.getDataType()) {
case BOOLEAN -> {
boolean newValue = Boolean.parseBoolean(value);
if (selectedOption == ConfigOption.ENABLE_BUNGEE && newValue != Stargate.getGateConfig().enableBungee()) {
Stargate.getStargateConfig().startStopBungeeListener(newValue);
}
Stargate.getStargateConfig().getConfigOptionsReference().put(selectedOption, newValue);
configuration.set(selectedOption.getConfigNode(), newValue);
}
case INTEGER -> {
Integer intValue = getInteger(commandSender, selectedOption, value);
if (intValue == null) {
return;
} else {
Stargate.getStargateConfig().getConfigOptionsReference().put(selectedOption, intValue);
configuration.set(selectedOption.getConfigNode(), intValue);
}
}
case STRING -> {
if (selectedOption == ConfigOption.GATE_FOLDER || selectedOption == ConfigOption.PORTAL_FOLDER ||
selectedOption == ConfigOption.DEFAULT_GATE_NETWORK) {
if (value.contains("../") || value.contains("..\\")) {
commandSender.sendMessage(ChatColor.RED + "Path traversal characters cannot be used");
return;
}
}
if (ConfigTag.COLOR.isTagged(selectedOption)) {
if (!registerColor(selectedOption, value, commandSender)) {
return;
}
}
if (selectedOption == ConfigOption.LANGUAGE) {
Stargate.getStargateConfig().getLanguageLoader().setChosenLanguage(value);
}
Stargate.getStargateConfig().getConfigOptionsReference().put(selectedOption, value);
configuration.set(selectedOption.getConfigNode(), value);
}
default -> {
Stargate.getStargateConfig().getConfigOptionsReference().put(selectedOption, value);
configuration.set(selectedOption.getConfigNode(), value);
}
}
//Save the config file and reload if necessary
Stargate.getInstance().saveConfig();
Stargate.getMessageSender().sendSuccessMessage(commandSender, "Config updated");
//Reload whatever is necessary
reloadIfNecessary(commandSender, selectedOption);
}
/**
* Registers the chat color if
*
* @param selectedOption <p>The option to change</p>
* @param commandSender <p>The command sender to alert if the color is invalid</p>
* @param value <p>The new option value</p>
*/
private boolean registerColor(ConfigOption selectedOption, String value, CommandSender commandSender) {
ChatColor parsedColor = parseColor(value);
if (parsedColor == null) {
commandSender.sendMessage(ChatColor.RED + "Invalid color given");
return false;
}
if (selectedOption == ConfigOption.FREE_GATES_COLOR) {
PortalSignDrawer.setFreeColor(parsedColor);
} else if (selectedOption == ConfigOption.MAIN_SIGN_COLOR) {
PortalSignDrawer.setMainColor(parsedColor);
} else if (selectedOption == ConfigOption.HIGHLIGHT_SIGN_COLOR) {
PortalSignDrawer.setHighlightColor(parsedColor);
}
return true;
}
/**
* Parses a chat color
*
* @param value <p>The value to parse</p>
* @return <p>The parsed color or null</p>
*/
private ChatColor parseColor(String value) {
try {
return ChatColor.valueOf(value.toUpperCase());
} catch (IllegalArgumentException | NullPointerException ignored) {
return null;
}
}
/**
* Gets an integer from a string
*
* @param commandSender <p>The command sender that sent the config command</p>
* @param selectedOption <p>The option the command sender is trying to change</p>
* @param value <p>The value given</p>
* @return <p>An integer, or null if it was invalid</p>
*/
private Integer getInteger(CommandSender commandSender, ConfigOption selectedOption, String value) {
try {
int intValue = Integer.parseInt(value);
if ((selectedOption == ConfigOption.USE_COST || selectedOption == ConfigOption.CREATE_COST) && intValue < 0) {
commandSender.sendMessage(ChatColor.RED + "This config option cannot be negative.");
return null;
}
return intValue;
} catch (NumberFormatException exception) {
commandSender.sendMessage(ChatColor.RED + "Invalid number given");
return null;
}
}
/**
* Reloads the config if necessary
*
* @param commandSender <p>The command sender initiating the reload</p>
* @param configOption <p>The changed config option</p>
*/
private void reloadIfNecessary(CommandSender commandSender, ConfigOption configOption) {
if (ConfigTag.requiresFullReload(configOption)) {
//Reload everything
Stargate.getStargateConfig().reload(commandSender);
} else if (ConfigTag.requiresPortalReload(configOption)) {
//Just unload and reload the portals
Stargate.getStargateConfig().unloadAllPortals();
Stargate.getStargateConfig().loadAllPortals();
} else if (ConfigTag.requiresLanguageReload(configOption)) {
//Reload the language loader
Stargate.getStargateConfig().getLanguageLoader().reload();
//Re-draw all portal signs
for (Portal portal : PortalRegistry.getAllPortals()) {
portal.drawSign();
}
} else if (ConfigTag.requiresEconomyReload(configOption)) {
//Load or unload Vault and Economy as necessary
Stargate.getStargateConfig().reloadEconomy();
}
}
/**
* Prints information about a config option and its current value
*
* @param sender <p>The command sender that sent the command</p>
* @param option <p>The config option to print information about</p>
*/
private void printConfigOptionValue(CommandSender sender, ConfigOption option) {
Object value = Stargate.getStargateConfig().getConfigOptions().get(option);
sender.sendMessage(getOptionDescription(option));
sender.sendMessage(ChatColor.GREEN + "Current value: " + ChatColor.GOLD + value);
}
/**
* Displays the name and a small description of every config value
*
* @param sender <p>The command sender to display the config list to</p>
*/
private void displayConfigValues(CommandSender sender) {
sender.sendMessage(ChatColor.GREEN + Stargate.getBackupString("prefix") + ChatColor.GOLD +
"Config values:");
for (ConfigOption option : ConfigOption.values()) {
sender.sendMessage(getOptionDescription(option));
}
}
/**
* Gets the description of a single config option
*
* @param option <p>The option to describe</p>
* @return <p>A string describing the config option</p>
*/
private String getOptionDescription(ConfigOption option) {
return ChatColor.GOLD + option.getName() + ChatColor.WHITE + " - " + ChatColor.GREEN + option.getDescription() +
ChatColor.DARK_GRAY + " (Default: " + ChatColor.GRAY + option.getDefaultValue() + ChatColor.DARK_GRAY + ")";
}
}

View File

@ -1,6 +1,7 @@
package net.knarcraft.stargate.command; package net.knarcraft.stargate.command;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import org.apache.commons.lang.ArrayUtils;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
@ -23,6 +24,9 @@ public class CommandStarGate implements CommandExecutor {
return new CommandAbout().onCommand(commandSender, command, s, args); return new CommandAbout().onCommand(commandSender, command, s, args);
} else if (args[0].equalsIgnoreCase("reload")) { } else if (args[0].equalsIgnoreCase("reload")) {
return new CommandReload().onCommand(commandSender, command, s, args); return new CommandReload().onCommand(commandSender, command, s, args);
} else if (args[0].equalsIgnoreCase("config")) {
String[] subArgs = (String[]) ArrayUtils.remove(args, 0);
return new CommandConfig().onCommand(commandSender, command, s, subArgs);
} }
return false; return false;
} else { } else {

View File

@ -0,0 +1,183 @@
package net.knarcraft.stargate.command;
import net.knarcraft.stargate.config.ConfigOption;
import net.knarcraft.stargate.config.OptionDataType;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* This is the completer for stargates config sub-command (/sg config)
*/
public class ConfigTabCompleter implements TabCompleter {
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] args) {
if (args.length > 1) {
ConfigOption selectedOption = ConfigOption.getByName(args[0]);
if (selectedOption == null) {
return new ArrayList<>();
} else {
return getPossibleOptionValues(selectedOption, args[1]);
}
} else {
List<String> configOptionNames = new ArrayList<>();
for (ConfigOption option : ConfigOption.values()) {
configOptionNames.add(option.getName());
}
return filterMatching(configOptionNames, args[0]);
}
}
/**
* Find completable strings which match the text typed by the command's sender
*
* @param values <p>The values to filter</p>
* @param typedText <p>The text the player has started typing</p>
* @return <p>The given string values which start with the player's typed text</p>
*/
private List<String> filterMatching(List<String> values, String typedText) {
List<String> configValues = new ArrayList<>();
for (String value : values) {
if (value.toLowerCase().startsWith(typedText.toLowerCase())) {
configValues.add(value);
}
}
return configValues;
}
/**
* Get possible values for the selected option
*
* @param selectedOption <p>The selected option</p>
* @param typedText <p>The beginning of the typed text, for filtering matching results</p>
* @return <p>Some or all of the valid values for the option</p>
*/
private List<String> getPossibleOptionValues(ConfigOption selectedOption, String typedText) {
List<String> booleans = new ArrayList<>();
booleans.add("true");
booleans.add("false");
List<String> numbers = new ArrayList<>();
numbers.add("0");
numbers.add("5");
switch (selectedOption) {
case LANGUAGE:
//Return available languages
return filterMatching(getLanguages(), typedText);
case GATE_FOLDER:
case PORTAL_FOLDER:
case DEFAULT_GATE_NETWORK:
//Just return the default value as most values should be possible
if (typedText.trim().isEmpty()) {
return putStringInList((String) selectedOption.getDefaultValue());
} else {
return new ArrayList<>();
}
case MAIN_SIGN_COLOR:
case HIGHLIGHT_SIGN_COLOR:
case FREE_GATES_COLOR:
//Return all colors
return filterMatching(getColors(), typedText);
}
//If the config value is a boolean, show the two boolean values
if (selectedOption.getDataType() == OptionDataType.BOOLEAN) {
return filterMatching(booleans, typedText);
}
//If the config value is an integer, display some valid numbers
if (selectedOption.getDataType() == OptionDataType.INTEGER) {
if (typedText.trim().isEmpty()) {
return numbers;
} else {
return new ArrayList<>();
}
}
return null;
}
/**
* Gets all available languages
*
* @return <p>The available languages</p>
*/
private List<String> getLanguages() {
List<String> languages = new ArrayList<>();
languages.add("de");
languages.add("en");
languages.add("es");
languages.add("fr");
languages.add("hu");
languages.add("it");
languages.add("nb-no");
languages.add("nl");
languages.add("nn-no");
languages.add("pt-br");
languages.add("ru");
return languages;
}
/**
* Gets all available colors
*
* @return <p>All available colors</p>
*/
private List<String> getColors() {
List<String> colors = new ArrayList<>();
for (ChatColor color : getChatColors()) {
colors.add(color.name());
}
return colors;
}
/**
* Gets a list of all available chat colors
*
* @return <p>A list of chat colors</p>
*/
private List<ChatColor> getChatColors() {
List<ChatColor> 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);
return chatColors;
}
/**
* Puts a single string value into a string list
*
* @param value <p>The string to make into a list</p>
* @return <p>A list containing the string value</p>
*/
private List<String> putStringInList(String value) {
List<String> list = new ArrayList<>();
list.add(value);
return list;
}
}

View File

@ -1,8 +1,10 @@
package net.knarcraft.stargate.command; package net.knarcraft.stargate.command;
import org.apache.commons.lang.ArrayUtils;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter; import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -17,15 +19,39 @@ public class StarGateTabCompleter implements TabCompleter {
@Override @Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, public @Nullable List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command,
@NotNull String s, @NotNull String[] args) { @NotNull String s, @NotNull String[] args) {
List<String> commands = new ArrayList<>();
commands.add("about");
commands.add("reload");
if (args.length == 1) { if (args.length == 1) {
return commands; List<String> commands = getAvailableCommands(commandSender);
List<String> matchingCommands = new ArrayList<>();
for (String availableCommand : commands) {
if (availableCommand.startsWith(args[0])) {
matchingCommands.add(availableCommand);
}
}
return matchingCommands;
} else if (args.length > 1 && args[0].equalsIgnoreCase("config")) {
String[] subArgs = (String[]) ArrayUtils.remove(args, 0);
return new ConfigTabCompleter().onTabComplete(commandSender, command, s, subArgs);
} else { } else {
return new ArrayList<>(); return new ArrayList<>();
} }
} }
/**
* Gets the available commands
*
* @param commandSender <p>The command sender to get available commands for</p>
* @return <p>The commands available to the command sender</p>
*/
private List<String> getAvailableCommands(CommandSender commandSender) {
List<String> commands = new ArrayList<>();
commands.add("about");
if (!(commandSender instanceof Player player) || player.hasPermission("stargate.admin.reload")) {
commands.add("reload");
}
if (!(commandSender instanceof Player player) || player.hasPermission("stargate.admin.config")) {
commands.add("config");
}
return commands;
}
} }

View File

@ -0,0 +1,245 @@
package net.knarcraft.stargate.config;
/**
* A ConfigOption represents one of the available config options
*/
public enum ConfigOption {
/**
* The language used for player-interface text
*/
LANGUAGE("language", "The language used for all signs and all messages to players", "en"),
/**
* The folder for portal files
*/
PORTAL_FOLDER("folders.portalFolder", "The folder containing the portal databases", "plugins/Stargate/portals/"),
/**
* The folder for gate files
*/
GATE_FOLDER("folders.gateFolder", "The folder containing all gate files", "plugins/Stargate/gates/"),
/**
* The max number of portals on a single network
*/
MAX_GATES_EACH_NETWORK("gates.maxGatesEachNetwork", "The max number of stargates in a single network", 0),
/**
* The network used if not specified
*/
DEFAULT_GATE_NETWORK("gates.defaultGateNetwork", "The network used when no network is specified", "central"),
/**
* Whether to remember the lastly used destination
*/
REMEMBER_DESTINATION("gates.cosmetic.rememberDestination", "Whether to remember the last destination used", false),
/**
* Whether to sort the network destinations
*/
SORT_NETWORK_DESTINATIONS("gates.cosmetic.sortNetworkDestinations", "Whether to sort destinations by name", false),
/**
* The main color to use for all signs
*/
MAIN_SIGN_COLOR("gates.cosmetic.mainSignColor", "The main text color of all stargate signs", "BLACK"),
/**
* The color to use for highlighting sign text
*/
HIGHLIGHT_SIGN_COLOR("gates.cosmetic.highlightSignColor", "The text color used for highlighting stargate signs", "WHITE"),
/**
* Whether to destroy portals when any blocks are broken by explosions
*/
DESTROYED_BY_EXPLOSION("gates.integrity.destroyedByExplosion", "Whether stargates should be destroyed by explosions", false),
/**
* Whether to verify each portal's gate layout after each load
*/
VERIFY_PORTALS("gates.integrity.verifyPortals", "Whether to verify that portals match their gate layout on load", false),
/**
* Whether to protect the entrance of portals
*/
PROTECT_ENTRANCE("gates.integrity.protectEntrance", "Whether to protect stargates' entrances", false),
/**
* Whether to enable BungeeCord support
*/
ENABLE_BUNGEE("gates.functionality.enableBungee", "Whether to enable BungeeCord support", false),
/**
* Whether to enable vehicle teleportation
*/
HANDLE_VEHICLES("gates.functionality.handleVehicles", "Whether to enable vehicle teleportation", true),
/**
* Whether to enable teleportation of empty vehicles
*/
HANDLE_EMPTY_VEHICLES("gates.functionality.handleEmptyVehicles", "Whether to enable teleportation of empty vehicles", true),
/**
* Whether to enable teleportation of creatures using vehicles
*/
HANDLE_CREATURE_TRANSPORTATION("gates.functionality.handleCreatureTransportation",
"Whether to enable teleportation of vehicles containing non-player creatures", true),
/**
* Whether to allow creatures to teleport alone, bypassing any access restrictions
*/
HANDLE_NON_PLAYER_VEHICLES("gates.functionality.handleNonPlayerVehicles",
"Whether to enable teleportation of non-empty vehicles without a player", true),
/**
* Whether to enable teleportations of creatures on a leash
*/
HANDLE_LEASHED_CREATURES("gates.functionality.handleLeashedCreatures",
"Whether to enable players to teleport a creature on a leash", true),
/**
* Whether to enable economy support for taking payment from players creating/destroying/using stargates
*/
USE_ECONOMY("economy.useEconomy", "Whether to use economy to incur fees when stargates are used, created or destroyed", false),
/**
* The cost of creating a new stargate
*/
CREATE_COST("economy.createCost", "The cost of creating a new stargate", 0),
/**
* The cost of destroying a stargate
*/
DESTROY_COST("economy.destroyCost", "The cost of destroying a stargate. Negative to refund", 0),
/**
* The cost of using (teleporting through) a stargate
*/
USE_COST("economy.useCost", "The cost of using (teleporting through) a stargate", 0),
/**
* Whether any payments should go to the stargate's owner
*/
TO_OWNER("economy.toOwner", "Whether any teleportation fees should go to the owner of the used stargate", false),
/**
* Whether to charge for using a stargate, even if its destination is free
*/
CHARGE_FREE_DESTINATION("economy.chargeFreeDestination",
"Whether to require payment if the destination is free, but the entrance stargate is not", true),
/**
* Whether to mark free gates with a different color
*/
FREE_GATES_COLORED("economy.freeGatesColored", "Whether to use coloring to mark all free stargates", false),
/**
* The color to use for marking free stargates
*/
FREE_GATES_COLOR("economy.freeGatesColor", "The color to use for marking free stargates", "DARK_GREEN"),
/**
* Whether to enable debug output
*/
DEBUG("debugging.debug", "Whether to enable debugging output", false),
/**
* Whether to enable debug output for debugging permissions
*/
PERMISSION_DEBUG("debugging.permissionDebug", "Whether to enable permission debugging output", false);
private final String configNode;
private final String description;
private final Object defaultValue;
private final OptionDataType dataType;
/**
* Instantiates a new config option
*
* @param configNode <p>The full path of this config option's config node</p>
* @param description <p>The description of what this config option does</p>
* @param defaultValue <p>The default value of this config option</p>
*/
ConfigOption(String configNode, String description, Object defaultValue) {
this.configNode = configNode;
this.description = description;
this.defaultValue = defaultValue;
if (defaultValue instanceof String) {
this.dataType = OptionDataType.STRING;
} else if (defaultValue instanceof Boolean) {
this.dataType = OptionDataType.BOOLEAN;
} else if (defaultValue instanceof Integer) {
this.dataType = OptionDataType.INTEGER;
} else {
throw new IllegalArgumentException("Unknown config data type encountered.");
}
}
/**
* Gets a config option given its name
*
* @param name <p>The name of the config option to get</p>
* @return <p>The corresponding config option, or null if the name is invalid</p>
*/
public static ConfigOption getByName(String name) {
for (ConfigOption option : ConfigOption.values()) {
if (option.getName().equalsIgnoreCase(name)) {
return option;
}
}
return null;
}
/**
* Gets the name of this config option
*
* @return <p>The name of this config option</p>
*/
public String getName() {
if (!this.configNode.contains(".")) {
return this.configNode;
}
String[] pathParts = this.configNode.split("\\.");
return pathParts[pathParts.length - 1];
}
/**
* Gets the data type used for storing this config option
*
* @return <p>The data type used</p>
*/
public OptionDataType getDataType() {
return this.dataType;
}
/**
* Gets the config node of this config option
*
* @return <p>This config option's config node</p>
*/
public String getConfigNode() {
return this.configNode;
}
/**
* Gets the description of what this config option does
*
* @return <p>The description of this config option</p>
*/
public String getDescription() {
return this.description;
}
/**
* Gets this config option's default value
*
* @return <p>This config option's default value</p>
*/
public Object getDefaultValue() {
return this.defaultValue;
}
}

View File

@ -0,0 +1,74 @@
package net.knarcraft.stargate.config;
import java.util.Arrays;
/**
* A config tag groups config values by a property
*/
public enum ConfigTag {
COLOR(new ConfigOption[]{ConfigOption.FREE_GATES_COLOR, ConfigOption.MAIN_SIGN_COLOR, ConfigOption.HIGHLIGHT_SIGN_COLOR}),
FOLDER(new ConfigOption[]{ConfigOption.GATE_FOLDER, ConfigOption.PORTAL_FOLDER});
private final ConfigOption[] taggedOptions;
/**
* Instantiates a new config tag
*
* @param taggedOptions <p>The config options included in this tag</p>
*/
ConfigTag(ConfigOption[] taggedOptions) {
this.taggedOptions = taggedOptions;
}
/**
* Checks whether a config tag includes the given config option
*
* @param option <p>The config option to check</p>
* @return <p>True of the config option is tagged</p>
*/
public boolean isTagged(ConfigOption option) {
return Arrays.stream(taggedOptions).anyMatch((item) -> item == option);
}
/**
* Checks whether a given config option requires a full reload to take effect
*
* @param option <p>The config option to check</p>
* @return <p>True if changing the config option requires a full reload to take effect</p>
*/
public static boolean requiresFullReload(ConfigOption option) {
return FOLDER.isTagged(option);
}
/**
* Checks whether a given config option requires a portal reload to take effect
*
* @param option <p>The config option to check</p>
* @return <p>True if changing the config option requires a portal reload to take effect</p>
*/
public static boolean requiresPortalReload(ConfigOption option) {
return COLOR.isTagged(option) || FOLDER.isTagged(option) || option == ConfigOption.VERIFY_PORTALS;
}
/**
* Checks whether a given config option requires the language loader to be reloaded
*
* @param option <p>The config option to check</p>
* @return <p>True if the language loader requires a reload</p>
*/
public static boolean requiresLanguageReload(ConfigOption option) {
return option == ConfigOption.LANGUAGE;
}
/**
* Checks whether a given config option requires economy to be reloaded
*
* @param option <p>The config option to check</p>
* @return <p>True if economy requires a reload</p>
*/
public static boolean requiresEconomyReload(ConfigOption option) {
return option == ConfigOption.USE_ECONOMY;
}
}

View File

@ -1,42 +1,42 @@
package net.knarcraft.stargate.config; package net.knarcraft.stargate.config;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.PortalSignDrawer;
import net.knarcraft.stargate.portal.property.gate.Gate; import net.knarcraft.stargate.portal.property.gate.Gate;
import net.knarcraft.stargate.utility.PermissionHelper; import net.knarcraft.stargate.utility.PermissionHelper;
import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit; import org.bukkit.ChatColor;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.ServicesManager; import org.bukkit.plugin.ServicesManager;
import java.util.UUID; import java.util.Map;
/** /**
* The economy config keeps track of economy config values and performs economy actions such as payment for using a gate * The economy config keeps track of economy config values and performs economy actions such as payment for using a gate
*/ */
public final class EconomyConfig { public final class EconomyConfig {
private boolean economyEnabled = false;
private Economy economy = null; private Economy economy = null;
private Plugin vault = null; private Plugin vault = null;
private int useCost = 0;
private int createCost = 0; private final Map<ConfigOption, Object> configOptions;
private int destroyCost = 0;
private boolean toOwner = false;
private boolean chargeFreeDestination = true;
private boolean freeGatesGreen = false;
/** /**
* Instantiates a new economy config * Instantiates a new economy config
* *
* @param newConfig <p>The file configuration to read values from</p> * @param configOptions <p>The loaded config options to read</p>
*/ */
public EconomyConfig(FileConfiguration newConfig) { public EconomyConfig(Map<ConfigOption, Object> configOptions) {
loadEconomyConfig(newConfig); this.configOptions = configOptions;
try {
String freeColor = (String) configOptions.get(ConfigOption.FREE_GATES_COLOR);
PortalSignDrawer.setFreeColor(ChatColor.valueOf(freeColor.toUpperCase()));
} catch (IllegalArgumentException | NullPointerException ignored) {
PortalSignDrawer.setFreeColor(ChatColor.DARK_GREEN);
}
} }
/** /**
@ -45,7 +45,7 @@ public final class EconomyConfig {
* @return <p>The gate use cost</p> * @return <p>The gate use cost</p>
*/ */
public int getDefaultUseCost() { public int getDefaultUseCost() {
return useCost; return (Integer) configOptions.get(ConfigOption.USE_COST);
} }
/** /**
@ -54,7 +54,7 @@ public final class EconomyConfig {
* @return <p>Whether economy is enabled</p> * @return <p>Whether economy is enabled</p>
*/ */
public boolean isEconomyEnabled() { public boolean isEconomyEnabled() {
return economyEnabled; return (boolean) configOptions.get(ConfigOption.USE_ECONOMY);
} }
/** /**
@ -84,12 +84,12 @@ public final class EconomyConfig {
} }
/** /**
* Gets whether free portals should be marked with green coloring * Gets whether free portals should be marked with a different coloring
* *
* @return <p>Whether free portals should be green</p> * @return <p>Whether free portals should be colored</p>
*/ */
public boolean drawFreePortalsGreen() { public boolean drawFreePortalsColored() {
return freeGatesGreen; return (boolean) configOptions.get(ConfigOption.FREE_GATES_COLORED);
} }
/** /**
@ -101,8 +101,8 @@ public final class EconomyConfig {
* *
* @return <p>Whether to charge for free destinations</p> * @return <p>Whether to charge for free destinations</p>
*/ */
public boolean chargeFreeDestination() { public boolean freeIfFreeDestination() {
return chargeFreeDestination; return !((boolean) configOptions.get(ConfigOption.CHARGE_FREE_DESTINATION));
} }
/** /**
@ -111,21 +111,7 @@ public final class EconomyConfig {
* @return <p>Whether to send payments to the portal owner</p> * @return <p>Whether to send payments to the portal owner</p>
*/ */
public boolean sendPaymentToOwner() { public boolean sendPaymentToOwner() {
return toOwner; return (boolean) configOptions.get(ConfigOption.TO_OWNER);
}
/**
* Sets the cost of using a gate without a specified cost
*
* <p>The use cost cannot be negative.</p>
*
* @param useCost <p>The gate use cost</p>
*/
public void setDefaultUseCost(int useCost) {
if (useCost < 0) {
throw new IllegalArgumentException("Using a gate cannot cost a negative amount");
}
this.useCost = useCost;
} }
/** /**
@ -134,18 +120,7 @@ public final class EconomyConfig {
* @return <p>The gate creation cost</p> * @return <p>The gate creation cost</p>
*/ */
public int getDefaultCreateCost() { public int getDefaultCreateCost() {
return createCost; return (Integer) configOptions.get(ConfigOption.CREATE_COST);
}
/**
* Sets the cost of creating a gate without a specified cost
*
* <p>The gate create cost cannot be negative</p>
*
* @param createCost <p>The gate creation cost</p>
*/
public void setDefaultCreateCost(int createCost) {
this.createCost = createCost;
} }
/** /**
@ -154,31 +129,7 @@ public final class EconomyConfig {
* @return <p>The gate destruction cost</p> * @return <p>The gate destruction cost</p>
*/ */
public int getDefaultDestroyCost() { public int getDefaultDestroyCost() {
return destroyCost; return (Integer) configOptions.get(ConfigOption.DESTROY_COST);
}
/**
* Sets the cost of destroying a gate without a specified cost
*
* @param destroyCost <p>The gate destruction cost</p>
*/
public void setDefaultDestroyCost(int destroyCost) {
this.destroyCost = destroyCost;
}
/**
* Charges the player for an action, if required
*
* @param player <p>The player to take money from</p>
* @param cost <p>The cost of the transaction</p>
* @return <p>True if the player was charged successfully</p>
*/
public boolean chargePlayerIfNecessary(Player player, int cost) {
if (skipPayment(cost)) {
return true;
}
//Charge player
return chargePlayer(player, cost);
} }
/** /**
@ -192,22 +143,6 @@ public final class EconomyConfig {
return economy.getBalance(player) > cost; return economy.getBalance(player) > cost;
} }
/**
* Charges the player for an action, if required
*
* @param player <p>The player to take money from</p>
* @param target <p>The target to pay</p>
* @param cost <p>The cost of the transaction</p>
* @return <p>True if the player was charged successfully</p>
*/
public boolean chargePlayerIfNecessary(Player player, UUID target, int cost) {
if (skipPayment(cost)) {
return true;
}
//Charge player
return chargePlayer(player, target, cost);
}
/** /**
* Gets a formatted string for an amount, adding the name of the currency * Gets a formatted string for an amount, adding the name of the currency
* *
@ -215,7 +150,7 @@ public final class EconomyConfig {
* @return <p>A formatted text string describing the amount</p> * @return <p>A formatted text string describing the amount</p>
*/ */
public String format(int amount) { public String format(int amount) {
if (economyEnabled) { if (isEconomyEnabled()) {
return economy.format(amount); return economy.format(amount);
} else { } else {
return ""; return "";
@ -229,7 +164,7 @@ public final class EconomyConfig {
* @return <p>True if economy was enabled</p> * @return <p>True if economy was enabled</p>
*/ */
public boolean setupEconomy(PluginManager pluginManager) { public boolean setupEconomy(PluginManager pluginManager) {
if (!economyEnabled) { if (!isEconomyEnabled()) {
return false; return false;
} }
//Check if vault is loaded //Check if vault is loaded
@ -247,7 +182,7 @@ public final class EconomyConfig {
} else { } else {
Stargate.logInfo(Stargate.getString("vaultLoadError")); Stargate.logInfo(Stargate.getString("vaultLoadError"));
} }
economyEnabled = false; configOptions.put(ConfigOption.USE_ECONOMY, false);
return false; return false;
} }
@ -257,46 +192,7 @@ public final class EconomyConfig {
* @return <p>True if the user has turned on economy and economy is available</p> * @return <p>True if the user has turned on economy and economy is available</p>
*/ */
public boolean useEconomy() { public boolean useEconomy() {
return economyEnabled && economy != null; return isEconomyEnabled() && economy != null;
}
/**
* Checks whether a payment transaction should be skipped
*
* @param cost <p>The cost of the transaction</p>
* @return <p>True if the transaction should be skipped</p>
*/
private boolean skipPayment(int cost) {
return cost == 0 || !useEconomy();
}
/**
* Determines the cost of using a gate
*
* @param player <p>The player trying to use the gate</p>
* @param source <p>The source/entry portal</p>
* @param destination <p>The destination portal</p>
* @return <p>The cost of using the portal</p>
*/
public int getUseCost(Player player, Portal source, Portal destination) {
//No payment required
if (!useEconomy() || source.getOptions().isFree()) {
return 0;
}
//Not charging for free destinations
if (destination != null && !chargeFreeDestination && destination.getOptions().isFree()) {
return 0;
}
//Cost is 0 if the player owns this gate and funds go to the owner
if (source.getGate().getToOwner() && source.isOwner(player)) {
return 0;
}
//Player gets free gate use
if (PermissionHelper.hasPermission(player, "stargate.free.use")) {
return 0;
}
return source.getGate().getUseCost();
} }
/** /**
@ -329,21 +225,6 @@ public final class EconomyConfig {
} }
} }
/**
* Loads all config values related to economy
*
* @param newConfig <p>The configuration containing the values to read</p>
*/
private void loadEconomyConfig(FileConfiguration newConfig) {
economyEnabled = newConfig.getBoolean("economy.useEconomy");
setDefaultCreateCost(newConfig.getInt("economy.createCost"));
setDefaultDestroyCost(newConfig.getInt("economy.destroyCost"));
setDefaultUseCost(newConfig.getInt("economy.useCost"));
toOwner = newConfig.getBoolean("economy.toOwner");
chargeFreeDestination = newConfig.getBoolean("economy.chargeFreeDestination");
freeGatesGreen = newConfig.getBoolean("economy.freeGatesGreen");
}
/** /**
* Determines if a player can do a gate action for free * Determines if a player can do a gate action for free
* *
@ -355,41 +236,4 @@ public final class EconomyConfig {
return !useEconomy() || PermissionHelper.hasPermission(player, "stargate.free." + permissionNode); return !useEconomy() || PermissionHelper.hasPermission(player, "stargate.free." + permissionNode);
} }
/**
* Charges a player
*
* @param player <p>The player to charge</p>
* @param amount <p>The amount to charge</p>
* @return <p>True if the payment succeeded, or if no payment was necessary</p>
*/
private boolean chargePlayer(Player player, double amount) {
if (economyEnabled && economy != null) {
if (!economy.has(player, amount)) {
return false;
}
economy.withdrawPlayer(player, amount);
}
return true;
}
/**
* Charges a player, giving the charge to a target
*
* @param player <p>The player to charge</p>
* @param target <p>The UUID of the player to pay</p>
* @param amount <p>The amount to charge</p>
* @return <p>True if the payment succeeded, or if no payment was necessary</p>
*/
private boolean chargePlayer(Player player, UUID target, double amount) {
if (economyEnabled && player.getUniqueId().compareTo(target) != 0 && economy != null) {
if (!economy.has(player, amount)) {
return false;
}
//Take money from the user and give to the owner
economy.withdrawPlayer(player, amount);
economy.depositPlayer(Bukkit.getOfflinePlayer(target), amount);
}
return true;
}
} }

View File

@ -0,0 +1,21 @@
package net.knarcraft.stargate.config;
/**
* An enum defining the different data types an option can have
*/
public enum OptionDataType {
/**
* The data type for the option is a String
*/
STRING,
/**
* The data type for the option is a Boolean
*/
BOOLEAN,
/**
* The data type for the option is an Integer
*/
INTEGER
}

View File

@ -18,6 +18,7 @@ import org.bukkit.plugin.messaging.Messenger;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Queue; import java.util.Queue;
@ -45,8 +46,7 @@ public final class StargateConfig {
private String portalFolder; private String portalFolder;
private String languageName = "en"; private String languageName = "en";
private boolean debuggingEnabled = false; private final Map<ConfigOption, Object> configOptions;
private boolean permissionDebuggingEnabled = false;
/** /**
* Instantiates a new stargate config * Instantiates a new stargate config
@ -55,6 +55,7 @@ public final class StargateConfig {
*/ */
public StargateConfig(Logger logger) { public StargateConfig(Logger logger) {
this.logger = logger; this.logger = logger;
configOptions = new HashMap<>();
dataFolderPath = Stargate.getInstance().getDataFolder().getPath().replaceAll("\\\\", "/"); dataFolderPath = Stargate.getInstance().getDataFolder().getPath().replaceAll("\\\\", "/");
portalFolder = dataFolderPath + "/portals/"; portalFolder = dataFolderPath + "/portals/";
@ -62,6 +63,18 @@ public final class StargateConfig {
languageLoader = new LanguageLoader(dataFolderPath + "/lang/"); languageLoader = new LanguageLoader(dataFolderPath + "/lang/");
} }
/**
* Gets a direct reference to the config option map
*
* <p>This reference can be used to alter the value of config options. Values should only be altered after it's
* been verified that the value is valid.</p>
*
* @return <p>A reference to the config options map</p>
*/
public Map<ConfigOption, Object> getConfigOptionsReference() {
return configOptions;
}
/** /**
* Finish the config setup by loading languages, gates and portals, and loading economy if vault is loaded * Finish the config setup by loading languages, gates and portals, and loading economy if vault is loaded
*/ */
@ -78,7 +91,7 @@ public final class StargateConfig {
languageLoader.reload(); languageLoader.reload();
messageSender = new MessageSender(languageLoader); messageSender = new MessageSender(languageLoader);
if (debuggingEnabled) { if (isDebuggingEnabled()) {
languageLoader.debug(); languageLoader.debug();
} }
@ -90,6 +103,15 @@ public final class StargateConfig {
setupVaultEconomy(); setupVaultEconomy();
} }
/**
* Gets a copy of all loaded config options with its values
*
* @return <p>The loaded config options</p>
*/
public Map<ConfigOption, Object> getConfigOptions() {
return new HashMap<>(configOptions);
}
/** /**
* Gets the queue of open portals * Gets the queue of open portals
* *
@ -118,7 +140,7 @@ public final class StargateConfig {
* @return <p>Whether debugging is enabled</p> * @return <p>Whether debugging is enabled</p>
*/ */
public boolean isDebuggingEnabled() { public boolean isDebuggingEnabled() {
return debuggingEnabled; return (boolean) configOptions.get(ConfigOption.DEBUG);
} }
/** /**
@ -127,7 +149,7 @@ public final class StargateConfig {
* @return <p>Whether permission debugging is enabled</p> * @return <p>Whether permission debugging is enabled</p>
*/ */
public boolean isPermissionDebuggingEnabled() { public boolean isPermissionDebuggingEnabled() {
return permissionDebuggingEnabled; return (boolean) configOptions.get(ConfigOption.PERMISSION_DEBUG);
} }
/** /**
@ -174,6 +196,17 @@ public final class StargateConfig {
* Un-loads all loaded data * Un-loads all loaded data
*/ */
private void unload() { private void unload() {
//De-activate, close and unload all loaded portals
unloadAllPortals();
//Clear all loaded gates
GateHandler.clearGates();
}
/**
* Un-loads all loaded portals
*/
public void unloadAllPortals() {
//De-activate all currently active portals //De-activate all currently active portals
for (Portal activePortal : activePortalsQueue) { for (Portal activePortal : activePortalsQueue) {
activePortal.getPortalActivator().deactivate(); activePortal.getPortalActivator().deactivate();
@ -189,9 +222,6 @@ public final class StargateConfig {
//Clear all loaded portals //Clear all loaded portals
PortalRegistry.clearPortals(); PortalRegistry.clearPortals();
//Clear all loaded gates
GateHandler.clearGates();
} }
/** /**
@ -244,7 +274,7 @@ public final class StargateConfig {
//Update the language loader in case the loaded language changed //Update the language loader in case the loaded language changed
languageLoader.setChosenLanguage(languageName); languageLoader.setChosenLanguage(languageName);
languageLoader.reload(); languageLoader.reload();
if (debuggingEnabled) { if (isDebuggingEnabled()) {
languageLoader.debug(); languageLoader.debug();
} }
@ -255,7 +285,7 @@ public final class StargateConfig {
/** /**
* Starts the listener for listening to BungeeCord messages * Starts the listener for listening to BungeeCord messages
*/ */
private void startStopBungeeListener(boolean start) { public void startStopBungeeListener(boolean start) {
Messenger messenger = Bukkit.getMessenger(); Messenger messenger = Bukkit.getMessenger();
String bungeeChannel = "BungeeCord"; String bungeeChannel = "BungeeCord";
@ -271,7 +301,7 @@ public final class StargateConfig {
/** /**
* Reloads economy by enabling or disabling it as necessary * Reloads economy by enabling or disabling it as necessary
*/ */
private void reloadEconomy() { public void reloadEconomy() {
EconomyConfig economyConfig = getEconomyConfig(); EconomyConfig economyConfig = getEconomyConfig();
if (economyConfig.isEconomyEnabled() && economyConfig.getEconomy() == null) { if (economyConfig.isEconomyEnabled() && economyConfig.getEconomy() == null) {
setupVaultEconomy(); setupVaultEconomy();
@ -297,9 +327,7 @@ public final class StargateConfig {
FileConfiguration newConfig = Stargate.getInstance().getConfig(); FileConfiguration newConfig = Stargate.getInstance().getConfig();
boolean isMigrating = false; boolean isMigrating = false;
if (newConfig.getString("lang") != null || if (newConfig.getString("lang") != null || newConfig.getString("economy.freeGatesGreen") != null) {
newConfig.getString("gates.integrity.ignoreEntrance") != null ||
newConfig.getString("ignoreEntrance") != null) {
migrateConfig(newConfig); migrateConfig(newConfig);
isMigrating = true; isMigrating = true;
} }
@ -307,16 +335,30 @@ public final class StargateConfig {
//Copy missing default values if any values are missing //Copy missing default values if any values are missing
newConfig.options().copyDefaults(true); newConfig.options().copyDefaults(true);
//Load all options
for (ConfigOption option : ConfigOption.values()) {
Object optionValue;
String configNode = option.getConfigNode();
//Load the option using its correct data type
switch (option.getDataType()) {
case STRING -> {
String value = newConfig.getString(configNode);
optionValue = value != null ? value.trim() : "";
}
case BOOLEAN -> optionValue = newConfig.getBoolean(configNode);
case INTEGER -> optionValue = newConfig.getInt(configNode);
default -> throw new IllegalArgumentException("Invalid config data type encountered");
}
configOptions.put(option, optionValue);
}
//Get the language name from the config //Get the language name from the config
languageName = newConfig.getString("language"); languageName = (String) configOptions.get(ConfigOption.LANGUAGE);
//Get important folders from the config //Get important folders from the config
portalFolder = newConfig.getString("folders.portalFolder"); portalFolder = (String) configOptions.get(ConfigOption.PORTAL_FOLDER);
gateFolder = newConfig.getString("folders.gateFolder"); gateFolder = (String) configOptions.get(ConfigOption.GATE_FOLDER);
//Get enabled debug settings from the config
debuggingEnabled = newConfig.getBoolean("debugging.debug");
permissionDebuggingEnabled = newConfig.getBoolean("debugging.permissionDebug");
//If users have an outdated config, assume they also need to update their default gates //If users have an outdated config, assume they also need to update their default gates
if (isMigrating) { if (isMigrating) {
@ -324,10 +366,10 @@ public final class StargateConfig {
} }
//Load all gate config values //Load all gate config values
stargateGateConfig = new StargateGateConfig(newConfig); stargateGateConfig = new StargateGateConfig(configOptions);
//Load all economy config values //Load all economy config values
economyConfig = new EconomyConfig(newConfig); economyConfig = new EconomyConfig(configOptions);
Stargate.getInstance().saveConfig(); Stargate.getInstance().saveConfig();
} }

View File

@ -3,36 +3,25 @@ package net.knarcraft.stargate.config;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.PortalSignDrawer; import net.knarcraft.stargate.portal.PortalSignDrawer;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.configuration.file.FileConfiguration;
import java.util.Map;
/** /**
* The Stargate gate config keeps track of all global config values related to gates * The Stargate gate config keeps track of all global config values related to gates
*/ */
public final class StargateGateConfig { public final class StargateGateConfig {
private int maxGatesEachNetwork = 0;
private boolean rememberDestination = false;
private boolean handleVehicles = true;
private boolean handleEmptyVehicles = true;
private boolean handleCreatureTransportation = true;
private boolean handleNonPlayerVehicles = true;
private boolean handleLeashedCreatures = true;
private boolean sortNetworkDestinations = false;
private boolean protectEntrance = false;
private boolean enableBungee = true;
private boolean verifyPortals = true;
private boolean destroyExplosion = false;
private String defaultGateNetwork = "central";
private static final int activeTime = 10; private static final int activeTime = 10;
private static final int openTime = 10; private static final int openTime = 10;
private final Map<ConfigOption, Object> configOptions;
/** /**
* Instantiates a new stargate config * Instantiates a new stargate config
* *
* @param newConfig <p>The file configuration to read values from</p> * @param configOptions <p>The loaded config options to use</p>
*/ */
public StargateGateConfig(FileConfiguration newConfig) { public StargateGateConfig(Map<ConfigOption, Object> configOptions) {
loadGateConfig(newConfig); this.configOptions = configOptions;
loadGateConfig();
} }
/** /**
@ -59,7 +48,7 @@ public final class StargateGateConfig {
* @return <p>Maximum number of gates for each network</p> * @return <p>Maximum number of gates for each network</p>
*/ */
public int maxGatesEachNetwork() { public int maxGatesEachNetwork() {
return maxGatesEachNetwork; return (int) configOptions.get(ConfigOption.MAX_GATES_EACH_NETWORK);
} }
/** /**
@ -68,7 +57,7 @@ public final class StargateGateConfig {
* @return <p>Whether a portal's lastly used destination should be remembered</p> * @return <p>Whether a portal's lastly used destination should be remembered</p>
*/ */
public boolean rememberDestination() { public boolean rememberDestination() {
return rememberDestination; return (boolean) configOptions.get(ConfigOption.REMEMBER_DESTINATION);
} }
/** /**
@ -77,7 +66,7 @@ public final class StargateGateConfig {
* @return <p>Whether vehicle teleportation should be handled</p> * @return <p>Whether vehicle teleportation should be handled</p>
*/ */
public boolean handleVehicles() { public boolean handleVehicles() {
return handleVehicles; return (boolean) configOptions.get(ConfigOption.HANDLE_VEHICLES);
} }
/** /**
@ -89,7 +78,7 @@ public final class StargateGateConfig {
* @return <p>Whether vehicles without passengers should be handled</p> * @return <p>Whether vehicles without passengers should be handled</p>
*/ */
public boolean handleEmptyVehicles() { public boolean handleEmptyVehicles() {
return handleEmptyVehicles; return (boolean) configOptions.get(ConfigOption.HANDLE_EMPTY_VEHICLES);
} }
/** /**
@ -101,7 +90,7 @@ public final class StargateGateConfig {
* @return <p>Whether vehicles with creatures should be handled</p> * @return <p>Whether vehicles with creatures should be handled</p>
*/ */
public boolean handleCreatureTransportation() { public boolean handleCreatureTransportation() {
return handleCreatureTransportation; return (boolean) configOptions.get(ConfigOption.HANDLE_CREATURE_TRANSPORTATION);
} }
/** /**
@ -118,7 +107,7 @@ public final class StargateGateConfig {
* @return <p>Whether non-empty vehicles without a player should be handled</p> * @return <p>Whether non-empty vehicles without a player should be handled</p>
*/ */
public boolean handleNonPlayerVehicles() { public boolean handleNonPlayerVehicles() {
return handleNonPlayerVehicles; return (boolean) configOptions.get(ConfigOption.HANDLE_NON_PLAYER_VEHICLES);
} }
/** /**
@ -127,7 +116,7 @@ public final class StargateGateConfig {
* @return <p>Whether leashed creatures should be handled</p> * @return <p>Whether leashed creatures should be handled</p>
*/ */
public boolean handleLeashedCreatures() { public boolean handleLeashedCreatures() {
return handleLeashedCreatures; return (boolean) configOptions.get(ConfigOption.HANDLE_LEASHED_CREATURES);
} }
/** /**
@ -136,7 +125,7 @@ public final class StargateGateConfig {
* @return <p>Whether network destinations should be sorted</p> * @return <p>Whether network destinations should be sorted</p>
*/ */
public boolean sortNetworkDestinations() { public boolean sortNetworkDestinations() {
return sortNetworkDestinations; return (boolean) configOptions.get(ConfigOption.SORT_NETWORK_DESTINATIONS);
} }
/** /**
@ -145,7 +134,7 @@ public final class StargateGateConfig {
* @return <p>Whether portal entrances should be protected</p> * @return <p>Whether portal entrances should be protected</p>
*/ */
public boolean protectEntrance() { public boolean protectEntrance() {
return protectEntrance; return (boolean) configOptions.get(ConfigOption.PROTECT_ENTRANCE);
} }
/** /**
@ -154,7 +143,7 @@ public final class StargateGateConfig {
* @return <p>Whether bungee support is enabled</p> * @return <p>Whether bungee support is enabled</p>
*/ */
public boolean enableBungee() { public boolean enableBungee() {
return enableBungee; return (boolean) configOptions.get(ConfigOption.ENABLE_BUNGEE);
} }
/** /**
@ -163,7 +152,7 @@ public final class StargateGateConfig {
* @return <p>Whether portals need to be verified</p> * @return <p>Whether portals need to be verified</p>
*/ */
public boolean verifyPortals() { public boolean verifyPortals() {
return verifyPortals; return (boolean) configOptions.get(ConfigOption.VERIFY_PORTALS);
} }
/** /**
@ -172,7 +161,7 @@ public final class StargateGateConfig {
* @return <p>Whether portals should be destroyed by explosions</p> * @return <p>Whether portals should be destroyed by explosions</p>
*/ */
public boolean destroyedByExplosion() { public boolean destroyedByExplosion() {
return destroyExplosion; return (boolean) configOptions.get(ConfigOption.DESTROYED_BY_EXPLOSION);
} }
/** /**
@ -181,37 +170,16 @@ public final class StargateGateConfig {
* @return <p>The default portal network</p> * @return <p>The default portal network</p>
*/ */
public String getDefaultPortalNetwork() { public String getDefaultPortalNetwork() {
return defaultGateNetwork; return (String) configOptions.get(ConfigOption.DEFAULT_GATE_NETWORK);
} }
/** /**
* Loads all config values related to gates * Loads all config values related to gates
*
* @param newConfig <p>The configuration containing the values to read</p>
*/ */
private void loadGateConfig(FileConfiguration newConfig) { private void loadGateConfig() {
String defaultNetwork = newConfig.getString("gates.defaultGateNetwork"); //Load the sign colors
defaultGateNetwork = defaultNetwork != null ? defaultNetwork.trim() : null; loadSignColor((String) configOptions.get(ConfigOption.MAIN_SIGN_COLOR),
maxGatesEachNetwork = newConfig.getInt("gates.maxGatesEachNetwork"); (String) configOptions.get(ConfigOption.HIGHLIGHT_SIGN_COLOR));
//Functionality
handleVehicles = newConfig.getBoolean("gates.functionality.handleVehicles");
handleEmptyVehicles = newConfig.getBoolean("gates.functionality.handleEmptyVehicles");
handleCreatureTransportation = newConfig.getBoolean("gates.functionality.handleCreatureTransportation");
handleNonPlayerVehicles = newConfig.getBoolean("gates.functionality.handleNonPlayerVehicles");
handleLeashedCreatures = newConfig.getBoolean("gates.functionality.handleLeashedCreatures");
enableBungee = newConfig.getBoolean("gates.functionality.enableBungee");
//Integrity
protectEntrance = newConfig.getBoolean("gates.integrity.protectEntrance");
verifyPortals = newConfig.getBoolean("gates.integrity.verifyPortals");
destroyExplosion = newConfig.getBoolean("gates.integrity.destroyedByExplosion");
//Cosmetic
sortNetworkDestinations = newConfig.getBoolean("gates.cosmetic.sortNetworkDestinations");
rememberDestination = newConfig.getBoolean("gates.cosmetic.rememberDestination");
loadSignColor(newConfig.getString("gates.cosmetic.mainSignColor"),
newConfig.getString("gates.cosmetic.highlightSignColor"));
} }
/** /**
@ -220,15 +188,13 @@ public final class StargateGateConfig {
* @param mainSignColor <p>A string representing the main sign color</p> * @param mainSignColor <p>A string representing the main sign color</p>
*/ */
private void loadSignColor(String mainSignColor, String highlightSignColor) { private void loadSignColor(String mainSignColor, String highlightSignColor) {
if (mainSignColor != null) { try {
try { PortalSignDrawer.setMainColor(ChatColor.valueOf(mainSignColor.toUpperCase()));
PortalSignDrawer.setColors(ChatColor.valueOf(mainSignColor.toUpperCase()), PortalSignDrawer.setHighlightColor(ChatColor.valueOf(highlightSignColor.toUpperCase()));
ChatColor.valueOf(highlightSignColor.toUpperCase())); } catch (IllegalArgumentException | NullPointerException exception) {
return; Stargate.logWarning("You have specified an invalid color in your config.yml. Defaulting to BLACK and WHITE");
} catch (IllegalArgumentException | NullPointerException ignored) { PortalSignDrawer.setMainColor(ChatColor.BLACK);
} PortalSignDrawer.setHighlightColor(ChatColor.WHITE);
} }
Stargate.logWarning("You have specified an invalid color in your config.yml. Defaulting to BLACK and WHITE");
PortalSignDrawer.setColors(ChatColor.BLACK, ChatColor.WHITE);
} }
} }

View File

@ -25,6 +25,7 @@ import org.bukkit.event.block.BlockPhysicsEvent;
import org.bukkit.event.block.BlockPistonEvent; import org.bukkit.event.block.BlockPistonEvent;
import org.bukkit.event.block.BlockPistonExtendEvent; import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.block.BlockPistonRetractEvent; import org.bukkit.event.block.BlockPistonRetractEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.EntityBlockFormEvent; import org.bukkit.event.block.EntityBlockFormEvent;
import org.bukkit.event.block.SignChangeEvent; import org.bukkit.event.block.SignChangeEvent;
@ -96,6 +97,22 @@ public class BlockEventListener implements Listener {
portal::drawSign, 1); portal::drawSign, 1);
} }
@EventHandler(priority = EventPriority.HIGHEST)
public void onBlockPlace(BlockPlaceEvent event) {
if (event.isCancelled() || !Stargate.getGateConfig().protectEntrance()) {
return;
}
Block block = event.getBlock();
Player player = event.getPlayer();
Portal portal = PortalHandler.getByEntrance(block);
if (portal != null) {
//Prevent blocks from being placed in the entrance, if protectEntrance is enabled, as breaking the block
// would destroy the portal
event.setCancelled(true);
}
}
/** /**
* Detects block breaking to detect if the user is destroying a gate * Detects block breaking to detect if the user is destroying a gate
* *
@ -140,7 +157,9 @@ public class BlockEventListener implements Listener {
//Destroy denied //Destroy denied
if (destroyEvent.getDeny()) { if (destroyEvent.getDeny()) {
Stargate.getMessageSender().sendErrorMessage(player, destroyEvent.getDenyReason()); if (!destroyEvent.getDenyReason().trim().isEmpty()) {
Stargate.getMessageSender().sendErrorMessage(player, destroyEvent.getDenyReason());
}
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
@ -169,7 +188,7 @@ public class BlockEventListener implements Listener {
if (cost != 0) { if (cost != 0) {
String portalName = portal.getName(); String portalName = portal.getName();
//Cannot pay //Cannot pay
if (!Stargate.getEconomyConfig().chargePlayerIfNecessary(player, cost)) { if (!EconomyHelper.chargePlayerIfNecessary(player, cost)) {
Stargate.debug("onBlockBreak", "Insufficient Funds"); Stargate.debug("onBlockBreak", "Insufficient Funds");
EconomyHelper.sendInsufficientFundsMessage(portalName, player, cost); EconomyHelper.sendInsufficientFundsMessage(portalName, player, cost);
event.setCancelled(true); event.setCancelled(true);

View File

@ -7,6 +7,7 @@ import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalActivator; import net.knarcraft.stargate.portal.PortalActivator;
import net.knarcraft.stargate.portal.PortalHandler; import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter; import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter;
import net.knarcraft.stargate.portal.teleporter.Teleporter;
import net.knarcraft.stargate.portal.teleporter.VehicleTeleporter; import net.knarcraft.stargate.portal.teleporter.VehicleTeleporter;
import net.knarcraft.stargate.utility.BungeeHelper; import net.knarcraft.stargate.utility.BungeeHelper;
import net.knarcraft.stargate.utility.MaterialHelper; import net.knarcraft.stargate.utility.MaterialHelper;
@ -170,7 +171,9 @@ public class PlayerEventListener implements Listener {
} }
return false; return false;
} }
return true;
//Make sure to check if the player has any leashed creatures, even though leashed teleportation is disabled
return Teleporter.noLeashedCreaturesPreventTeleportation(player);
} }
/** /**
@ -244,7 +247,7 @@ public class PlayerEventListener implements Listener {
* @return <p>True if the player should be denied</p> * @return <p>True if the player should be denied</p>
*/ */
private boolean cannotAccessPortal(Player player, Portal portal) { private boolean cannotAccessPortal(Player player, Portal portal) {
boolean deny = PermissionHelper.cannotAccessNetwork(player, portal.getNetwork()); boolean deny = PermissionHelper.cannotAccessNetwork(player, portal.getCleanNetwork());
if (PermissionHelper.portalAccessDenied(player, portal, deny)) { if (PermissionHelper.portalAccessDenied(player, portal, deny)) {
if (!portal.getOptions().isSilent()) { if (!portal.getOptions().isSilent()) {
@ -317,7 +320,7 @@ public class PlayerEventListener implements Listener {
} }
//Display portal information as a portal without a sign does not display any //Display portal information as a portal without a sign does not display any
if (portal.getOptions().hasNoSign() && !portal.getOptions().isSilent()) { if (portal.getOptions().hasNoSign() && (!portal.getOptions().isSilent() || player.isSneaking())) {
MessageSender sender = Stargate.getMessageSender(); MessageSender sender = Stargate.getMessageSender();
sender.sendSuccessMessage(player, ChatColor.GOLD + Stargate.getString("portalInfoTitle")); sender.sendSuccessMessage(player, ChatColor.GOLD + Stargate.getString("portalInfoTitle"));
sender.sendSuccessMessage(player, Stargate.replaceVars(Stargate.getString("portalInfoName"), sender.sendSuccessMessage(player, Stargate.replaceVars(Stargate.getString("portalInfoName"),

View File

@ -3,6 +3,7 @@ package net.knarcraft.stargate.listener;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler; import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.teleporter.Teleporter;
import net.knarcraft.stargate.portal.teleporter.VehicleTeleporter; import net.knarcraft.stargate.portal.teleporter.VehicleTeleporter;
import net.knarcraft.stargate.utility.EconomyHelper; import net.knarcraft.stargate.utility.EconomyHelper;
import net.knarcraft.stargate.utility.EntityHelper; import net.knarcraft.stargate.utility.EntityHelper;
@ -110,7 +111,7 @@ public class VehicleEventListener implements Listener {
//To prevent the case where the first passenger pays and then the second passenger is denied, this has to be //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 // run after it has been confirmed that all passengers are able to pay
int cost = Stargate.getEconomyConfig().getUseCost(player, entrancePortal, destinationPortal); int cost = EconomyHelper.getUseCost(player, entrancePortal, destinationPortal);
if (cost > 0) { if (cost > 0) {
if (!takePlayerPayment(passengers, entrancePortal, cost)) { if (!takePlayerPayment(passengers, entrancePortal, cost)) {
return; return;
@ -164,12 +165,16 @@ public class VehicleEventListener implements Listener {
} }
//Check if the player is able to afford the teleport fee //Check if the player is able to afford the teleport fee
int cost = Stargate.getEconomyConfig().getUseCost(player, entrancePortal, destinationPortal); int cost = EconomyHelper.getUseCost(player, entrancePortal, destinationPortal);
boolean canAffordFee = cost <= 0 || Stargate.getEconomyConfig().canAffordFee(player, cost); boolean canAffordFee = cost <= 0 || Stargate.getEconomyConfig().canAffordFee(player, cost);
if (!canAffordFee && !entrancePortal.getOptions().isSilent()) { if (!canAffordFee) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("ecoInFunds")); if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("ecoInFunds"));
}
return false;
} }
return canAffordFee;
return Teleporter.noLeashedCreaturesPreventTeleportation(player);
} }
} }

View File

@ -8,6 +8,7 @@ import net.knarcraft.stargate.portal.property.PortalOptions;
import net.knarcraft.stargate.portal.property.PortalOwner; import net.knarcraft.stargate.portal.property.PortalOwner;
import net.knarcraft.stargate.portal.property.PortalStructure; import net.knarcraft.stargate.portal.property.PortalStructure;
import net.knarcraft.stargate.portal.property.gate.Gate; import net.knarcraft.stargate.portal.property.gate.Gate;
import org.bukkit.ChatColor;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -19,7 +20,10 @@ import java.util.Map;
public class Portal { public class Portal {
private final String name; private final String name;
private final String cleanName;
private final String network; private final String network;
private final String cleanNetwork;
private final PortalOwner portalOwner; private final PortalOwner portalOwner;
private boolean isRegistered; private boolean isRegistered;
@ -53,6 +57,8 @@ public class Portal {
this.portalOpener = new PortalOpener(this, destination); this.portalOpener = new PortalOpener(this, destination);
this.structure = new PortalStructure(this, gate, button); this.structure = new PortalStructure(this, gate, button);
this.portalActivator = portalOpener.getPortalActivator(); this.portalActivator = portalOpener.getPortalActivator();
this.cleanName = cleanString(name);
this.cleanNetwork = cleanString(network);
} }
/** /**
@ -149,6 +155,15 @@ public class Portal {
return network; return network;
} }
/**
* Gets the clean name of the network this portal belongs to
*
* @return <p>The clean network name</p>
*/
public String getCleanNetwork() {
return cleanNetwork;
}
/** /**
* Gets the time this portal was triggered (activated/opened) * Gets the time this portal was triggered (activated/opened)
* *
@ -170,6 +185,15 @@ public class Portal {
return name; return name;
} }
/**
* Gets the clean name of this portal
*
* @return <p>The clean name of this portal</p>
*/
public String getCleanName() {
return cleanName;
}
/** /**
* Gets the portal opener used by this portal * Gets the portal opener used by this portal
* *
@ -273,6 +297,16 @@ public class Portal {
return getTopLeft().getRelativeLocation(vector, getYaw()); return getTopLeft().getRelativeLocation(vector, getYaw());
} }
/**
* Cleans a string by removing color codes, lower-casing and replacing spaces with underscores
*
* @param string <p>The string to clean</p>
* @return <p>The clean string</p>
*/
public static String cleanString(String string) {
return ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', string)).toLowerCase();
}
@Override @Override
public String toString() { public String toString() {
return String.format("Portal [id=%s, network=%s name=%s, type=%s]", getSignLocation(), network, name, return String.format("Portal [id=%s, network=%s name=%s, type=%s]", getSignLocation(), network, name,
@ -283,8 +317,8 @@ public class Portal {
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((cleanName == null) ? 0 : cleanName.hashCode());
result = prime * result + ((network == null) ? 0 : network.hashCode()); result = prime * result + ((cleanNetwork == null) ? 0 : cleanNetwork.hashCode());
return result; return result;
} }
@ -297,18 +331,18 @@ public class Portal {
return false; return false;
} }
Portal other = (Portal) object; Portal other = (Portal) object;
if (name == null) { if (cleanName == null) {
if (other.name != null) { if (other.cleanName != null) {
return false; return false;
} }
} else if (!name.equalsIgnoreCase(other.name)) { } else if (!cleanName.equalsIgnoreCase(other.cleanName)) {
return false; return false;
} }
//If none of the portals have a name, check if the network is the same //If none of the portals have a name, check if the network is the same
if (network == null) { if (cleanNetwork == null) {
return other.network == null; return other.cleanNetwork == null;
} else { } else {
return network.equalsIgnoreCase(other.network); return cleanNetwork.equalsIgnoreCase(other.cleanNetwork);
} }
} }
} }

View File

@ -6,7 +6,7 @@ import net.knarcraft.stargate.event.StargateDeactivateEvent;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
@ -64,7 +64,7 @@ public class PortalActivator {
* @return <p>The destination portal the player should teleport to</p> * @return <p>The destination portal the player should teleport to</p>
*/ */
public Portal getDestination(Player player) { public Portal getDestination(Player player) {
String portalNetwork = portal.getNetwork(); String portalNetwork = portal.getCleanNetwork();
if (portal.getOptions().isRandom()) { if (portal.getOptions().isRandom()) {
//Find possible destinations //Find possible destinations
List<String> destinations = PortalHandler.getDestinations(portal, player, portalNetwork); List<String> destinations = PortalHandler.getDestinations(portal, player, portalNetwork);
@ -73,10 +73,10 @@ public class PortalActivator {
} }
//Get one random destination //Get one random destination
String destination = destinations.get((new Random()).nextInt(destinations.size())); String destination = destinations.get((new Random()).nextInt(destinations.size()));
return PortalHandler.getByName(destination, portalNetwork); return PortalHandler.getByName(Portal.cleanString(destination), portalNetwork);
} else { } else {
//Just return the normal fixed destination //Just return the normal fixed destination
return PortalHandler.getByName(destination, portalNetwork); return PortalHandler.getByName(Portal.cleanString(destination), portalNetwork);
} }
} }
@ -136,12 +136,12 @@ public class PortalActivator {
//Set the given player as the active player //Set the given player as the active player
activePlayer = player; activePlayer = player;
String network = portal.getNetwork(); String network = portal.getCleanNetwork();
destinations = PortalHandler.getDestinations(portal, player, network); destinations = PortalHandler.getDestinations(portal, player, network);
//Sort destinations if enabled //Sort destinations if enabled
if (Stargate.getGateConfig().sortNetworkDestinations()) { if (Stargate.getGateConfig().sortNetworkDestinations()) {
Collections.sort(destinations); destinations.sort(Comparator.comparing(Portal::cleanString));
} }
//Select last used destination if remember destination is enabled //Select last used destination if remember destination is enabled
@ -242,7 +242,7 @@ public class PortalActivator {
activate = true; activate = true;
Stargate.debug("cycleDestination", "Network Size: " + Stargate.debug("cycleDestination", "Network Size: " +
PortalHandler.getNetwork(portal.getNetwork()).size()); PortalHandler.getNetwork(portal.getCleanNetwork()).size());
Stargate.debug("cycleDestination", "Player has access to: " + destinations.size()); Stargate.debug("cycleDestination", "Player has access to: " + destinations.size());
} }

View File

@ -22,6 +22,8 @@ import org.bukkit.event.block.SignChangeEvent;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static net.knarcraft.stargate.Stargate.getMaxNameNetworkLength;
/** /**
* The portal creator can create and validate a new portal * The portal creator can create and validate a new portal
*/ */
@ -105,7 +107,8 @@ public class PortalCreator {
Stargate.debug("createPortal", builder.toString()); Stargate.debug("createPortal", builder.toString());
//Use default network if a proper alternative is not set //Use default network if a proper alternative is not set
if (!portalOptions.get(PortalOption.BUNGEE) && (network.length() < 1 || network.length() > 11)) { if (!portalOptions.get(PortalOption.BUNGEE) && (network.length() < 1 || network.length() >
getMaxNameNetworkLength())) {
network = Stargate.getDefaultNetwork(); network = Stargate.getDefaultNetwork();
} }
@ -117,8 +120,8 @@ public class PortalCreator {
Stargate.debug("createPortal", "Player doesn't have create permissions on network. Trying personal"); Stargate.debug("createPortal", "Player doesn't have create permissions on network. Trying personal");
if (PermissionHelper.canCreatePersonalPortal(player)) { if (PermissionHelper.canCreatePersonalPortal(player)) {
network = player.getName(); network = player.getName();
if (network.length() > 11) { if (network.length() > getMaxNameNetworkLength()) {
network = network.substring(0, 11); network = network.substring(0, getMaxNameNetworkLength());
} }
Stargate.debug("createPortal", "Creating personal portal"); Stargate.debug("createPortal", "Creating personal portal");
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createPersonal")); Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createPersonal"));
@ -189,7 +192,9 @@ public class PortalCreator {
//Tell the user why it was denied from creating the portal //Tell the user why it was denied from creating the portal
if (stargateCreateEvent.getDeny()) { if (stargateCreateEvent.getDeny()) {
Stargate.getMessageSender().sendErrorMessage(player, stargateCreateEvent.getDenyReason()); if (!stargateCreateEvent.getDenyReason().trim().isEmpty()) {
Stargate.getMessageSender().sendErrorMessage(player, stargateCreateEvent.getDenyReason());
}
return null; return null;
} }
@ -228,29 +233,30 @@ public class PortalCreator {
*/ */
private boolean checkIfNewPortalIsValid(int cost, String portalName) { private boolean checkIfNewPortalIsValid(int cost, String portalName) {
//Check if the portal name can fit on the sign with padding (>name<) //Check if the portal name can fit on the sign with padding (>name<)
if (portal.getName().length() < 1 || portal.getName().length() > 11) { if (portal.getCleanName().length() < 1 || portal.getCleanName().length() > getMaxNameNetworkLength()) {
Stargate.debug("createPortal", "Name length error"); Stargate.debug("createPortal", String.format("Name length error. %s is too long.",
portal.getCleanName()));
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createNameLength")); Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createNameLength"));
return false; return false;
} }
if (portal.getOptions().isBungee()) { if (portal.getOptions().isBungee()) {
//Check if the bungee portal's name has been duplicated //Check if the bungee portal's name has been duplicated
if (PortalHandler.getBungeePortals().get(portal.getName().toLowerCase()) != null) { if (PortalHandler.getBungeePortals().get(portal.getCleanName()) != null) {
Stargate.debug("createPortal::Bungee", "Gate name duplicate"); Stargate.debug("createPortal::Bungee", "Gate name duplicate");
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createExists")); Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createExists"));
return false; return false;
} }
} else { } else {
//Check if the portal name has been duplicated on the network //Check if the portal name has been duplicated on the network
if (PortalHandler.getByName(portal.getName(), portal.getNetwork()) != null) { if (PortalHandler.getByName(portal.getCleanName(), portal.getCleanNetwork()) != null) {
Stargate.debug("createPortal", "Gate name duplicate"); Stargate.debug("createPortal", "Gate name duplicate");
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createExists")); Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createExists"));
return false; return false;
} }
//Check if the number of portals in the network has been surpassed //Check if the number of portals in the network has been surpassed
List<String> networkList = PortalHandler.getAllPortalNetworks().get(portal.getNetwork().toLowerCase()); List<String> networkList = PortalHandler.getAllPortalNetworks().get(portal.getCleanNetwork());
int maxGates = Stargate.getGateConfig().maxGatesEachNetwork(); int maxGates = Stargate.getGateConfig().maxGatesEachNetwork();
if (maxGates > 0 && networkList != null && networkList.size() >= maxGates) { if (maxGates > 0 && networkList != null && networkList.size() >= maxGates) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createFull")); Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createFull"));
@ -260,7 +266,7 @@ public class PortalCreator {
if (cost > 0) { if (cost > 0) {
//Deduct the required fee from the player //Deduct the required fee from the player
if (!Stargate.getEconomyConfig().chargePlayerIfNecessary(player, cost)) { if (!EconomyHelper.chargePlayerIfNecessary(player, cost)) {
EconomyHelper.sendInsufficientFundsMessage(portalName, player, cost); EconomyHelper.sendInsufficientFundsMessage(portalName, player, cost);
Stargate.debug("createPortal", "Insufficient Funds"); Stargate.debug("createPortal", "Insufficient Funds");
return false; return false;
@ -283,7 +289,7 @@ public class PortalCreator {
portal.getPortalOpener().openPortal(true); portal.getPortalOpener().openPortal(true);
} else if (portal.getOptions().isAlwaysOn()) { } else if (portal.getOptions().isAlwaysOn()) {
//For a normal always-on portal, open both the portal and the destination //For a normal always-on portal, open both the portal and the destination
Portal destinationPortal = PortalHandler.getByName(destinationName, portal.getNetwork()); Portal destinationPortal = PortalHandler.getByName(destinationName, portal.getCleanNetwork());
if (destinationPortal != null) { if (destinationPortal != null) {
portal.getPortalOpener().openPortal(true); portal.getPortalOpener().openPortal(true);
destinationPortal.drawSign(); destinationPortal.drawSign();

View File

@ -66,7 +66,7 @@ public class PortalHandler {
*/ */
public static List<String> getDestinations(Portal entrancePortal, Player player, String network) { public static List<String> getDestinations(Portal entrancePortal, Player player, String network) {
List<String> destinations = new ArrayList<>(); List<String> destinations = new ArrayList<>();
for (String destination : PortalRegistry.getAllPortalNetworks().get(network.toLowerCase())) { for (String destination : PortalRegistry.getAllPortalNetworks().get(network)) {
Portal portal = getByName(destination, network); Portal portal = getByName(destination, network);
if (portal == null) { if (portal == null) {
continue; continue;
@ -80,11 +80,12 @@ public class PortalHandler {
continue; continue;
} }
//Check if destination is this portal //Check if destination is this portal
if (destination.equalsIgnoreCase(entrancePortal.getName())) { if (destination.equals(entrancePortal.getCleanName())) {
continue; continue;
} }
//Check if destination is a fixed portal not pointing to this portal //Check if destination is a fixed portal not pointing to this portal
if (portal.getOptions().isFixed() && !portal.getDestinationName().equalsIgnoreCase(entrancePortal.getName())) { if (portal.getOptions().isFixed() &&
!Portal.cleanString(portal.getDestinationName()).equals(entrancePortal.getCleanName())) {
continue; continue;
} }
//Allow random use by non-players (Minecarts) //Allow random use by non-players (Minecarts)
@ -182,10 +183,10 @@ public class PortalHandler {
* @param portal <p>The newly created portal</p> * @param portal <p>The newly created portal</p>
*/ */
static void updatePortalsPointingAtNewPortal(Portal portal) { static void updatePortalsPointingAtNewPortal(Portal portal) {
for (String originName : PortalRegistry.getAllPortalNetworks().get(portal.getNetwork().toLowerCase())) { for (String originName : PortalRegistry.getAllPortalNetworks().get(portal.getCleanNetwork())) {
Portal origin = getByName(originName, portal.getNetwork()); Portal origin = getByName(originName, portal.getCleanNetwork());
if (origin == null || if (origin == null ||
!origin.getDestinationName().equalsIgnoreCase(portal.getName()) || !Portal.cleanString(origin.getDestinationName()).equals(portal.getCleanName()) ||
!origin.getStructure().isVerified()) { !origin.getStructure().isVerified()) {
continue; continue;
} }

View File

@ -126,7 +126,7 @@ public class PortalOpener {
return; return;
} }
boolean thisIsDestination = destination.getDestinationName().equalsIgnoreCase(portal.getName()); boolean thisIsDestination = Portal.cleanString(destination.getDestinationName()).equals(portal.getCleanName());
//Only open destination if it's not-fixed or points at this portal, and is not already open //Only open destination if it's not-fixed or points at this portal, and is not already open
if (!options.isRandom() && (!destination.getOptions().isFixed() || thisIsDestination) && !destination.isOpen()) { if (!options.isRandom() && (!destination.getOptions().isFixed() || thisIsDestination) && !destination.isOpen()) {
//Open the destination portal //Open the destination portal

View File

@ -63,7 +63,7 @@ public class PortalRegistry {
private static void clearPortals(List<Portal> portalsToRemove) { private static void clearPortals(List<Portal> portalsToRemove) {
//Store the names of the portals to remove as some maps require the name, not the object //Store the names of the portals to remove as some maps require the name, not the object
List<String> portalNames = new ArrayList<>(); List<String> portalNames = new ArrayList<>();
portalsToRemove.forEach((portal) -> portalNames.add(portal.getName())); portalsToRemove.forEach((portal) -> portalNames.add(portal.getCleanName()));
//Clear all the lookup locations for the portals //Clear all the lookup locations for the portals
lookupBlocks.keySet().removeIf((key) -> portalsToRemove.contains(lookupBlocks.get(key))); lookupBlocks.keySet().removeIf((key) -> portalsToRemove.contains(lookupBlocks.get(key)));
@ -165,8 +165,8 @@ public class PortalRegistry {
portal.getPortalActivator().deactivate(); portal.getPortalActivator().deactivate();
portal.getPortalOpener().closePortal(true); portal.getPortalOpener().closePortal(true);
String portalName = portal.getName().toLowerCase(); String portalName = portal.getCleanName();
String networkName = portal.getNetwork().toLowerCase(); String networkName = portal.getCleanNetwork();
//Remove portal from lookup blocks //Remove portal from lookup blocks
for (BlockLocation block : portal.getStructure().getFrame()) { for (BlockLocation block : portal.getStructure().getFrame()) {
@ -203,7 +203,7 @@ public class PortalRegistry {
//Update all portals in the same network with this portal as its destination //Update all portals in the same network with this portal as its destination
for (String originName : allPortalNetworks.get(networkName)) { for (String originName : allPortalNetworks.get(networkName)) {
Portal origin = PortalHandler.getByName(originName, portal.getNetwork()); Portal origin = PortalHandler.getByName(originName, portal.getCleanNetwork());
if (origin == null || !origin.getDestinationName().equalsIgnoreCase(portalName) || if (origin == null || !origin.getDestinationName().equalsIgnoreCase(portalName) ||
!origin.getStructure().isVerified()) { !origin.getStructure().isVerified()) {
continue; continue;
@ -235,8 +235,8 @@ public class PortalRegistry {
portal.getOptions().setFixed(portal.getDestinationName().length() > 0 || portal.getOptions().isRandom() || portal.getOptions().setFixed(portal.getDestinationName().length() > 0 || portal.getOptions().isRandom() ||
portal.getOptions().isBungee()); portal.getOptions().isBungee());
String portalName = portal.getName().toLowerCase(); String portalName = portal.getCleanName();
String networkName = portal.getNetwork().toLowerCase(); String networkName = portal.getCleanNetwork();
//Bungee portals are stored in their own list //Bungee portals are stored in their own list
if (portal.getOptions().isBungee()) { if (portal.getOptions().isBungee()) {

View File

@ -15,7 +15,7 @@ public class PortalSignDrawer {
private final Portal portal; private final Portal portal;
private final static ChatColor errorColor = ChatColor.DARK_RED; private final static ChatColor errorColor = ChatColor.DARK_RED;
private final static ChatColor freeColor = ChatColor.DARK_GREEN; private static ChatColor freeColor;
private static ChatColor mainColor; private static ChatColor mainColor;
private static ChatColor highlightColor; private static ChatColor highlightColor;
@ -29,19 +29,36 @@ public class PortalSignDrawer {
} }
/** /**
* Sets the main sign color * Sets the highlighting sign color
* *
* <p>The main sign color is used for most text on the sign, while the highlighting color is used for the markings * <p>The highlighting color is used for the markings around portal names and network names ('>','<','-',')','(').</p>
* around portal names and network names ('>','<','-',')','(')</p>
* *
* @param newMainColor <p>The new main sign color</p>
* @param newHighlightColor <p>The new highlight color</p> * @param newHighlightColor <p>The new highlight color</p>
*/ */
public static void setColors(ChatColor newMainColor, ChatColor newHighlightColor) { public static void setHighlightColor(ChatColor newHighlightColor) {
mainColor = newMainColor;
highlightColor = newHighlightColor; highlightColor = newHighlightColor;
} }
/**
* Sets the main sign color
*
* <p>The main sign color is used for most text on the sign.</p>
*
* @param newMainColor <p>The new main sign color</p>
*/
public static void setMainColor(ChatColor newMainColor) {
mainColor = newMainColor;
}
/**
* Sets the color to use for marking free stargates
*
* @param freeColor <p>The new color to use for marking free stargates</p>
*/
public static void setFreeColor(ChatColor freeColor) {
PortalSignDrawer.freeColor = freeColor;
}
/** /**
* Draws the sign of the portal this sign drawer is responsible for * Draws the sign of the portal this sign drawer is responsible for
*/ */
@ -81,8 +98,7 @@ public class PortalSignDrawer {
private void drawSign(Sign sign) { private void drawSign(Sign sign) {
//Clear sign //Clear sign
clearSign(sign); clearSign(sign);
setLine(sign, 0, highlightColor + "-" + mainColor + setLine(sign, 0, highlightColor + "-" + mainColor + fixColor(portal.getName()) + highlightColor + "-");
portal.getName() + highlightColor + "-");
if (!portal.getPortalActivator().isActive()) { if (!portal.getPortalActivator().isActive()) {
//Default sign text //Default sign text
@ -123,7 +139,7 @@ public class PortalSignDrawer {
return; return;
} }
clearSign(sign); clearSign(sign);
sign.setLine(0, portal.getName()); sign.setLine(0, fixColor(portal.getName()));
sign.update(); sign.update();
} }
@ -137,46 +153,46 @@ public class PortalSignDrawer {
int maxIndex = destinations.getDestinations().size() - 1; int maxIndex = destinations.getDestinations().size() - 1;
int signLineIndex = 0; int signLineIndex = 0;
int destinationIndex = destinations.getDestinations().indexOf(portal.getDestinationName()); int destinationIndex = destinations.getDestinations().indexOf(portal.getDestinationName());
boolean freeGatesGreen = Stargate.getEconomyConfig().useEconomy() && boolean freeGatesColored = Stargate.getEconomyConfig().useEconomy() &&
Stargate.getEconomyConfig().drawFreePortalsGreen(); Stargate.getEconomyConfig().drawFreePortalsColored();
//Last, and not only entry. Draw the entry two back //Last, and not only entry. Draw the entry two back
if ((destinationIndex == maxIndex) && (maxIndex > 1)) { if ((destinationIndex == maxIndex) && (maxIndex > 1)) {
drawNetworkSignLine(freeGatesGreen, sign, ++signLineIndex, destinationIndex - 2); drawNetworkSignLine(freeGatesColored, sign, ++signLineIndex, destinationIndex - 2);
} }
//Not first entry. Draw the previous entry //Not first entry. Draw the previous entry
if (destinationIndex > 0) { if (destinationIndex > 0) {
drawNetworkSignLine(freeGatesGreen, sign, ++signLineIndex, destinationIndex - 1); drawNetworkSignLine(freeGatesColored, sign, ++signLineIndex, destinationIndex - 1);
} }
//Draw the chosen entry (line 2 or 3) //Draw the chosen entry (line 2 or 3)
drawNetworkSignChosenLine(freeGatesGreen, sign, ++signLineIndex); drawNetworkSignChosenLine(freeGatesColored, sign, ++signLineIndex);
//Has another entry and space on the sign //Has another entry and space on the sign
if ((maxIndex >= destinationIndex + 1)) { if ((maxIndex >= destinationIndex + 1)) {
drawNetworkSignLine(freeGatesGreen, sign, ++signLineIndex, destinationIndex + 1); drawNetworkSignLine(freeGatesColored, sign, ++signLineIndex, destinationIndex + 1);
} }
//Has another entry and space on the sign //Has another entry and space on the sign
if ((maxIndex >= destinationIndex + 2) && (++signLineIndex <= 3)) { if ((maxIndex >= destinationIndex + 2) && (++signLineIndex <= 3)) {
drawNetworkSignLine(freeGatesGreen, sign, signLineIndex, destinationIndex + 2); drawNetworkSignLine(freeGatesColored, sign, signLineIndex, destinationIndex + 2);
} }
} }
/** /**
* Draws the chosen destination on one sign line * Draws the chosen destination on one sign line
* *
* @param freeGatesGreen <p>Whether to display free gates in a green color</p> * @param freeGatesColored <p>Whether to display free gates in a different color</p>
* @param sign <p>The sign to draw on</p> * @param sign <p>The sign to draw on</p>
* @param signLineIndex <p>The line to draw on</p> * @param signLineIndex <p>The line to draw on</p>
*/ */
private void drawNetworkSignChosenLine(boolean freeGatesGreen, Sign sign, int signLineIndex) { private void drawNetworkSignChosenLine(boolean freeGatesColored, Sign sign, int signLineIndex) {
if (freeGatesGreen) { if (freeGatesColored) {
Portal destination = PortalHandler.getByName(portal.getDestinationName(), portal.getNetwork()); Portal destination = PortalHandler.getByName(portal.getDestinationName(), portal.getNetwork());
boolean green = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination); boolean free = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination);
ChatColor nameColor = (green ? freeColor : highlightColor); ChatColor nameColor = (free ? freeColor : highlightColor);
setLine(sign, signLineIndex, nameColor + ">" + (green ? freeColor : mainColor) + setLine(sign, signLineIndex, nameColor + ">" + (free ? freeColor : mainColor) +
portal.getDestinationName() + nameColor + "<"); fixColor(portal.getDestinationName()) + nameColor + "<");
} else { } else {
setLine(sign, signLineIndex, highlightColor + ">" + mainColor + portal.getDestinationName() + setLine(sign, signLineIndex, highlightColor + ">" + mainColor +
highlightColor + "<"); fixColor(portal.getDestinationName()) + highlightColor + "<");
} }
} }
@ -194,20 +210,20 @@ public class PortalSignDrawer {
/** /**
* Draws one network destination on one sign line * Draws one network destination on one sign line
* *
* @param freeGatesGreen <p>Whether to display free gates in a green color</p> * @param freeGatesColored <p>Whether to display free gates in a different color</p>
* @param sign <p>The sign to draw on</p> * @param sign <p>The sign to draw on</p>
* @param signLineIndex <p>The line to draw on</p> * @param signLineIndex <p>The line to draw on</p>
* @param destinationIndex <p>The index of the destination to draw</p> * @param destinationIndex <p>The index of the destination to draw</p>
*/ */
private void drawNetworkSignLine(boolean freeGatesGreen, Sign sign, int signLineIndex, int destinationIndex) { private void drawNetworkSignLine(boolean freeGatesColored, Sign sign, int signLineIndex, int destinationIndex) {
PortalActivator destinations = portal.getPortalActivator(); PortalActivator destinations = portal.getPortalActivator();
String destinationName = destinations.getDestinations().get(destinationIndex); String destinationName = destinations.getDestinations().get(destinationIndex);
if (freeGatesGreen) { if (freeGatesColored) {
Portal destination = PortalHandler.getByName(destinationName, portal.getNetwork()); Portal destination = PortalHandler.getByName(destinationName, portal.getNetwork());
boolean green = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination); boolean free = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination);
setLine(sign, signLineIndex, (green ? freeColor : mainColor) + destinationName); setLine(sign, signLineIndex, (free ? freeColor : mainColor) + fixColor(destinationName));
} else { } else {
setLine(sign, signLineIndex, mainColor + destinationName); setLine(sign, signLineIndex, mainColor + fixColor(destinationName));
} }
} }
@ -218,8 +234,10 @@ public class PortalSignDrawer {
*/ */
private void drawBungeeSign(Sign sign) { private void drawBungeeSign(Sign sign) {
setLine(sign, 1, Stargate.getString("bungeeSign")); setLine(sign, 1, Stargate.getString("bungeeSign"));
setLine(sign, 2, highlightColor + ">" + mainColor + portal.getDestinationName() + highlightColor + "<"); setLine(sign, 2, highlightColor + ">" + mainColor + fixColor(portal.getDestinationName()) +
setLine(sign, 3, highlightColor + "[" + mainColor + portal.getNetwork() + highlightColor + "]"); highlightColor + "<");
setLine(sign, 3, highlightColor + "[" + mainColor + fixColor(portal.getNetwork()) +
highlightColor + "]");
} }
/** /**
@ -233,7 +251,8 @@ public class PortalSignDrawer {
setLine(sign, 1, Stargate.getString("signRightClick")); setLine(sign, 1, Stargate.getString("signRightClick"));
setLine(sign, 2, Stargate.getString("signToUse")); setLine(sign, 2, Stargate.getString("signToUse"));
if (!portal.getOptions().isNoNetwork()) { if (!portal.getOptions().isNoNetwork()) {
setLine(sign, 3, highlightColor + "(" + mainColor + portal.getNetwork() + highlightColor + ")"); setLine(sign, 3, highlightColor + "(" + mainColor + fixColor(portal.getNetwork()) +
highlightColor + ")");
} else { } else {
setLine(sign, 3, ""); setLine(sign, 3, "");
} }
@ -245,16 +264,20 @@ public class PortalSignDrawer {
* @param sign <p>The sign to re-draw</p> * @param sign <p>The sign to re-draw</p>
*/ */
private void drawFixedSign(Sign sign) { private void drawFixedSign(Sign sign) {
Portal destinationPortal = PortalHandler.getByName(Portal.cleanString(portal.getDestinationName()),
portal.getCleanNetwork());
String destinationName = portal.getOptions().isRandom() ? Stargate.getString("signRandom") : String destinationName = portal.getOptions().isRandom() ? Stargate.getString("signRandom") :
portal.getDestinationName(); (destinationPortal != null ? destinationPortal.getName() : portal.getDestinationName());
setLine(sign, 1, highlightColor + ">" + mainColor + destinationName + highlightColor + "<"); setLine(sign, 1, highlightColor + ">" + mainColor + fixColor(destinationName) + highlightColor + "<");
if (portal.getOptions().isNoNetwork()) { if (portal.getOptions().isNoNetwork()) {
setLine(sign, 2, ""); setLine(sign, 2, "");
} else { } else {
setLine(sign, 2, highlightColor + "(" + mainColor + portal.getNetwork() + highlightColor + ")"); setLine(sign, 2, highlightColor + "(" + mainColor + fixColor(portal.getNetwork()) +
highlightColor + ")");
} }
Portal destination = PortalHandler.getByName(portal.getDestinationName(), portal.getNetwork()); Portal destination = PortalHandler.getByName(Portal.cleanString(portal.getDestinationName()),
portal.getNetwork());
if (destination == null && !portal.getOptions().isRandom()) { if (destination == null && !portal.getOptions().isRandom()) {
setLine(sign, 3, errorColor + Stargate.getString("signDisconnected")); setLine(sign, 3, errorColor + Stargate.getString("signDisconnected"));
} else { } else {
@ -270,11 +293,24 @@ public class PortalSignDrawer {
* @param lineIndex <p>The index of the line the invalid portal was found at</p> * @param lineIndex <p>The index of the line the invalid portal was found at</p>
*/ */
public static void markPortalWithInvalidGate(PortalLocation portalLocation, String gateName, int lineIndex) { public static void markPortalWithInvalidGate(PortalLocation portalLocation, String gateName, int lineIndex) {
Sign sign = (Sign) portalLocation.getSignLocation().getBlock().getState(); BlockState blockState = portalLocation.getSignLocation().getBlock().getState();
if (!(blockState instanceof Sign sign)) {
return;
}
sign.setLine(3, errorColor + Stargate.getString("signInvalidGate")); sign.setLine(3, errorColor + Stargate.getString("signInvalidGate"));
sign.update(); sign.update();
Stargate.logInfo(String.format("Gate layout on line %d does not exist [%s]", lineIndex, gateName)); Stargate.logInfo(String.format("Gate layout on line %d does not exist [%s]", lineIndex, gateName));
} }
/**
* Fixes coloring of signs as the & character isn't translated on all servers
*
* @param text <p>The text to fix the coloring of</p>
* @return <p>The text with the coloring fixed</p>
*/
private String fixColor(String text) {
return ChatColor.translateAlternateColorCodes('&', text);
}
} }

View File

@ -69,6 +69,15 @@ public class Gate {
return layout; return layout;
} }
/**
* Gets a copy of the character to material mapping for this gate
*
* @return <p>The character to material map</p>
*/
public Map<Character, Material> getCharacterMaterialMap() {
return new HashMap<>(characterMaterialMap);
}
/** /**
* Gets the material type used for this gate's control blocks * Gets the material type used for this gate's control blocks
* *

View File

@ -188,16 +188,35 @@ public class GateHandler {
* @return <p>True if the gate is valid. False otherwise</p> * @return <p>True if the gate is valid. False otherwise</p>
*/ */
private static boolean validateGate(Gate gate, String fileName) { private static boolean validateGate(Gate gate, String fileName) {
String failString = String.format("Could not load Gate %s", fileName) + " - %s";
if (gate.getLayout().getControls().length != 2) { if (gate.getLayout().getControls().length != 2) {
Stargate.logSevere(String.format("Could not load Gate %s - Gates must have exactly 2 control points.", Stargate.logSevere(String.format(failString, "Gates must have exactly 2 control points."));
fileName));
return false; return false;
} }
if (!MaterialHelper.isButtonCompatible(gate.getPortalButton())) { if (!MaterialHelper.isButtonCompatible(gate.getPortalButton())) {
Stargate.logSevere(String.format("Could not load Gate %s - Gate button must be a type of button.", fileName)); Stargate.logSevere(String.format(failString, "Gate button must be a type of button."));
return false; return false;
} }
if (!gate.getPortalOpenBlock().isBlock()) {
Stargate.logSevere(String.format(failString, "Gate open block must be a type of block."));
return false;
}
if (!gate.getPortalClosedBlock().isBlock()) {
Stargate.logSevere(String.format(failString, "Gate closed block must be a type of block."));
return false;
}
for (Material material : gate.getCharacterMaterialMap().values()) {
if (!material.isBlock()) {
Stargate.logSevere(String.format(failString, "Every gate border block must be a type of block."));
return false;
}
}
return true; return true;
} }

View File

@ -191,9 +191,9 @@ public abstract class Teleporter {
*/ */
private Location adjustExitLocation(Location traveller, Location exitLocation) { private Location adjustExitLocation(Location traveller, Location exitLocation) {
if (exitLocation != null) { if (exitLocation != null) {
BlockData blockData = portal.getWorld().getBlockAt(exitLocation).getBlockData(); BlockData blockData = exitLocation.getBlock().getBlockData();
if ((blockData instanceof Bisected && ((Bisected) blockData).getHalf() == Bisected.Half.BOTTOM) || if ((blockData instanceof Bisected bisected && bisected.getHalf() == Bisected.Half.BOTTOM) ||
(blockData instanceof Slab) && ((Slab) blockData).getType() == Slab.Type.BOTTOM) { (blockData instanceof Slab slab && slab.getType() == Slab.Type.BOTTOM)) {
//Prevent traveller from spawning inside a slab //Prevent traveller from spawning inside a slab
Stargate.debug("adjustExitLocation", "Added a block to get above a slab"); Stargate.debug("adjustExitLocation", "Added a block to get above a slab");
exitLocation.add(0, 1, 0); exitLocation.add(0, 1, 0);
@ -250,9 +250,37 @@ public abstract class Teleporter {
return chunksToLoad; return chunksToLoad;
} }
/**
* Checks whether a player has leashed creatures that block the teleportation
*
* @param player <p>The player trying to teleport</p>
* @return <p>False if the player has leashed any creatures that cannot go through the portal</p>
*/
public static boolean noLeashedCreaturesPreventTeleportation(Player player) {
//Find any nearby leashed entities to teleport with the player
List<Creature> nearbyCreatures = getLeashedCreatures(player);
//Disallow creatures with passengers to prevent smuggling
for (Creature creature : nearbyCreatures) {
if (!creature.getPassengers().isEmpty()) {
return false;
}
}
//If it's enabled, there is no problem
if (Stargate.getGateConfig().handleLeashedCreatures()) {
return true;
} else {
return nearbyCreatures.isEmpty();
}
}
/** /**
* Teleports any creatures leashed by the player * Teleports any creatures leashed by the player
* *
* <p>Will return false if the teleportation should be aborted because the player has leashed creatures that
* aren't allowed to be teleported with the player.</p>
*
* @param player <p>The player which is teleported</p> * @param player <p>The player which is teleported</p>
* @param origin <p>The portal the player is teleporting from</p> * @param origin <p>The portal the player is teleporting from</p>
*/ */
@ -264,6 +292,7 @@ public abstract class Teleporter {
//Find any nearby leashed entities to teleport with the player //Find any nearby leashed entities to teleport with the player
List<Creature> nearbyEntities = getLeashedCreatures(player); List<Creature> nearbyEntities = getLeashedCreatures(player);
//Teleport all creatures leashed by the player to the portal the player is to exit from //Teleport all creatures leashed by the player to the portal the player is to exit from
for (Creature creature : nearbyEntities) { for (Creature creature : nearbyEntities) {
creature.setLeashHolder(null); creature.setLeashHolder(null);
@ -280,7 +309,7 @@ public abstract class Teleporter {
* @param player <p>The player to check</p> * @param player <p>The player to check</p>
* @return <p>A list of all creatures the player is holding in a leash (lead)</p> * @return <p>A list of all creatures the player is holding in a leash (lead)</p>
*/ */
protected List<Creature> getLeashedCreatures(Player player) { protected static List<Creature> getLeashedCreatures(Player player) {
List<Creature> leashedCreatures = new ArrayList<>(); List<Creature> leashedCreatures = new ArrayList<>();
//Find any nearby leashed entities to teleport with the player //Find any nearby leashed entities to teleport with the player
List<Entity> nearbyEntities = player.getNearbyEntities(15, 15, 15); List<Entity> nearbyEntities = player.getNearbyEntities(15, 15, 15);

View File

@ -4,6 +4,7 @@ import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler; import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter; import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerMoveEvent;
@ -71,7 +72,7 @@ public final class BungeeHelper {
//Build the message data and send it over the SGBungee BungeeCord channel //Build the message data and send it over the SGBungee BungeeCord channel
dataOutputStream.writeUTF("Forward"); dataOutputStream.writeUTF("Forward");
//Send the message to the server defined in the entrance portal's network line //Send the message to the server defined in the entrance portal's network line
dataOutputStream.writeUTF(entrancePortal.getNetwork()); dataOutputStream.writeUTF(stripColor(entrancePortal.getNetwork()));
//Specify the sub-channel/tag to make it recognizable on arrival //Specify the sub-channel/tag to make it recognizable on arrival
dataOutputStream.writeUTF(bungeeSubChannel); dataOutputStream.writeUTF(bungeeSubChannel);
//Write the length of the message //Write the length of the message
@ -102,7 +103,7 @@ public final class BungeeHelper {
//Send a connect-message to connect the player to the server defined in the entrance portal's network line //Send a connect-message to connect the player to the server defined in the entrance portal's network line
dataOutputStream.writeUTF("Connect"); dataOutputStream.writeUTF("Connect");
dataOutputStream.writeUTF(entrancePortal.getNetwork()); dataOutputStream.writeUTF(stripColor(entrancePortal.getNetwork()));
//Send the plugin message //Send the plugin message
player.sendPluginMessage(Stargate.getInstance(), bungeeChannel, byteArrayOutputStream.toByteArray()); player.sendPluginMessage(Stargate.getInstance(), bungeeChannel, byteArrayOutputStream.toByteArray());
@ -207,4 +208,14 @@ public final class BungeeHelper {
return true; return true;
} }
/**
* Strips all color tags from a string
*
* @param string <p>The string to strip color from</p>
* @return <p>The string without color codes</p>
*/
private static String stripColor(String string) {
return ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', string));
}
} }

View File

@ -1,8 +1,11 @@
package net.knarcraft.stargate.utility; package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.EconomyConfig;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.property.PortalOwner; import net.knarcraft.stargate.portal.property.PortalOwner;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.UUID; import java.util.UUID;
@ -34,9 +37,9 @@ public final class EconomyHelper {
"was therefore not possible. Make the owner re-create the portal to fix this.", entrancePortal)); "was therefore not possible. Make the owner re-create the portal to fix this.", entrancePortal));
} }
if (entrancePortal.getGate().getToOwner() && ownerUUID != null) { if (entrancePortal.getGate().getToOwner() && ownerUUID != null) {
success = Stargate.getEconomyConfig().chargePlayerIfNecessary(player, ownerUUID, cost); success = chargePlayerIfNecessary(player, ownerUUID, cost);
} else { } else {
success = Stargate.getEconomyConfig().chargePlayerIfNecessary(player, cost); success = chargePlayerIfNecessary(player, cost);
} }
//Send the insufficient funds message //Send the insufficient funds message
@ -118,6 +121,116 @@ public final class EconomyHelper {
Stargate.getMessageSender().sendSuccessMessage(player, refundMsg); Stargate.getMessageSender().sendSuccessMessage(player, refundMsg);
} }
/**
* Determines the cost of using a gate
*
* @param player <p>The player trying to use the gate</p>
* @param source <p>The source/entry portal</p>
* @param destination <p>The destination portal</p>
* @return <p>The cost of using the portal</p>
*/
public static int getUseCost(Player player, Portal source, Portal destination) {
EconomyConfig config = Stargate.getEconomyConfig();
//No payment required
if (!config.useEconomy() || source.getOptions().isFree()) {
return 0;
}
//Not charging for free destinations
if (destination != null && config.freeIfFreeDestination() && destination.getOptions().isFree()) {
return 0;
}
//Cost is 0 if the player owns this gate and funds go to the owner
if (source.getGate().getToOwner() && source.isOwner(player)) {
return 0;
}
//Player gets free gate use
if (PermissionHelper.hasPermission(player, "stargate.free.use")) {
return 0;
}
return source.getGate().getUseCost();
}
/**
* Charges the player for an action, if required
*
* @param player <p>The player to take money from</p>
* @param target <p>The target to pay</p>
* @param cost <p>The cost of the transaction</p>
* @return <p>True if the player was charged successfully</p>
*/
public static boolean chargePlayerIfNecessary(Player player, UUID target, int cost) {
if (skipPayment(cost)) {
return true;
}
//Charge player
return chargePlayer(player, target, cost);
}
/**
* Charges a player
*
* @param player <p>The player to charge</p>
* @param amount <p>The amount to charge</p>
* @return <p>True if the payment succeeded, or if no payment was necessary</p>
*/
private static boolean chargePlayer(Player player, double amount) {
Economy economy = Stargate.getEconomyConfig().getEconomy();
if (Stargate.getEconomyConfig().isEconomyEnabled() && economy != null) {
if (!economy.has(player, amount)) {
return false;
}
economy.withdrawPlayer(player, amount);
}
return true;
}
/**
* Charges the player for an action, if required
*
* @param player <p>The player to take money from</p>
* @param cost <p>The cost of the transaction</p>
* @return <p>True if the player was charged successfully</p>
*/
public static boolean chargePlayerIfNecessary(Player player, int cost) {
if (skipPayment(cost)) {
return true;
}
//Charge player
return chargePlayer(player, cost);
}
/**
* Checks whether a payment transaction should be skipped
*
* @param cost <p>The cost of the transaction</p>
* @return <p>True if the transaction should be skipped</p>
*/
private static boolean skipPayment(int cost) {
return cost == 0 || !Stargate.getEconomyConfig().useEconomy();
}
/**
* Charges a player, giving the charge to a target
*
* @param player <p>The player to charge</p>
* @param target <p>The UUID of the player to pay</p>
* @param amount <p>The amount to charge</p>
* @return <p>True if the payment succeeded, or if no payment was necessary</p>
*/
private static boolean chargePlayer(Player player, UUID target, double amount) {
Economy economy = Stargate.getEconomyConfig().getEconomy();
if (Stargate.getEconomyConfig().isEconomyEnabled() && player.getUniqueId().compareTo(target) != 0 && economy != null) {
if (!economy.has(player, amount)) {
return false;
}
//Take money from the user and give to the owner
economy.withdrawPlayer(player, amount);
economy.depositPlayer(Bukkit.getOfflinePlayer(target), amount);
}
return true;
}
/** /**
* Replaces the cost and portal variables in a string * Replaces the cost and portal variables in a string
* *

View File

@ -8,6 +8,8 @@ import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerMoveEvent;
import static net.knarcraft.stargate.Stargate.getMaxNameNetworkLength;
/** /**
* Helper class for deciding which actions a player is allowed to perform * Helper class for deciding which actions a player is allowed to perform
*/ */
@ -105,12 +107,12 @@ public final class PermissionHelper {
boolean deny = false; boolean deny = false;
if (entrancePortal.getOptions().isBungee()) { if (entrancePortal.getOptions().isBungee()) {
if (!PermissionHelper.canAccessServer(player, entrancePortal.getNetwork())) { if (!PermissionHelper.canAccessServer(player, entrancePortal.getCleanNetwork())) {
//If the portal is a bungee portal, and the player cannot access the server, deny //If the portal is a bungee portal, and the player cannot access the server, deny
Stargate.debug("cannotAccessPortal", "Cannot access server"); Stargate.debug("cannotAccessPortal", "Cannot access server");
deny = true; deny = true;
} }
} else if (PermissionHelper.cannotAccessNetwork(player, entrancePortal.getNetwork())) { } else if (PermissionHelper.cannotAccessNetwork(player, entrancePortal.getCleanNetwork())) {
//If the player does not have access to the network, deny //If the player does not have access to the network, deny
Stargate.debug("cannotAccessPortal", "Cannot access network"); Stargate.debug("cannotAccessPortal", "Cannot access network");
deny = true; deny = true;
@ -200,8 +202,8 @@ public final class PermissionHelper {
} }
//Is able to create personal gates (Assumption is made they can also access them) //Is able to create personal gates (Assumption is made they can also access them)
String playerName = player.getName(); String playerName = player.getName();
if (playerName.length() > 11) { if (playerName.length() > getMaxNameNetworkLength()) {
playerName = playerName.substring(0, 11); playerName = playerName.substring(0, getMaxNameNetworkLength());
} }
return !network.equals(playerName) || !hasPermission(player, "stargate.create.personal"); return !network.equals(playerName) || !hasPermission(player, "stargate.create.personal");
} }
@ -241,7 +243,7 @@ public final class PermissionHelper {
return true; return true;
} }
//Don't charge for free destinations unless specified in the config //Don't charge for free destinations unless specified in the config
return dest != null && !Stargate.getEconomyConfig().chargeFreeDestination() && dest.getOptions().isFree(); return dest != null && Stargate.getEconomyConfig().freeIfFreeDestination() && dest.getOptions().isFree();
} }
/** /**
@ -345,7 +347,7 @@ public final class PermissionHelper {
* @return <p>True if the player is allowed to destroy the portal</p> * @return <p>True if the player is allowed to destroy the portal</p>
*/ */
public static boolean canDestroyPortal(Player player, Portal portal) { public static boolean canDestroyPortal(Player player, Portal portal) {
String network = portal.getNetwork(); String network = portal.getCleanNetwork();
//Use a special check for bungee portals //Use a special check for bungee portals
if (portal.getOptions().isBungee()) { if (portal.getOptions().isBungee()) {
@ -405,7 +407,7 @@ public final class PermissionHelper {
} }
//Player cannot pay for teleportation //Player cannot pay for teleportation
int cost = Stargate.getEconomyConfig().getUseCost(player, entrancePortal, destination); int cost = EconomyHelper.getUseCost(player, entrancePortal, destination);
if (cost > 0) { if (cost > 0) {
return EconomyHelper.cannotPayTeleportFee(entrancePortal, player, cost); return EconomyHelper.cannotPayTeleportFee(entrancePortal, player, cost);
} }

View File

@ -292,16 +292,15 @@ public final class PortalFileHelper {
*/ */
private static void updatePortalButton(Portal portal) { private static void updatePortalButton(Portal portal) {
BlockLocation buttonLocation = getButtonLocation(portal); BlockLocation buttonLocation = getButtonLocation(portal);
BlockData buttonData = buttonLocation.getBlock().getBlockData();
if (portal.getOptions().isAlwaysOn()) { if (portal.getOptions().isAlwaysOn()) {
//Clear button if not already air or water //Clear button if not already air or water
if (MaterialHelper.isButtonCompatible(buttonData.getMaterial())) { if (MaterialHelper.isButtonCompatible(buttonLocation.getType())) {
Material newMaterial = decideRemovalMaterial(buttonLocation, portal); Material newMaterial = decideRemovalMaterial(buttonLocation, portal);
Stargate.addBlockChangeRequest(new BlockChangeRequest(buttonLocation, newMaterial, null)); Stargate.addBlockChangeRequest(new BlockChangeRequest(buttonLocation, newMaterial, null));
} }
} else { } else {
//Replace button if the material does not match //Replace button if the material does not match
if (buttonData.getMaterial() != portal.getGate().getPortalButton()) { if (buttonLocation.getType() != portal.getGate().getPortalButton()) {
generatePortalButton(portal, DirectionHelper.getBlockFaceFromYaw(portal.getYaw())); generatePortalButton(portal, DirectionHelper.getBlockFaceFromYaw(portal.getYaw()));
} }
} }

View File

@ -19,7 +19,11 @@ import java.util.UUID;
/** /**
* Helps migrate player names to UUID where necessary * Helps migrate player names to UUID where necessary
*/ */
public class UUIDMigrationHelper { public final class UUIDMigrationHelper {
private UUIDMigrationHelper() {
}
private static Map<String, List<Portal>> playerNamesToMigrate; private static Map<String, List<Portal>> playerNamesToMigrate;
@ -40,7 +44,7 @@ public class UUIDMigrationHelper {
return; return;
} }
Stargate.debug("PlayerEventListener::migrateUUID", String.format("Migrating name to UUID for player %s", Stargate.debug("UUIDMigrationHelper::migrateUUID", String.format("Migrating name to UUID for player %s",
playerName)); playerName));
List<Portal> portalsOwned = playersToMigrate.get(playerName); List<Portal> portalsOwned = playersToMigrate.get(playerName);
if (portalsOwned == null) { if (portalsOwned == null) {
@ -64,7 +68,7 @@ public class UUIDMigrationHelper {
//Get the real portal from the copy and set UUID //Get the real portal from the copy and set UUID
for (Portal portalCopy : portals) { for (Portal portalCopy : portals) {
Portal portal = PortalHandler.getByName(portalCopy.getName(), portalCopy.getNetwork()); Portal portal = PortalHandler.getByName(portalCopy.getCleanName(), portalCopy.getCleanNetwork());
if (portal != null) { if (portal != null) {
portal.getOwner().setUUID(uniqueId); portal.getOwner().setUUID(uniqueId);
worldsToSave.add(portal.getWorld()); worldsToSave.add(portal.getWorld());

View File

@ -25,3 +25,4 @@ toowner=economy.toOwner
chargefreedestination=economy.chargeFreeDestination chargefreedestination=economy.chargeFreeDestination
freegatesgreen=economy.freeGatesGreen freegatesgreen=economy.freeGatesGreen
CheckUpdates= CheckUpdates=
economy.freeGatesGreen=economy.freeGatesColored

View File

@ -27,7 +27,8 @@
# useCost - The cost to use a gate # useCost - The cost to use a gate
# toOwner - Whether the charge for using a gate goes to the gate's owner # toOwner - Whether the charge for using a gate goes to the gate's owner
# chargeFreeDestination - Whether a gate whose destination is a free gate is still charged # chargeFreeDestination - Whether a gate whose destination is a free gate is still charged
# freeGatesGreen - Whether a free gate in the destination list is drawn green # freeGatesColored - Whether a free gate in the destination list is marked with a color
# freeGatesColor - The color to use for marking free gates
# I-------I-------I # # I-------I-------I #
# Debug options # # Debug options #
# I-------I-------I # # I-------I-------I #
@ -64,7 +65,8 @@ economy:
useCost: 0 useCost: 0
toOwner: false toOwner: false
chargeFreeDestination: true chargeFreeDestination: true
freeGatesGreen: false freeGatesColored: false
freeGatesColor: DARK_GREEN
debugging: debugging:
debug: false debug: false
permissionDebug: false permissionDebug: false

View File

@ -1,6 +1,6 @@
name: Stargate name: Stargate
main: net.knarcraft.stargate.Stargate main: net.knarcraft.stargate.Stargate
version: 0.9.0.7 version: 0.9.2.3
description: Stargate mod for Bukkit Revived description: Stargate mod for Bukkit Revived
author: EpicKnarvik97 author: EpicKnarvik97
authors: [ Drakia, PseudoKnight, EpicKnarvik97 ] authors: [ Drakia, PseudoKnight, EpicKnarvik97 ]
@ -11,8 +11,8 @@ commands:
stargate: stargate:
aliases: aliases:
- sg - sg
description: Used to see stargate info description: Used to see stargate info, reloading and editing config values
usage: /<command> <reload/about> - Used to see stargate info or reload the plugin usage: /<command> <reload/about/config> - Used to see stargate info, reload the plugin or change config values
permissions: permissions:
stargate.*: stargate.*:
description: Wildcard permission which gives all Stargate permissions description: Wildcard permission which gives all Stargate permissions
@ -138,14 +138,18 @@ permissions:
stargate.admin.bungee: stargate.admin.bungee:
description: Allows the creation and destruction of a stargate between BungeeCord servers description: Allows the creation and destruction of a stargate between BungeeCord servers
default: false default: false
stargate.admin.config:
description: Allows the player to change config values from the chat
default: false
stargate.server: stargate.server:
description: Allows the creation of a BungeeCord stargate going to any server description: Allows the creation of a BungeeCord stargate going to any server
default: false default: false
stargate.admin: stargate.admin:
description: Allow all admin features and commands (Hidden/Private bypass, BungeeCord, Reload) description: Allow all admin features and commands (Hidden/Private bypass, BungeeCord, Reload, Config)
default: op default: op
children: children:
stargate.admin.reload: true stargate.admin.reload: true
stargate.admin.hidden: true stargate.admin.hidden: true
stargate.admin.private: true stargate.admin.private: true
stargate.admin.bungee: true stargate.admin.bungee: true
stargate.admin.config: true