42 Commits

Author SHA1 Message Date
29fdc8f849 Adds a new feature to the README 2022-01-27 00:44:31 +01:00
043c5f2408 Updates README and version to 0.9.3.0 2022-01-26 23:41:05 +01:00
a74d47e999 Makes sure default config values are stored with comments on the first run 2022-01-26 23:37:34 +01:00
e86be3e848 Finishes the work required for changing per-sign colors using the /sg config command 2022-01-26 23:27:31 +01:00
366cd3107e Updates per-sign inverted colors when the main or highlighting color is changed 2022-01-26 20:30:16 +01:00
02f6c6e9fc Updates README with recent changes 2022-01-26 18:17:10 +01:00
97670c9367 Adds the possibility to use the inverted default colors for per-sign colors
Adds code for getting inverted colors if "inverted" is given as the per-sign color
Fixes exceptions thrown when the per-sign config value is malformed
Changes the default to use inverted colors for crimson, dark_oak, spruce and warped signs
Adds methods to get main and highlighting colors from the portal sign drawer in case the given default colors are invalid and fallback colors are necessary instead
2022-01-26 18:02:53 +01:00
2773079a09 Uses the inverted color for a dyed sign's highlighting color 2022-01-26 15:49:07 +01:00
071f1895de Makes sure only the owner and players with stargate.admin.dye can dye stargate signs 2022-01-26 14:57:15 +01:00
4cae54e46f Adds support for dyed stargate signs
A dyed sign's color will now take priority over its main sign color. Black is used as the "default" color, so use black dye to remove dye effects
Adds a new class to keep track of a sign and its colors
Updates a bunch of code to make everything account for the dye color
2022-01-26 14:40:29 +01:00
7d41b75bac Makes string list config values display their default value properly
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2022-01-26 05:09:34 +01:00
404b4d0543 Changes the comment format for config files 2022-01-26 02:07:07 +01:00
842fd9c452 Fixes a few bugs regarding the new sign color system
Fixes missing STRING_LIST in loadConfig switch
Fixes missing color valid check in loadGateConfig
Fixes typing of PER_SIGN_COLORS
2022-01-26 02:06:42 +01:00
2bb0e8670d Makes a lot of changes necessary for RGB and per-sign color configuration support 2022-01-25 16:46:29 +01:00
acbdcd3ce3 Fixes a hang caused by MockBukkit 2022-01-25 15:34:27 +01:00
948f92f140 Updates Spigot and MockBukkit versions
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2022-01-15 21:59:46 +01:00
5d1d6ffaf0 Removes some unnecessary calculation when converting relative vectors to real vectors 2021-12-03 23:23:19 +01:00
a7dc02eef0 Updates plugin version and README
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-12-02 04:19:44 +01:00
9177773a0e Updates Spigot and Java version 2021-12-02 04:05:27 +01:00
fc5bac937a Changes the max age of gateway blocks to prevent the occasional purple beam
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-26 16:55:22 +01:00
f8ae83bc08 Updates README and version to 0.9.2.4
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-25 14:56:44 +01:00
cfb4910977 Adds a toggle-able admin alert when any admin joins the server 2021-11-25 14:56:05 +01:00
a61a03be33 Adds an update checker for alerting about new updates 2021-11-25 14:54:50 +01:00
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
35 changed files with 1432 additions and 463 deletions

View File

@ -3,18 +3,22 @@
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.
- Player permissions -- let players build their own networks.
- Vault economy support -- can add costs for create, destroy and use.
- Ability to create custom gate configurations. Three different default gate configurations are available.
- Message customization
- Multiple built-in languages (de, en, es, fr, hu, it, nb-no, nl, nn-no, pt-br, ru)
- Teleport across worlds or servers (BungeeCord supported)
- Vehicle teleportation -- teleport minecarts, boats, horses, pigs and striders
- Leashed teleportation -- teleport any creature in a leash with the player
- 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
- 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
- **Player permissions** -- let players build their own networks.
- **Vault economy support** -- can add costs for create, destroy and use.
- **Ability to create custom gate configurations**. Four different default gate configurations are available.
- **Message customization**
- **Multiple built-in languages** (de, en, es, fr, hu, it, nb-no, nl, nn-no, pt-br, ru)
- **Teleport across worlds or servers** (BungeeCord supported)
- **Vehicle teleportation** -- teleport minecarts, boats, horses, pigs and striders
- **Leashed teleportation** -- teleport any creature in a leash with the player
- **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
- **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
- **Color customization** -- Stargate signs can be colored in many ways. Colors can be set globally, or on a per sign
type basis
- **RGB and dye support** -- Signs can use RGB colors (using hex codes) as their main and highlighting colors, and can
also be dyed on a per-sign basis
## Background
@ -36,10 +40,8 @@ Permissions have had a few changes, so you should check the permissions section
permissions.
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
stargate owner re-create the stargate or edit the file in the portals folder in a text editor. There are various ways to
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.
a UUID, and not a username. A player name will be upgraded to a UUID when the player with the given name joins the
server.
# Permissions
@ -87,6 +89,7 @@ stargate.admin -- Allow all admin features (Hidden/Private bypass, BungeeCord, R
stargate.admin.bungee -- Allow the creation of BungeeCord stargates (U option)
stargate.admin.reload -- Allow use of the reload command
stargate.admin.config -- Allows the player to change config values from the chat
stargate.admin.dye -- Allows this player to change the dye of any stargate's sign
```
## Default Permissions
@ -134,7 +137,7 @@ section). See the Custom Gate Layout section to learn how to add custom gates.
player enters. (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
- '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
&\[0-9a-f] color codes are not counted in the character limit, thus allowing a 13-character name with an additional 2
@ -296,6 +299,7 @@ while the per-gate costs re defined in the .gate files. To define a certain cost
```
language - The language to use (Included languages: en, de, es, fr, hu, it, nb-no, nl, nn-no, pt-br, ru)
adminUpdateAlert - Whether to alert admins about an available update when joining the server
folders:
portalFolder - The folder your portal databases are saved in
gateFolder - The folder containing your .gate files
@ -305,8 +309,9 @@ gates:
cosmetic:
rememberDestination - Whether to set the first destination as the last used destination for all gates
sortNetworkDestinations - If true, network lists will be sorted alphabetically.
mainSignColor - This allows you to specify the color of the gate signs.
highlightSignColor - This allows you to specify the color of the sign markings.
mainSignColor - This allows you to specify the color of the gate signs. Use a color code such as WHITE,BLACK,YELLOW or a hex color code such as '#ed76d9'. You need quotes around hex color codes.
highlightSignColor - This allows you to specify the color of the sign markings. Use a color code such as WHITE,BLACK,YELLOW or a hex color code such as '#ed76d9'. You need quotes around hex color codes.
perSignColors: - A list of per-sign color specifications. Format: "SIGN_TYPE:mainColor,highlight_color". The SIGN_TYPE is OAK for an oak sign, DARK_OAK for a dark oak sign and so on. The colors can be "default" to use the color specified in "mainSignColor" or "highlightSignColor", "inverted" to use the inverse color of the default color, a normal color such as BLACK,WHITE,YELLOW or a hex color code such as #ed76d9.
integrity:
destroyedByExplosion - Whether to destroy a stargate with explosions, or stop an explosion if it contains a gates controls.
verifyPortals - Whether or not all the non-sign blocks are checked to match the gate layout when an old stargate is loaded at startup.
@ -391,6 +396,45 @@ portalInfoServer=Server: %server%
# Changes
#### \[Version 0.9.3.0] EpicKnarvik97 fork
- Adds support for RGB colors (use hex color codes)
- Adds support for dyed and glowing signs
- Adds support for specifying sign colors per sign type
- Adds a tab-completable config sub-command for easily changing per-sign colors
- Allows a per-sign color to be set as the inverse of the default color of the given type
#### \[Version 0.9.2.5] EpicKnarvik97 fork
- Updates Java version to JDK 17
- Updates Spigot API version to 1.18
#### \[Version 0.9.2.4] EpicKnarvik97 fork
- Adds update checking, which will display a notice in the console when updates are available
- Adds an alert about an available update when an admin joins the server
- Adds the adminUpdateAlert config option to allow the admin notices to be turned off
#### \[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

16
pom.xml
View File

@ -4,7 +4,7 @@
<groupId>net.knarcraft</groupId>
<artifactId>Stargate</artifactId>
<version>0.9.2.0</version>
<version>0.9.3.0</version>
<licenses>
<license>
@ -15,8 +15,8 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<repositories>
@ -34,7 +34,7 @@
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.17.1-R0.1-SNAPSHOT</version>
<version>1.18.1-R0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>net.milkbowl.vault</groupId>
@ -49,8 +49,8 @@
</dependency>
<dependency>
<groupId>com.github.seeseemelk</groupId>
<artifactId>MockBukkit-v1.17</artifactId>
<version>1.7.0</version>
<artifactId>MockBukkit-v1.18</artifactId>
<version>1.14.0</version>
<scope>test</scope>
</dependency>
<dependency>
@ -75,8 +75,8 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>16</source>
<target>16</target>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>

View File

@ -21,6 +21,7 @@ import net.knarcraft.stargate.portal.PortalRegistry;
import net.knarcraft.stargate.thread.BlockChangeThread;
import net.knarcraft.stargate.thread.ChunkUnloadThread;
import net.knarcraft.stargate.thread.StarGateThread;
import net.knarcraft.stargate.utility.UpdateChecker;
import org.bukkit.Server;
import org.bukkit.command.PluginCommand;
import org.bukkit.configuration.file.FileConfiguration;
@ -55,6 +56,8 @@ public class Stargate extends JavaPlugin {
private static PluginManager pluginManager;
private static StargateConfig stargateConfig;
private static String updateAvailable = null;
/**
* Empty constructor necessary for Spigot
*/
@ -74,6 +77,26 @@ public class Stargate extends JavaPlugin {
super(loader, descriptionFile, dataFolder, file);
}
/**
* Stores information about an available update
*
* <p>If a non-null version is given, joining admins will be alerted about the new update.</p>
*
* @param version <p>The version of the new update available</p>
*/
public static void setUpdateAvailable(String version) {
updateAvailable = version;
}
/**
* Gets information about an available update
*
* @return <p>The version number if an update is available. Null otherwise</p>
*/
public static String getUpdateAvailable() {
return updateAvailable;
}
/**
* Gets an instance of this plugin
*
@ -144,6 +167,7 @@ public class Stargate extends JavaPlugin {
*
* @return <p>The max portal name/network length</p>
*/
@SuppressWarnings("SameReturnValue")
public static int getMaxNameNetworkLength() {
return 13;
}
@ -315,6 +339,9 @@ public class Stargate extends JavaPlugin {
PluginDescriptionFile pluginDescriptionFile = this.getDescription();
pluginManager = getServer().getPluginManager();
FileConfiguration newConfig = this.getConfig();
this.saveDefaultConfig();
newConfig.options().copyDefaults(true);
logger = Logger.getLogger("Minecraft");
Server server = getServer();
stargate = this;
@ -333,6 +360,9 @@ public class Stargate extends JavaPlugin {
runThreads();
this.registerCommands();
//Check for any available updates
UpdateChecker.checkForUpdate();
}
/**

View File

@ -1,7 +1,7 @@
package net.knarcraft.stargate.command;
import net.knarcraft.stargate.Stargate;
import org.bukkit.ChatColor;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;

View File

@ -2,7 +2,14 @@ package net.knarcraft.stargate.command;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.ConfigOption;
import org.bukkit.ChatColor;
import net.knarcraft.stargate.config.ConfigTag;
import net.knarcraft.stargate.config.OptionDataType;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalRegistry;
import net.knarcraft.stargate.portal.PortalSignDrawer;
import net.md_5.bungee.api.ChatColor;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
@ -10,6 +17,9 @@ import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* This command represents the config command for changing config values
*/
@ -31,7 +41,11 @@ public class CommandConfig implements CommandExecutor {
return false;
}
if (args.length > 1) {
updateConfigValue(selectedOption, commandSender, args[1]);
if (selectedOption.getDataType() == OptionDataType.STRING_LIST) {
updateListConfigValue(selectedOption, commandSender, args);
} else {
updateConfigValue(selectedOption, commandSender, args[1]);
}
} else {
//Display info and the current value of the given config value
printConfigOptionValue(commandSender, selectedOption);
@ -55,9 +69,9 @@ public class CommandConfig implements CommandExecutor {
FileConfiguration configuration = Stargate.getInstance().getConfig();
//Validate any sign colors
if (selectedOption == ConfigOption.MAIN_SIGN_COLOR || selectedOption == ConfigOption.HIGHLIGHT_SIGN_COLOR) {
if (ConfigTag.COLOR.isTagged(selectedOption)) {
try {
ChatColor.valueOf(value.toUpperCase());
ChatColor.of(value.toUpperCase());
} catch (IllegalArgumentException | NullPointerException ignored) {
commandSender.sendMessage(ChatColor.RED + "Invalid color given");
return;
@ -66,43 +80,272 @@ public class CommandConfig implements CommandExecutor {
//Store the config values, accounting for the data type
switch (selectedOption.getDataType()) {
case BOOLEAN -> configuration.set(selectedOption.getConfigNode(), Boolean.parseBoolean(value));
case BOOLEAN -> updateBooleanConfigValue(selectedOption, value, configuration);
case INTEGER -> {
try {
configuration.set(selectedOption.getConfigNode(), Integer.parseInt(value));
} catch (NumberFormatException exception) {
commandSender.sendMessage(ChatColor.RED + "Invalid number given");
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;
}
}
updateStringConfigValue(selectedOption, commandSender, value);
configuration.set(selectedOption.getConfigNode(), value);
}
default -> {
Stargate.getStargateConfig().getConfigOptionsReference().put(selectedOption, value);
configuration.set(selectedOption.getConfigNode(), value);
}
default -> configuration.set(selectedOption.getConfigNode(), value);
}
saveAndReload(selectedOption, commandSender);
}
/**
* Updates a boolean config value
*
* @param selectedOption <p>The option which should be updated</p>
* @param value <p>The new value of the config option</p>
* @param configuration <p>The configuration file to save to</p>
*/
private void updateBooleanConfigValue(ConfigOption selectedOption, String value, FileConfiguration configuration) {
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);
}
/**
* Updates a string 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 updateStringConfigValue(ConfigOption selectedOption, CommandSender commandSender, String value) {
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);
}
/**
* 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 arguments <p>The arguments for the new config option</p>
*/
private void updateListConfigValue(ConfigOption selectedOption, CommandSender commandSender, String[] arguments) {
FileConfiguration configuration = Stargate.getInstance().getConfig();
if (selectedOption == ConfigOption.PER_SIGN_COLORS) {
if (arguments.length < 4) {
Stargate.getMessageSender().sendErrorMessage(commandSender, "Usage: /sg config perSignColors " +
"<SIGN_TYPE> <MAIN_COLOR> <HIGHLIGHTING_COLOR>");
return;
}
String colorString = parsePerSignColorInput(commandSender, arguments);
if (colorString == null) {
return;
}
//Update the per-sign colors according to input
updatePerSignColors(arguments[1], colorString, configuration);
}
saveAndReload(selectedOption, commandSender);
}
/**
* Parses the input given for changing the per-color string
*
* @param commandSender <p>The command sender that triggered the command</p>
* @param arguments <p>The arguments given by the user</p>
* @return <p>The per-sign color string to update with, or null if the input was invalid</p>
*/
private String parsePerSignColorInput(CommandSender commandSender, String[] arguments) {
//Make sure the sign type is an actual sign
if (Material.matchMaterial(arguments[1] + "_SIGN") == null) {
Stargate.getMessageSender().sendErrorMessage(commandSender, "The given sign type is invalid");
return null;
}
String colorString = arguments[1] + ":";
//Validate the colors given by the user
String[] errorMessage = new String[]{"The given main sign color is invalid!", "The given highlight sign color is invalid!"};
String[] newColors = new String[2];
for (int i = 0; i < 2; i++) {
if (validatePerSignColor(arguments[i + 2])) {
newColors[i] = arguments[i + 2];
} else {
Stargate.getMessageSender().sendErrorMessage(commandSender, errorMessage[i]);
return null;
}
}
colorString += String.join(",", newColors);
return colorString;
}
/**
* Updates the per-sign colors with the given input
*
* @param signType <p>The sign type that is updated</p>
* @param colorString <p>The new color string to replace any previous value with</p>
* @param configuration <p>The file configuration to update with the new per-sign colors</p>
*/
private void updatePerSignColors(String signType, String colorString, FileConfiguration configuration) {
List<String> newColorStrings = new ArrayList<>();
List<?> oldColors = (List<?>) Stargate.getStargateConfig().getConfigOptionsReference().get(ConfigOption.PER_SIGN_COLORS);
for (Object object : oldColors) {
newColorStrings.add(String.valueOf(object));
}
newColorStrings.removeIf((item) -> item.startsWith(signType));
newColorStrings.add(colorString);
Stargate.getStargateConfig().getConfigOptionsReference().put(ConfigOption.PER_SIGN_COLORS, newColorStrings);
configuration.set(ConfigOption.PER_SIGN_COLORS.getConfigNode(), newColorStrings);
}
/**
* Tries to validate one of the colors given when changing per-sign colors
*
* @param color <p>The color chosen by the user</p>
* @return <p>True if the given color is valid</p>
*/
private boolean validatePerSignColor(String color) {
ChatColor newHighlightColor = parseColor(color);
return newHighlightColor != null || color.equalsIgnoreCase("default") ||
color.equalsIgnoreCase("inverted");
}
/**
* Saves the configuration file and reloads as necessary
*
* @param selectedOption <p>The config option that was changed</p>
* @param commandSender <p>The command sender that executed the config command</p>
*/
private void saveAndReload(ConfigOption selectedOption, CommandSender commandSender) {
//Save the config file and reload if necessary
Stargate.getInstance().saveConfig();
reloadIfNecessary(commandSender);
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.of(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) {
//TODO: Only update the config values which have changed and do the least amount of work necessary to load the
// changes. Only do a full reload if absolutely necessary, or when the partial reloading would be as
// inefficient as a full reload.
Stargate.getStargateConfig().reload(commandSender);
private void reloadIfNecessary(CommandSender commandSender, ConfigOption configOption) {
if (ConfigTag.requiresFullReload(configOption)) {
//Reload everything
Stargate.getStargateConfig().reload(commandSender);
} else {
if (ConfigTag.requiresColorReload(configOption)) {
Stargate.getStargateConfig().getStargateGateConfig().loadPerSignColors();
}
if (ConfigTag.requiresPortalReload(configOption)) {
//Just unload and reload the portals
Stargate.getStargateConfig().unloadAllPortals();
Stargate.getStargateConfig().loadAllPortals();
}
if (ConfigTag.requiresLanguageReload(configOption)) {
//Reload the language loader
Stargate.getStargateConfig().getLanguageLoader().reload();
//Re-draw all portal signs
for (Portal portal : PortalRegistry.getAllPortals()) {
portal.drawSign();
}
}
if (ConfigTag.requiresEconomyReload(configOption)) {
//Load or unload Vault and Economy as necessary
Stargate.getStargateConfig().reloadEconomy();
}
}
}
/**
@ -137,8 +380,13 @@ public class CommandConfig implements CommandExecutor {
* @return <p>A string describing the config option</p>
*/
private String getOptionDescription(ConfigOption option) {
Object defaultValue = option.getDefaultValue();
String stringValue = String.valueOf(defaultValue);
if (option.getDataType() == OptionDataType.STRING_LIST) {
stringValue = "[" + StringUtils.join((String[]) defaultValue, ",") + "]";
}
return ChatColor.GOLD + option.getName() + ChatColor.WHITE + " - " + ChatColor.GREEN + option.getDescription() +
ChatColor.DARK_GRAY + " (Default: " + ChatColor.GRAY + option.getDefaultValue() + ChatColor.DARK_GRAY + ")";
ChatColor.DARK_GRAY + " (Default: " + ChatColor.GRAY + stringValue + ChatColor.DARK_GRAY + ")";
}
}

View File

@ -1,8 +1,8 @@
package net.knarcraft.stargate.command;
import net.knarcraft.stargate.Stargate;
import net.md_5.bungee.api.ChatColor;
import org.apache.commons.lang.ArrayUtils;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;

View File

@ -2,7 +2,9 @@ package net.knarcraft.stargate.command;
import net.knarcraft.stargate.config.ConfigOption;
import net.knarcraft.stargate.config.OptionDataType;
import org.bukkit.ChatColor;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
@ -17,15 +19,26 @@ import java.util.List;
*/
public class ConfigTabCompleter implements TabCompleter {
private List<String> signTypes;
private List<String> booleans;
private List<String> numbers;
private List<String> chatColors;
private List<String> languages;
private List<String> extendedColors;
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] args) {
if (signTypes == null || booleans == null || numbers == null || chatColors == null || languages == null) {
initializeAutoCompleteLists();
}
if (args.length > 1) {
ConfigOption selectedOption = ConfigOption.getByName(args[0]);
if (selectedOption == null) {
return new ArrayList<>();
} else if (selectedOption.getDataType() == OptionDataType.STRING_LIST) {
return getPossibleStringListOptionValues(selectedOption, args);
} else {
return getPossibleOptionValues(selectedOption, args[1]);
}
@ -63,18 +76,10 @@ public class ConfigTabCompleter implements TabCompleter {
* @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);
return filterMatching(languages, typedText);
case GATE_FOLDER:
case PORTAL_FOLDER:
case DEFAULT_GATE_NETWORK:
@ -88,7 +93,7 @@ public class ConfigTabCompleter implements TabCompleter {
case HIGHLIGHT_SIGN_COLOR:
case FREE_GATES_COLOR:
//Return all colors
return filterMatching(getColors(), typedText);
return filterMatching(chatColors, typedText);
}
//If the config value is a boolean, show the two boolean values
@ -104,48 +109,95 @@ public class ConfigTabCompleter implements TabCompleter {
return new ArrayList<>();
}
}
return null;
}
/**
* Gets all available languages
* Get possible values for the selected string list option
*
* @return <p>The available languages</p>
* @param selectedOption <p>The selected option</p>
* @param args <p>The arguments given by the user</p>
* @return <p>Some or all of the valid values for the option</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());
private List<String> getPossibleStringListOptionValues(ConfigOption selectedOption, String[] args) {
if (selectedOption == ConfigOption.PER_SIGN_COLORS) {
return getPerSignColorCompletion(args);
} else {
return null;
}
return colors;
}
/**
* Gets a list of all available chat colors
* Gets the tab completion values for completing the per-sign color text
*
* @return <p>A list of chat colors</p>
* @param args <p>The arguments given by the user</p>
* @return <p>The options to give the user</p>
*/
private List<String> getPerSignColorCompletion(String[] args) {
if (args.length < 3) {
return filterMatching(signTypes, args[1]);
} else if (args.length < 4) {
return filterMatching(extendedColors, args[2]);
} else if (args.length < 5) {
return filterMatching(extendedColors, args[3]);
}
return new ArrayList<>();
}
/**
* 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;
}
/**
* Initializes all lists of auto-completable values
*/
private void initializeAutoCompleteLists() {
booleans = new ArrayList<>();
booleans.add("true");
booleans.add("false");
numbers = new ArrayList<>();
numbers.add("0");
numbers.add("5");
signTypes = new ArrayList<>();
for (Material material : Material.values()) {
if (Tag.STANDING_SIGNS.isTagged(material)) {
signTypes.add(material.toString().replace("_SIGN", ""));
}
}
getColors();
initializeLanguages();
extendedColors = new ArrayList<>(chatColors);
extendedColors.add("default");
extendedColors.add("inverted");
}
/**
* Initializes the list of chat colors
*/
private void getColors() {
chatColors = new ArrayList<>();
for (ChatColor color : getChatColors()) {
chatColors.add(color.getName());
}
}
/**
* Gets available chat colors
*
* @return <p>The available chat colors</p>
*/
private List<ChatColor> getChatColors() {
List<ChatColor> chatColors = new ArrayList<>();
@ -165,19 +217,29 @@ public class ConfigTabCompleter implements TabCompleter {
chatColors.add(ChatColor.DARK_GRAY);
chatColors.add(ChatColor.GRAY);
chatColors.add(ChatColor.YELLOW);
chatColors.add(ChatColor.of("#ed76d9"));
chatColors.add(ChatColor.of("#ffecb7"));
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>
* Initializes the list of all available languages
*/
private List<String> putStringInList(String value) {
List<String> list = new ArrayList<>();
list.add(value);
return list;
private void initializeLanguages() {
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");
//TODO: Generate this list dynamically by listing the language files in the jar and adding the user's custom
// language files
}
}

View File

@ -50,6 +50,10 @@ public enum ConfigOption {
*/
HIGHLIGHT_SIGN_COLOR("gates.cosmetic.highlightSignColor", "The text color used for highlighting stargate signs", "WHITE"),
PER_SIGN_COLORS("gates.cosmetic.perSignColors", "The per-sign color specification", new String[]{
"'ACACIA:default,default'", "'BIRCH:default,default'", "'CRIMSON:inverted,inverted'", "'DARK_OAK:inverted,inverted'",
"'JUNGLE:default,default'", "'OAK:default,default'", "'SPRUCE:inverted,inverted'", "'WARPED:inverted,inverted'"}),
/**
* Whether to destroy portals when any blocks are broken by explosions
*/
@ -147,7 +151,12 @@ public enum ConfigOption {
/**
* Whether to enable debug output for debugging permissions
*/
PERMISSION_DEBUG("debugging.permissionDebug", "Whether to enable permission debugging output", false);
PERMISSION_DEBUG("debugging.permissionDebug", "Whether to enable permission debugging output", false),
/**
* Whether to alert admins about new updates
*/
ADMIN_UPDATE_ALERT("adminUpdateAlert", "Whether to alert admins about new plugin updates", true);
private final String configNode;
@ -167,14 +176,16 @@ public enum ConfigOption {
this.description = description;
this.defaultValue = defaultValue;
if (defaultValue instanceof String) {
if (defaultValue instanceof String[]) {
this.dataType = OptionDataType.STRING_LIST;
} else 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.");
throw new IllegalArgumentException("Unknown config data type encountered: " + defaultValue);
}
}

View File

@ -0,0 +1,85 @@
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, ConfigOption.PER_SIGN_COLORS}),
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 "reload of colors" to take effect
*
* @param configOption <p>The config option to check</p>
* @return <p>True if changing the config option requires a "reload of colors" to take effect</p>
*/
public static boolean requiresColorReload(ConfigOption configOption) {
return (COLOR.isTagged(configOption) && configOption != ConfigOption.FREE_GATES_COLOR);
}
/**
* 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,13 +1,11 @@
package net.knarcraft.stargate.config;
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.utility.PermissionHelper;
import net.md_5.bungee.api.ChatColor;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
@ -15,22 +13,16 @@ import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.ServicesManager;
import java.util.Map;
import java.util.UUID;
/**
* The economy config keeps track of economy config values and performs economy actions such as payment for using a gate
*/
public final class EconomyConfig {
private boolean economyEnabled = false;
private Economy economy = null;
private Plugin vault = null;
private int useCost = 0;
private int createCost = 0;
private int destroyCost = 0;
private boolean toOwner = false;
private boolean chargeFreeDestination = true;
private boolean freeGatesColored = false;
private final Map<ConfigOption, Object> configOptions;
/**
* Instantiates a new economy config
@ -38,7 +30,13 @@ public final class EconomyConfig {
* @param configOptions <p>The loaded config options to read</p>
*/
public EconomyConfig(Map<ConfigOption, Object> configOptions) {
loadEconomyConfig(configOptions);
this.configOptions = configOptions;
try {
String freeColor = (String) configOptions.get(ConfigOption.FREE_GATES_COLOR);
PortalSignDrawer.setFreeColor(ChatColor.of(freeColor.toUpperCase()));
} catch (IllegalArgumentException | NullPointerException ignored) {
PortalSignDrawer.setFreeColor(ChatColor.DARK_GREEN);
}
}
/**
@ -47,7 +45,7 @@ public final class EconomyConfig {
* @return <p>The gate use cost</p>
*/
public int getDefaultUseCost() {
return useCost;
return (Integer) configOptions.get(ConfigOption.USE_COST);
}
/**
@ -56,7 +54,7 @@ public final class EconomyConfig {
* @return <p>Whether economy is enabled</p>
*/
public boolean isEconomyEnabled() {
return economyEnabled;
return (boolean) configOptions.get(ConfigOption.USE_ECONOMY);
}
/**
@ -91,7 +89,7 @@ public final class EconomyConfig {
* @return <p>Whether free portals should be colored</p>
*/
public boolean drawFreePortalsColored() {
return freeGatesColored;
return (boolean) configOptions.get(ConfigOption.FREE_GATES_COLORED);
}
/**
@ -103,8 +101,8 @@ public final class EconomyConfig {
*
* @return <p>Whether to charge for free destinations</p>
*/
public boolean chargeFreeDestination() {
return chargeFreeDestination;
public boolean freeIfFreeDestination() {
return !((boolean) configOptions.get(ConfigOption.CHARGE_FREE_DESTINATION));
}
/**
@ -113,21 +111,7 @@ public final class EconomyConfig {
* @return <p>Whether to send payments to the portal owner</p>
*/
public boolean sendPaymentToOwner() {
return toOwner;
}
/**
* 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;
return (boolean) configOptions.get(ConfigOption.TO_OWNER);
}
/**
@ -136,18 +120,7 @@ public final class EconomyConfig {
* @return <p>The gate creation cost</p>
*/
public int getDefaultCreateCost() {
return createCost;
}
/**
* 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;
return (Integer) configOptions.get(ConfigOption.CREATE_COST);
}
/**
@ -156,31 +129,7 @@ public final class EconomyConfig {
* @return <p>The gate destruction cost</p>
*/
public int getDefaultDestroyCost() {
return destroyCost;
}
/**
* 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);
return (Integer) configOptions.get(ConfigOption.DESTROY_COST);
}
/**
@ -194,22 +143,6 @@ public final class EconomyConfig {
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
*
@ -217,7 +150,7 @@ public final class EconomyConfig {
* @return <p>A formatted text string describing the amount</p>
*/
public String format(int amount) {
if (economyEnabled) {
if (isEconomyEnabled()) {
return economy.format(amount);
} else {
return "";
@ -231,7 +164,7 @@ public final class EconomyConfig {
* @return <p>True if economy was enabled</p>
*/
public boolean setupEconomy(PluginManager pluginManager) {
if (!economyEnabled) {
if (!isEconomyEnabled()) {
return false;
}
//Check if vault is loaded
@ -249,7 +182,7 @@ public final class EconomyConfig {
} else {
Stargate.logInfo(Stargate.getString("vaultLoadError"));
}
economyEnabled = false;
configOptions.put(ConfigOption.USE_ECONOMY, false);
return false;
}
@ -259,46 +192,7 @@ public final class EconomyConfig {
* @return <p>True if the user has turned on economy and economy is available</p>
*/
public boolean useEconomy() {
return economyEnabled && 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();
return isEconomyEnabled() && economy != null;
}
/**
@ -331,28 +225,6 @@ public final class EconomyConfig {
}
}
/**
* Loads all config values related to economy
*
* @param configOptions <p>The loaded config options to get values from</p>
*/
private void loadEconomyConfig(Map<ConfigOption, Object> configOptions) {
economyEnabled = (boolean) configOptions.get(ConfigOption.USE_ECONOMY);
setDefaultCreateCost((Integer) configOptions.get(ConfigOption.CREATE_COST));
setDefaultDestroyCost((Integer) configOptions.get(ConfigOption.DESTROY_COST));
setDefaultUseCost((Integer) configOptions.get(ConfigOption.USE_COST));
toOwner = (boolean) configOptions.get(ConfigOption.TO_OWNER);
chargeFreeDestination = (boolean) configOptions.get(ConfigOption.CHARGE_FREE_DESTINATION);
freeGatesColored = (boolean) configOptions.get(ConfigOption.FREE_GATES_COLORED);
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);
}
}
/**
* Determines if a player can do a gate action for free
*
@ -364,41 +236,4 @@ public final class EconomyConfig {
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

@ -1,6 +1,6 @@
package net.knarcraft.stargate.config;
import org.bukkit.ChatColor;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.command.CommandSender;
/**

View File

@ -13,6 +13,7 @@ public enum OptionDataType {
* The data type for the option is a Boolean
*/
BOOLEAN,
STRING_LIST,
/**
* The data type for the option is an Integer
*/

View File

@ -46,8 +46,6 @@ public final class StargateConfig {
private String portalFolder;
private String languageName = "en";
private boolean debuggingEnabled = false;
private boolean permissionDebuggingEnabled = false;
private final Map<ConfigOption, Object> configOptions;
/**
@ -65,6 +63,18 @@ public final class StargateConfig {
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
*/
@ -81,7 +91,7 @@ public final class StargateConfig {
languageLoader.reload();
messageSender = new MessageSender(languageLoader);
if (debuggingEnabled) {
if (isDebuggingEnabled()) {
languageLoader.debug();
}
@ -130,7 +140,7 @@ public final class StargateConfig {
* @return <p>Whether debugging is enabled</p>
*/
public boolean isDebuggingEnabled() {
return debuggingEnabled;
return (boolean) configOptions.get(ConfigOption.DEBUG);
}
/**
@ -139,7 +149,7 @@ public final class StargateConfig {
* @return <p>Whether permission debugging is enabled</p>
*/
public boolean isPermissionDebuggingEnabled() {
return permissionDebuggingEnabled;
return (boolean) configOptions.get(ConfigOption.PERMISSION_DEBUG);
}
/**
@ -186,6 +196,17 @@ public final class StargateConfig {
* Un-loads all loaded data
*/
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
for (Portal activePortal : activePortalsQueue) {
activePortal.getPortalActivator().deactivate();
@ -201,9 +222,6 @@ public final class StargateConfig {
//Clear all loaded portals
PortalRegistry.clearPortals();
//Clear all loaded gates
GateHandler.clearGates();
}
/**
@ -256,7 +274,7 @@ public final class StargateConfig {
//Update the language loader in case the loaded language changed
languageLoader.setChosenLanguage(languageName);
languageLoader.reload();
if (debuggingEnabled) {
if (isDebuggingEnabled()) {
languageLoader.debug();
}
@ -267,7 +285,7 @@ public final class StargateConfig {
/**
* Starts the listener for listening to BungeeCord messages
*/
private void startStopBungeeListener(boolean start) {
public void startStopBungeeListener(boolean start) {
Messenger messenger = Bukkit.getMessenger();
String bungeeChannel = "BungeeCord";
@ -283,7 +301,7 @@ public final class StargateConfig {
/**
* Reloads economy by enabling or disabling it as necessary
*/
private void reloadEconomy() {
public void reloadEconomy() {
EconomyConfig economyConfig = getEconomyConfig();
if (economyConfig.isEconomyEnabled() && economyConfig.getEconomy() == null) {
setupVaultEconomy();
@ -301,6 +319,15 @@ public final class StargateConfig {
}
}
/**
* Gets whether admins should be alerted about new plugin updates
*
* @return <p>Whether admins should be alerted about new updates</p>
*/
public boolean alertAdminsAboutUpdates() {
return (boolean) configOptions.get(ConfigOption.ADMIN_UPDATE_ALERT);
}
/**
* Loads all config values
*/
@ -324,6 +351,7 @@ public final class StargateConfig {
//Load the option using its correct data type
switch (option.getDataType()) {
case STRING_LIST -> optionValue = newConfig.getStringList(configNode);
case STRING -> {
String value = newConfig.getString(configNode);
optionValue = value != null ? value.trim() : "";
@ -342,10 +370,6 @@ public final class StargateConfig {
portalFolder = (String) configOptions.get(ConfigOption.PORTAL_FOLDER);
gateFolder = (String) configOptions.get(ConfigOption.GATE_FOLDER);
//Get enabled debug settings from the config
debuggingEnabled = (boolean) configOptions.get(ConfigOption.DEBUG);
permissionDebuggingEnabled = (boolean) configOptions.get(ConfigOption.PERMISSION_DEBUG);
//If users have an outdated config, assume they also need to update their default gates
if (isMigrating) {
GateHandler.writeDefaultGatesToFolder(gateFolder);

View File

@ -2,8 +2,14 @@ package net.knarcraft.stargate.config;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.PortalSignDrawer;
import org.bukkit.ChatColor;
import net.knarcraft.stargate.utility.ColorHelper;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.Color;
import org.bukkit.Material;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@ -178,8 +184,91 @@ public final class StargateGateConfig {
*/
private void loadGateConfig() {
//Load the sign colors
loadSignColor((String) configOptions.get(ConfigOption.MAIN_SIGN_COLOR),
(String) configOptions.get(ConfigOption.HIGHLIGHT_SIGN_COLOR));
String mainSignColor = (String) configOptions.get(ConfigOption.MAIN_SIGN_COLOR);
String highlightSignColor = (String) configOptions.get(ConfigOption.HIGHLIGHT_SIGN_COLOR);
loadPerSignColor(mainSignColor, highlightSignColor);
loadPerSignColors();
}
/**
* Loads the per-sign colors specified in the config file
*/
public void loadPerSignColors() {
List<?> perSignColors = (List<?>) configOptions.get(ConfigOption.PER_SIGN_COLORS);
ChatColor[] defaultColors = new ChatColor[]{PortalSignDrawer.getMainColor(), PortalSignDrawer.getHighlightColor()};
List<Map<Material, ChatColor>> colorMaps = new ArrayList<>();
colorMaps.add(new HashMap<>());
colorMaps.add(new HashMap<>());
for (Object signColorSpecification : perSignColors) {
parsePerSignColors(signColorSpecification, defaultColors, colorMaps);
}
PortalSignDrawer.setPerSignMainColors(colorMaps.get(0));
PortalSignDrawer.setPerSignHighlightColors(colorMaps.get(1));
}
/**
* Parses a per-sign color specification object and stores the result
*
* @param signColorSpecification <p>The sign color specification to parse</p>
* @param defaultColors <p>The specified default colors</p>
* @param colorMaps <p>The list of color maps to save the resulting colors to</p>
*/
private void parsePerSignColors(Object signColorSpecification, ChatColor[] defaultColors,
List<Map<Material, ChatColor>> colorMaps) {
String[] specificationData = String.valueOf(signColorSpecification).split(":");
Material[] signMaterials = new Material[]{Material.matchMaterial(specificationData[0] + "_SIGN"),
Material.matchMaterial(specificationData[0] + "_WALL_SIGN")};
if (specificationData.length != 2) {
Stargate.logWarning("You have an invalid per-sign line in your config.yml file. Please fix it!");
return;
}
String[] colors = specificationData[1].split(",");
if (colors.length != 2) {
Stargate.logWarning("You have an invalid per-sign line in your config.yml file. Please fix it!");
return;
}
for (int colorIndex = 0; colorIndex < 2; colorIndex++) {
if (colors[colorIndex].equalsIgnoreCase("default")) {
continue;
}
loadPerSignColor(colors, colorIndex, defaultColors, signMaterials, colorMaps);
}
}
/**
* Loads a per-sign color
*
* @param colors <p>The colors specified in the config file</p>
* @param colorIndex <p>The index of the color to load</p>
* @param defaultColors <p>The specified default colors</p>
* @param signMaterials <p>The materials to load this color for</p>
* @param colorMaps <p>The list of color maps to save the resulting color to</p>
*/
private void loadPerSignColor(String[] colors, int colorIndex, ChatColor[] defaultColors, Material[] signMaterials,
List<Map<Material, ChatColor>> colorMaps) {
ChatColor parsedColor;
if (colors[colorIndex].equalsIgnoreCase("inverted")) {
//Convert from ChatColor to awt.Color to Bukkit.Color then invert and convert to ChatColor
java.awt.Color color = defaultColors[colorIndex].getColor();
parsedColor = ColorHelper.fromColor(ColorHelper.invert(Color.fromRGB(color.getRed(),
color.getGreen(), color.getBlue())));
} else {
try {
parsedColor = ChatColor.of(colors[colorIndex]);
} catch (IllegalArgumentException | NullPointerException exception) {
Stargate.logWarning("You have specified an invalid per-sign color in your config.yml. Custom color for \"" +
signMaterials[0] + "\" disabled");
return;
}
}
if (parsedColor != null) {
for (Material signMaterial : signMaterials) {
colorMaps.get(colorIndex).put(signMaterial, parsedColor);
}
}
}
/**
@ -187,16 +276,19 @@ public final class StargateGateConfig {
*
* @param mainSignColor <p>A string representing the main sign color</p>
*/
private void loadSignColor(String mainSignColor, String highlightSignColor) {
if (mainSignColor != null && highlightSignColor != null) {
try {
PortalSignDrawer.setColors(ChatColor.valueOf(mainSignColor.toUpperCase()),
ChatColor.valueOf(highlightSignColor.toUpperCase()));
return;
} catch (IllegalArgumentException | NullPointerException ignored) {
}
private void loadPerSignColor(String mainSignColor, String highlightSignColor) {
try {
PortalSignDrawer.setMainColor(ChatColor.of(mainSignColor.toUpperCase()));
} catch (IllegalArgumentException | NullPointerException exception) {
Stargate.logWarning("You have specified an invalid main sign color in your config.yml. Defaulting to BLACK");
PortalSignDrawer.setMainColor(ChatColor.BLACK);
}
try {
PortalSignDrawer.setHighlightColor(ChatColor.of(highlightSignColor.toUpperCase()));
} catch (IllegalArgumentException | NullPointerException exception) {
Stargate.logWarning("You have specified an invalid highlighting sign color in your config.yml. Defaulting to WHITE");
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

@ -0,0 +1,67 @@
package net.knarcraft.stargate.container;
import net.knarcraft.stargate.utility.ColorHelper;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.DyeColor;
import org.bukkit.block.Sign;
/**
* A class that keeps track of the sign colors for a given sign
*/
public class SignData {
private final Sign sign;
private final ChatColor mainSignColor;
private final ChatColor highlightSignColor;
private final DyeColor dyedColor;
/**
* Instantiates a new sign colors object
*
* @param sign <p>The sign the colors belong to</p>
* @param mainSignColor <p>The main color to use for the sign</p>
* @param highlightSignColor <p>The highlighting color to use for the sign</p>
*/
public SignData(Sign sign, ChatColor mainSignColor, ChatColor highlightSignColor) {
this.sign = sign;
this.mainSignColor = mainSignColor;
this.highlightSignColor = highlightSignColor;
this.dyedColor = sign.getColor();
}
/**
* Gets the sign of this sign colors object
*
* @return <p>The sign of this sign colors object</p>
*/
public Sign getSign() {
return sign;
}
/**
* Gets the main color of the sign
*
* @return <p>The main color of the sign</p>
*/
public ChatColor getMainSignColor() {
if (dyedColor != DyeColor.BLACK) {
return ColorHelper.fromColor(dyedColor.getColor());
} else {
return mainSignColor;
}
}
/**
* Gets the highlighting color of the sign
*
* @return <p>The highlighting color of the sign</p>
*/
public ChatColor getHighlightSignColor() {
if (dyedColor != DyeColor.BLACK) {
return ColorHelper.fromColor(ColorHelper.invert(dyedColor.getColor()));
} else {
return highlightSignColor;
}
}
}

View File

@ -25,6 +25,7 @@ import org.bukkit.event.block.BlockPhysicsEvent;
import org.bukkit.event.block.BlockPistonEvent;
import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.block.BlockPistonRetractEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.EntityBlockFormEvent;
import org.bukkit.event.block.SignChangeEvent;
@ -96,6 +97,22 @@ public class BlockEventListener implements Listener {
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
*
@ -140,7 +157,9 @@ public class BlockEventListener implements Listener {
//Destroy denied
if (destroyEvent.getDeny()) {
Stargate.getMessageSender().sendErrorMessage(player, destroyEvent.getDenyReason());
if (!destroyEvent.getDenyReason().trim().isEmpty()) {
Stargate.getMessageSender().sendErrorMessage(player, destroyEvent.getDenyReason());
}
event.setCancelled(true);
return;
}
@ -169,7 +188,7 @@ public class BlockEventListener implements Listener {
if (cost != 0) {
String portalName = portal.getName();
//Cannot pay
if (!Stargate.getEconomyConfig().chargePlayerIfNecessary(player, cost)) {
if (!EconomyHelper.chargePlayerIfNecessary(player, cost)) {
Stargate.debug("onBlockBreak", "Insufficient Funds");
EconomyHelper.sendInsufficientFundsMessage(portalName, player, cost);
event.setCancelled(true);

View File

@ -7,12 +7,15 @@ import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalActivator;
import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter;
import net.knarcraft.stargate.portal.teleporter.Teleporter;
import net.knarcraft.stargate.portal.teleporter.VehicleTeleporter;
import net.knarcraft.stargate.utility.BungeeHelper;
import net.knarcraft.stargate.utility.MaterialHelper;
import net.knarcraft.stargate.utility.PermissionHelper;
import net.knarcraft.stargate.utility.UUIDMigrationHelper;
import org.bukkit.ChatColor;
import net.knarcraft.stargate.utility.UpdateChecker;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.block.Block;
import org.bukkit.block.data.type.WallSign;
@ -47,14 +50,22 @@ public class PlayerEventListener implements Listener {
*/
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
//Migrate player name to UUID if necessary
UUIDMigrationHelper.migrateUUID(event.getPlayer());
UUIDMigrationHelper.migrateUUID(player);
//Notify joining admins about the available update
String availableUpdate = Stargate.getUpdateAvailable();
if (availableUpdate != null && Stargate.getStargateConfig().alertAdminsAboutUpdates() &&
player.hasPermission("stargate.admin")) {
String updateMessage = UpdateChecker.getUpdateAvailableString(availableUpdate, Stargate.getPluginVersion());
Stargate.getMessageSender().sendErrorMessage(player, updateMessage);
}
if (!Stargate.getGateConfig().enableBungee()) {
return;
}
Player player = event.getPlayer();
//Check if the player is waiting to be teleported to a stargate
String destination = BungeeHelper.removeFromQueue(player.getUniqueId());
if (destination == null) {
@ -170,7 +181,9 @@ public class PlayerEventListener implements Listener {
}
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);
}
/**
@ -209,6 +222,18 @@ public class PlayerEventListener implements Listener {
return;
}
//Allow players with permissions to apply dye to signs
EquipmentSlot hand = event.getHand();
if (hand != null && (PermissionHelper.hasPermission(player, "stargate.admin.dye") ||
portal.isOwner(player))) {
String itemName = player.getInventory().getItem(hand).getType().toString();
if (itemName.endsWith("DYE") || itemName.endsWith("INK_SAC")) {
event.setUseInteractedBlock(Event.Result.ALLOW);
Bukkit.getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(), portal::drawSign, 1);
return;
}
}
event.setUseInteractedBlock(Event.Result.DENY);
if (leftClick) {
//Cancel event in creative mode to prevent breaking the sign

View File

@ -3,6 +3,7 @@ package net.knarcraft.stargate.listener;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.teleporter.Teleporter;
import net.knarcraft.stargate.portal.teleporter.VehicleTeleporter;
import net.knarcraft.stargate.utility.EconomyHelper;
import net.knarcraft.stargate.utility.EntityHelper;
@ -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
// 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 (!takePlayerPayment(passengers, entrancePortal, cost)) {
return;
@ -164,12 +165,16 @@ public class VehicleEventListener implements Listener {
}
//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);
if (!canAffordFee && !entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("ecoInFunds"));
if (!canAffordFee) {
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("ecoInFunds"));
}
return false;
}
return canAffordFee;
return Teleporter.noLeashedCreaturesPreventTeleportation(player);
}
}

View File

@ -8,7 +8,7 @@ import net.knarcraft.stargate.portal.property.PortalOptions;
import net.knarcraft.stargate.portal.property.PortalOwner;
import net.knarcraft.stargate.portal.property.PortalStructure;
import net.knarcraft.stargate.portal.property.gate.Gate;
import org.bukkit.ChatColor;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.World;
import org.bukkit.entity.Player;

View File

@ -192,7 +192,9 @@ public class PortalCreator {
//Tell the user why it was denied from creating the portal
if (stargateCreateEvent.getDeny()) {
Stargate.getMessageSender().sendErrorMessage(player, stargateCreateEvent.getDenyReason());
if (!stargateCreateEvent.getDenyReason().trim().isEmpty()) {
Stargate.getMessageSender().sendErrorMessage(player, stargateCreateEvent.getDenyReason());
}
return null;
}
@ -264,7 +266,7 @@ public class PortalCreator {
if (cost > 0) {
//Deduct the required fee from the player
if (!Stargate.getEconomyConfig().chargePlayerIfNecessary(player, cost)) {
if (!EconomyHelper.chargePlayerIfNecessary(player, cost)) {
EconomyHelper.sendInsufficientFundsMessage(portalName, player, cost);
Stargate.debug("createPortal", "Insufficient Funds");
return false;

View File

@ -1,13 +1,19 @@
package net.knarcraft.stargate.portal;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.SignData;
import net.knarcraft.stargate.portal.property.PortalLocation;
import net.knarcraft.stargate.utility.PermissionHelper;
import org.bukkit.ChatColor;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
import java.util.Map;
import static net.knarcraft.stargate.utility.ColorHelper.translateAllColorCodes;
/**
* The portal sign drawer draws the sing of a given portal
*/
@ -18,6 +24,8 @@ public class PortalSignDrawer {
private static ChatColor freeColor;
private static ChatColor mainColor;
private static ChatColor highlightColor;
private static Map<Material, ChatColor> perSignMainColors;
private static Map<Material, ChatColor> perSignHighlightColors;
/**
* Instantiates a new portal sign drawer
@ -29,19 +37,27 @@ public class PortalSignDrawer {
}
/**
* Sets the main and highlighting sign colors
* 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
* around portal names and network names ('>','<','-',')','(')</p>
* <p>The highlighting color is used for the markings around portal names and network names ('>','<','-',')','(').</p>
*
* @param newMainColor <p>The new main sign color</p>
* @param newHighlightColor <p>The new highlight color</p>
*/
public static void setColors(ChatColor newMainColor, ChatColor newHighlightColor) {
mainColor = newMainColor;
public static void setHighlightColor(ChatColor 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
*
@ -51,6 +67,42 @@ public class PortalSignDrawer {
PortalSignDrawer.freeColor = freeColor;
}
/**
* Sets the per-sign main colors
*
* @param signMainColors <p>The per-sign main colors</p>
*/
public static void setPerSignMainColors(Map<Material, ChatColor> signMainColors) {
PortalSignDrawer.perSignMainColors = signMainColors;
}
/**
* Sets the per-sign highlight colors
*
* @param signHighlightColors <p>The per-sign highlight colors</p>
*/
public static void setPerSignHighlightColors(Map<Material, ChatColor> signHighlightColors) {
PortalSignDrawer.perSignHighlightColors = signHighlightColors;
}
/**
* Gets the currently used main sign color
*
* @return <p>The currently used main sign color</p>
*/
public static ChatColor getMainColor() {
return mainColor;
}
/**
* Gets the currently used highlighting sign color
*
* @return <p>The currently used highlighting sign color</p>
*/
public static ChatColor getHighlightColor() {
return highlightColor;
}
/**
* Draws the sign of the portal this sign drawer is responsible for
*/
@ -60,7 +112,8 @@ public class PortalSignDrawer {
return;
}
drawSign(sign);
SignData signData = new SignData(sign, getMainColor(sign.getType()), getHighlightColor(sign.getType()));
drawSign(signData);
}
/**
@ -85,26 +138,30 @@ public class PortalSignDrawer {
/**
* Draws the sign of the portal this sign drawer is responsible for
*
* @param sign <p>The sign re-draw</p>
* @param signData <p>All necessary sign information</p>
*/
private void drawSign(Sign sign) {
private void drawSign(SignData signData) {
Sign sign = signData.getSign();
ChatColor highlightColor = signData.getHighlightSignColor();
ChatColor mainColor = signData.getMainSignColor();
//Clear sign
clearSign(sign);
setLine(sign, 0, highlightColor + "-" + mainColor + fixColor(portal.getName()) + highlightColor + "-");
setLine(signData, 0, highlightColor + "-" + mainColor + translateAllColorCodes(portal.getName()) +
highlightColor + "-");
if (!portal.getPortalActivator().isActive()) {
//Default sign text
drawInactiveSign(sign);
drawInactiveSign(signData);
} else {
if (portal.getOptions().isBungee()) {
//Bungee sign
drawBungeeSign(sign);
drawBungeeSign(signData);
} else if (portal.getOptions().isFixed()) {
//Sign pointing at one other portal
drawFixedSign(sign);
drawFixedSign(signData);
} else {
//Networking stuff
drawNetworkSign(sign);
drawNetworkSign(signData);
}
}
@ -131,16 +188,16 @@ public class PortalSignDrawer {
return;
}
clearSign(sign);
sign.setLine(0, fixColor(portal.getName()));
sign.setLine(0, translateAllColorCodes(portal.getName()));
sign.update();
}
/**
* Draws a sign with choose-able network locations
*
* @param sign <p>The sign to re-draw</p>
* @param signData <p>All necessary sign information</p>
*/
private void drawNetworkSign(Sign sign) {
private void drawNetworkSign(SignData signData) {
PortalActivator destinations = portal.getPortalActivator();
int maxIndex = destinations.getDestinations().size() - 1;
int signLineIndex = 0;
@ -150,85 +207,91 @@ public class PortalSignDrawer {
//Last, and not only entry. Draw the entry two back
if ((destinationIndex == maxIndex) && (maxIndex > 1)) {
drawNetworkSignLine(freeGatesColored, sign, ++signLineIndex, destinationIndex - 2);
drawNetworkSignLine(signData, freeGatesColored, ++signLineIndex, destinationIndex - 2);
}
//Not first entry. Draw the previous entry
if (destinationIndex > 0) {
drawNetworkSignLine(freeGatesColored, sign, ++signLineIndex, destinationIndex - 1);
drawNetworkSignLine(signData, freeGatesColored, ++signLineIndex, destinationIndex - 1);
}
//Draw the chosen entry (line 2 or 3)
drawNetworkSignChosenLine(freeGatesColored, sign, ++signLineIndex);
drawNetworkSignChosenLine(signData, freeGatesColored, ++signLineIndex);
//Has another entry and space on the sign
if ((maxIndex >= destinationIndex + 1)) {
drawNetworkSignLine(freeGatesColored, sign, ++signLineIndex, destinationIndex + 1);
drawNetworkSignLine(signData, freeGatesColored, ++signLineIndex, destinationIndex + 1);
}
//Has another entry and space on the sign
if ((maxIndex >= destinationIndex + 2) && (++signLineIndex <= 3)) {
drawNetworkSignLine(freeGatesColored, sign, signLineIndex, destinationIndex + 2);
drawNetworkSignLine(signData, freeGatesColored, signLineIndex, destinationIndex + 2);
}
}
/**
* Draws the chosen destination on one sign line
*
* @param signData <p>All necessary sign information</p>
* @param freeGatesColored <p>Whether to display free gates in a different color</p>
* @param sign <p>The sign to draw on</p>
* @param signLineIndex <p>The line to draw on</p>
*/
private void drawNetworkSignChosenLine(boolean freeGatesColored, Sign sign, int signLineIndex) {
private void drawNetworkSignChosenLine(SignData signData, boolean freeGatesColored, int signLineIndex) {
ChatColor highlightColor = signData.getHighlightSignColor();
ChatColor mainColor = signData.getMainSignColor();
if (freeGatesColored) {
Portal destination = PortalHandler.getByName(portal.getDestinationName(), portal.getNetwork());
boolean free = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination);
ChatColor nameColor = (free ? freeColor : highlightColor);
setLine(sign, signLineIndex, nameColor + ">" + (free ? freeColor : mainColor) +
fixColor(portal.getDestinationName()) + nameColor + "<");
setLine(signData, signLineIndex, nameColor + ">" + (free ? freeColor : mainColor) +
translateAllColorCodes(portal.getDestinationName()) + nameColor + "<");
} else {
setLine(sign, signLineIndex, highlightColor + ">" + mainColor +
fixColor(portal.getDestinationName()) + highlightColor + "<");
setLine(signData, signLineIndex, highlightColor + ">" + mainColor +
translateAllColorCodes(portal.getDestinationName()) + highlightColor + "<");
}
}
/**
* Sets a line on a sign, adding the chosen sign color
*
* @param sign <p>The sign to update</p>
* @param index <p>The index of the sign line to change</p>
* @param text <p>The new text on the sign</p>
* @param signData <p>All necessary sign information</p>
* @param index <p>The index of the sign line to change</p>
* @param text <p>The new text on the sign</p>
*/
public void setLine(Sign sign, int index, String text) {
sign.setLine(index, mainColor + text);
public void setLine(SignData signData, int index, String text) {
ChatColor mainColor = signData.getMainSignColor();
signData.getSign().setLine(index, mainColor + text);
}
/**
* Draws one network destination on one sign line
*
* @param signData <p>All necessary sign information</p>
* @param freeGatesColored <p>Whether to display free gates in a different color</p>
* @param sign <p>The sign to draw on</p>
* @param signLineIndex <p>The line to draw on</p>
* @param destinationIndex <p>The index of the destination to draw</p>
*/
private void drawNetworkSignLine(boolean freeGatesColored, Sign sign, int signLineIndex, int destinationIndex) {
private void drawNetworkSignLine(SignData signData, boolean freeGatesColored, int signLineIndex, int destinationIndex) {
ChatColor mainColor = signData.getMainSignColor();
PortalActivator destinations = portal.getPortalActivator();
String destinationName = destinations.getDestinations().get(destinationIndex);
if (freeGatesColored) {
Portal destination = PortalHandler.getByName(destinationName, portal.getNetwork());
boolean free = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination);
setLine(sign, signLineIndex, (free ? freeColor : mainColor) + fixColor(destinationName));
setLine(signData, signLineIndex, (free ? freeColor : mainColor) + translateAllColorCodes(destinationName));
} else {
setLine(sign, signLineIndex, mainColor + fixColor(destinationName));
setLine(signData, signLineIndex, mainColor + translateAllColorCodes(destinationName));
}
}
/**
* Draws the sign of a BungeeCord portal
*
* @param sign <p>The sign to re-draw</p>
* @param signData <p>All necessary sign information</p>
*/
private void drawBungeeSign(Sign sign) {
setLine(sign, 1, Stargate.getString("bungeeSign"));
setLine(sign, 2, highlightColor + ">" + mainColor + fixColor(portal.getDestinationName()) +
private void drawBungeeSign(SignData signData) {
ChatColor highlightColor = signData.getHighlightSignColor();
ChatColor mainColor = signData.getMainSignColor();
setLine(signData, 1, Stargate.getString("bungeeSign"));
setLine(signData, 2, highlightColor + ">" + mainColor + translateAllColorCodes(portal.getDestinationName()) +
highlightColor + "<");
setLine(sign, 3, highlightColor + "[" + mainColor + fixColor(portal.getNetwork()) +
setLine(signData, 3, highlightColor + "[" + mainColor + translateAllColorCodes(portal.getNetwork()) +
highlightColor + "]");
}
@ -237,43 +300,48 @@ public class PortalSignDrawer {
*
* <p>The sign for an in-active portal should display the right-click prompt and the network.</p>
*
* @param sign <p>The sign to re-draw</p>
* @param signData <p>All necessary sign information</p>
*/
private void drawInactiveSign(Sign sign) {
setLine(sign, 1, Stargate.getString("signRightClick"));
setLine(sign, 2, Stargate.getString("signToUse"));
private void drawInactiveSign(SignData signData) {
ChatColor highlightColor = signData.getHighlightSignColor();
ChatColor mainColor = signData.getMainSignColor();
setLine(signData, 1, Stargate.getString("signRightClick"));
setLine(signData, 2, Stargate.getString("signToUse"));
if (!portal.getOptions().isNoNetwork()) {
setLine(sign, 3, highlightColor + "(" + mainColor + fixColor(portal.getNetwork()) +
setLine(signData, 3, highlightColor + "(" + mainColor + translateAllColorCodes(portal.getNetwork()) +
highlightColor + ")");
} else {
setLine(sign, 3, "");
setLine(signData, 3, "");
}
}
/**
* Draws a sign pointing to a fixed location
*
* @param sign <p>The sign to re-draw</p>
* @param signData <p>All necessary sign information</p>
*/
private void drawFixedSign(Sign sign) {
private void drawFixedSign(SignData signData) {
ChatColor highlightColor = signData.getHighlightSignColor();
ChatColor mainColor = signData.getMainSignColor();
Portal destinationPortal = PortalHandler.getByName(Portal.cleanString(portal.getDestinationName()),
portal.getCleanNetwork());
String destinationName = portal.getOptions().isRandom() ? Stargate.getString("signRandom") :
(destinationPortal != null ? destinationPortal.getName() : portal.getDestinationName());
setLine(sign, 1, highlightColor + ">" + mainColor + fixColor(destinationName) + highlightColor + "<");
setLine(signData, 1, highlightColor + ">" + mainColor + translateAllColorCodes(destinationName) +
highlightColor + "<");
if (portal.getOptions().isNoNetwork()) {
setLine(sign, 2, "");
setLine(signData, 2, "");
} else {
setLine(sign, 2, highlightColor + "(" + mainColor + fixColor(portal.getNetwork()) +
highlightColor + ")");
setLine(signData, 2, highlightColor + "(" + mainColor +
translateAllColorCodes(portal.getNetwork()) + highlightColor + ")");
}
Portal destination = PortalHandler.getByName(Portal.cleanString(portal.getDestinationName()),
portal.getNetwork());
if (destination == null && !portal.getOptions().isRandom()) {
setLine(sign, 3, errorColor + Stargate.getString("signDisconnected"));
setLine(signData, 3, errorColor + Stargate.getString("signDisconnected"));
} else {
setLine(sign, 3, "");
setLine(signData, 3, "");
}
}
@ -285,7 +353,10 @@ public class PortalSignDrawer {
* @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) {
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.update();
@ -293,13 +364,33 @@ public class PortalSignDrawer {
}
/**
* Fixes coloring of signs as the & character isn't translated on all servers
* Gets the main color to use for the given sign type
*
* @param text <p>The text to fix the coloring of</p>
* @return <p>The text with the coloring fixed</p>
* @param signType <p>The sign type to get the main color for</p>
* @return <p>The main color for the given sign type</p>
*/
private String fixColor(String text) {
return ChatColor.translateAlternateColorCodes('&', text);
private ChatColor getMainColor(Material signType) {
ChatColor signColor = perSignMainColors.get(signType);
if (signColor == null) {
return mainColor;
} else {
return signColor;
}
}
/**
* Gets the highlight color to use for the given sign type
*
* @param signType <p>The sign type to get the highlight color for</p>
* @return <p>The highlight color for the given sign type</p>
*/
private ChatColor getHighlightColor(Material signType) {
ChatColor signColor = perSignHighlightColors.get(signType);
if (signColor == null) {
return highlightColor;
} else {
return signColor;
}
}
}

View File

@ -69,6 +69,15 @@ public class Gate {
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
*

View File

@ -188,16 +188,35 @@ public class GateHandler {
* @return <p>True if the gate is valid. False otherwise</p>
*/
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) {
Stargate.logSevere(String.format("Could not load Gate %s - Gates must have exactly 2 control points.",
fileName));
Stargate.logSevere(String.format(failString, "Gates must have exactly 2 control points."));
return false;
}
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;
}
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;
}

View File

@ -250,9 +250,37 @@ public abstract class Teleporter {
return chunksToLoad;
}
/**
* Checks whether a player has leashed creatures that block the teleportation
*
* @param player <p>The player trying to teleport</p>
* @return <p>False if the player has leashed any creatures that cannot go through the portal</p>
*/
public static boolean noLeashedCreaturesPreventTeleportation(Player player) {
//Find any nearby leashed entities to teleport with the player
List<Creature> nearbyCreatures = getLeashedCreatures(player);
//Disallow creatures with passengers to prevent smuggling
for (Creature creature : nearbyCreatures) {
if (!creature.getPassengers().isEmpty()) {
return false;
}
}
//If it's enabled, there is no problem
if (Stargate.getGateConfig().handleLeashedCreatures()) {
return true;
} else {
return nearbyCreatures.isEmpty();
}
}
/**
* Teleports any creatures leashed by the player
*
* <p>Will return false if the teleportation should be aborted because the player has leashed creatures that
* aren't allowed to be teleported with the player.</p>
*
* @param player <p>The player which is teleported</p>
* @param origin <p>The portal the player is teleporting from</p>
*/
@ -264,6 +292,7 @@ public abstract class Teleporter {
//Find any nearby leashed entities to teleport with the player
List<Creature> nearbyEntities = getLeashedCreatures(player);
//Teleport all creatures leashed by the player to the portal the player is to exit from
for (Creature creature : nearbyEntities) {
creature.setLeashHolder(null);
@ -280,7 +309,7 @@ public abstract class Teleporter {
* @param player <p>The player to check</p>
* @return <p>A list of all creatures the player is holding in a leash (lead)</p>
*/
protected List<Creature> getLeashedCreatures(Player player) {
protected static List<Creature> getLeashedCreatures(Player player) {
List<Creature> leashedCreatures = new ArrayList<>();
//Find any nearby leashed entities to teleport with the player
List<Entity> nearbyEntities = player.getNearbyEntities(15, 15, 15);

View File

@ -39,8 +39,7 @@ public class BlockChangeThread implements Runnable {
Block block = blockChangeRequest.getBlockLocation().getBlock();
block.setType(blockChangeRequest.getMaterial(), false);
if (blockChangeRequest.getMaterial() == Material.END_GATEWAY &&
block.getWorld().getEnvironment() == World.Environment.THE_END) {
if (blockChangeRequest.getMaterial() == Material.END_GATEWAY) {
//Force a specific location to prevent exit gateway generation
fixEndGatewayGate(block);
} else if (blockChangeRequest.getAxis() != null) {
@ -56,8 +55,11 @@ public class BlockChangeThread implements Runnable {
*/
private static void fixEndGatewayGate(Block block) {
EndGateway gateway = (EndGateway) block.getState();
gateway.setExitLocation(block.getLocation());
gateway.setExactTeleport(true);
gateway.setAge(Long.MIN_VALUE);
if (block.getWorld().getEnvironment() == World.Environment.THE_END) {
gateway.setExitLocation(block.getLocation());
gateway.setExactTeleport(true);
}
gateway.update(false, false);
}

View File

@ -4,7 +4,7 @@ import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter;
import org.bukkit.ChatColor;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerMoveEvent;

View File

@ -0,0 +1,47 @@
package net.knarcraft.stargate.utility;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.Color;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ColorHelper {
/**
* Inverts the given color
*
* @param color <p>The color to invert</p>
* @return <p>The inverted color</p>
*/
public static Color invert(Color color) {
return color.setRed(255 - color.getRed()).setGreen(255 - color.getGreen()).setBlue(255 - color.getBlue());
}
/**
* Gets the chat color corresponding to the given color
*
* @param color <p>The color to convert into a chat color</p>
* @return <p>The resulting chat color</p>
*/
public static ChatColor fromColor(Color color) {
return ChatColor.of(String.format("#%02X%02X%02X", color.getRed(), color.getGreen(), color.getBlue()));
}
/**
* Translates all found color codes to formatting in a string
*
* @param message <p>The string to search for color codes</p>
* @return <p>The message with color codes translated</p>
*/
public static String translateAllColorCodes(String message) {
message = ChatColor.translateAlternateColorCodes('&', message);
Pattern pattern = Pattern.compile("(#[a-fA-F0-9]{6})");
Matcher matcher = pattern.matcher(message);
while (matcher.find()) {
message = message.replace(matcher.group(), "" + ChatColor.of(matcher.group()));
}
return message;
}
}

View File

@ -113,16 +113,21 @@ public final class DirectionHelper {
* @return <p>A normal vector</p>
*/
public static Vector getCoordinateVectorFromRelativeVector(double right, double down, double out, double yaw) {
Vector distanceVector = DirectionHelper.getDirectionVectorFromYaw(yaw);
distanceVector.multiply(out);
Vector rightVector = DirectionHelper.getDirectionVectorFromYaw(yaw - 90);
rightVector.multiply(right);
Vector depthVector = new Vector(0, -1, 0);
depthVector.multiply(down);
return distanceVector.add(rightVector).add(depthVector);
if (yaw == 0) {
//South
return new Vector(right, -down, out);
} else if (yaw == 90) {
//West
return new Vector(-out, -down, right);
} else if (yaw == 180) {
//North
return new Vector(-right, -down, -out);
} else if (yaw == 270) {
//East
return new Vector(out, -down, -right);
} else {
throw new IllegalArgumentException(String.format("Invalid yaw %f given", yaw));
}
}
/**

View File

@ -1,8 +1,11 @@
package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.EconomyConfig;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.property.PortalOwner;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
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));
}
if (entrancePortal.getGate().getToOwner() && ownerUUID != null) {
success = Stargate.getEconomyConfig().chargePlayerIfNecessary(player, ownerUUID, cost);
success = chargePlayerIfNecessary(player, ownerUUID, cost);
} else {
success = Stargate.getEconomyConfig().chargePlayerIfNecessary(player, cost);
success = chargePlayerIfNecessary(player, cost);
}
//Send the insufficient funds message
@ -118,6 +121,116 @@ public final class EconomyHelper {
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
*

View File

@ -1,6 +1,6 @@
package net.knarcraft.stargate.utility;
import org.bukkit.ChatColor;
import net.md_5.bungee.api.ChatColor;
import java.io.BufferedReader;
import java.io.BufferedWriter;

View File

@ -243,7 +243,7 @@ public final class PermissionHelper {
return true;
}
//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();
}
/**
@ -407,7 +407,7 @@ public final class PermissionHelper {
}
//Player cannot pay for teleportation
int cost = Stargate.getEconomyConfig().getUseCost(player, entrancePortal, destination);
int cost = EconomyHelper.getUseCost(player, entrancePortal, destination);
if (cost > 0) {
return EconomyHelper.cannotPayTeleportFee(entrancePortal, player, cost);
}

View File

@ -0,0 +1,87 @@
package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.Stargate;
import org.bukkit.scheduler.BukkitScheduler;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.logging.Level;
/**
* The update checker is responsible for looking for new updates
*/
public final class UpdateChecker {
private final static String APIResourceURL = "https://api.spigotmc.org/legacy/update.php?resource=97784";
private final static String updateNotice = "A new update is available: %s (You are still on %s)";
private UpdateChecker() {
}
/**
* Checks if there's a new update available, and alerts the user if necessary
*/
public static void checkForUpdate() {
BukkitScheduler scheduler = Stargate.getInstance().getServer().getScheduler();
scheduler.runTaskAsynchronously(Stargate.getInstance(), UpdateChecker::queryAPI);
}
/**
* Queries the spigot API to check for a newer version, and informs the user
*/
private static void queryAPI() {
try {
InputStream inputStream = new URL(APIResourceURL).openStream();
BufferedReader reader = FileHelper.getBufferedReaderFromInputStream(inputStream);
//There should only be one line of output
String newVersion = reader.readLine();
reader.close();
String oldVersion = Stargate.getPluginVersion();
//If there is a newer version, notify the user
if (isVersionHigher(oldVersion, newVersion)) {
Stargate.getConsoleLogger().log(Level.INFO, Stargate.getBackupString("prefix") +
getUpdateAvailableString(newVersion, oldVersion));
Stargate.setUpdateAvailable(newVersion);
}
} catch (IOException e) {
Stargate.debug("UpdateChecker", "Unable to get newest version.");
}
}
/**
* Gets the string to display to a user to alert about a new update
*
* @param newVersion <p>The new available plugin version</p>
* @param oldVersion <p>The old (current) plugin version</p>
* @return <p>The string to display</p>
*/
public static String getUpdateAvailableString(String newVersion, String oldVersion) {
return String.format(updateNotice, newVersion, oldVersion);
}
/**
* Decides whether one version number is higher than another
*
* @param oldVersion <p>The old version to check</p>
* @param newVersion <p>The new version to check</p>
* @return <p>True if the new version is higher than the old one</p>
*/
public static boolean isVersionHigher(String oldVersion, String newVersion) {
String[] oldVersionParts = oldVersion.split("\\.");
String[] newVersionParts = newVersion.split("\\.");
int versionLength = Math.max(oldVersionParts.length, newVersionParts.length);
for (int i = 0; i < versionLength; i++) {
int oldVersionNumber = oldVersionParts.length > i ? Integer.parseInt(oldVersionParts[i]) : 0;
int newVersionNumber = newVersionParts.length > i ? Integer.parseInt(newVersionParts[i]) : 0;
if (newVersionNumber != oldVersionNumber) {
return newVersionNumber > oldVersionNumber;
}
}
return false;
}
}

View File

@ -1,72 +1,84 @@
# stargate Configuration File
# Main stargate config
# I----------I----------I #
# portalFolder - The folder for storing portals
# gateFolder - The folder for storing gate layouts
# defaultGateNetwork - The default gate network
# destroyedByExplosion - Whether to destroy gates with explosions (Creeper, TNT, etc.)
# maxGatesEachNetwork - The maximum number of gates allowed on a network - 0 for unlimited
# language - The language file to load for messages
# rememberDestination - Whether to remember the cursor location between uses
# handleVehicles - Whether to allow vehicles through gates. This overrides other vehicle settings
# handleEmptyVehicles - Whether to allow empty vehicles through gates (chest/hopper/tnt/furnace minecarts included)
# handleCreatureTransportation - Whether to allow players to transport creatures by sending vehicles (minecarts, boats) through gates
# handleNonPlayerVehicles - Whether to allow vehicles with a passenger which is not a player through gates. handleCreatureTransportation must be enabled
# handleLeashedCreatures - Whether to allow creatures lead by a player to teleport with the player
# sortNetworkDestinations - Whether to sort network lists alphabetically
# protectEntrance - Whether to protect gate entrance material (More resource intensive. Only enable if using destroyable open/closed material)
# mainSignColor - The color used for drawing signs (Default: BLACK).
# highlightSignColor - The color used for sign markings (Default: WHITE)
# verifyPortals - Whether all the non-sign blocks are checked to match the gate layout when a stargate is loaded.
# I------------I-------------I #
# stargate economy options #
# I------------I-------------I #
# useEconomy - Whether to use an economy plugin
# createCost - The cost to create a gate
# destroyCost - The cost to destroy a gate
# useCost - The cost to use a gate
# 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
# 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 #
# Debug options #
# I-------I-------I #
# debug - Debug -- Only enable if you have issues, massive console output
# permissionDebug - This will output any and all Permissions checks to console, used for permissions debugging (Requires debug: true)
# language - The language file to load for messages
language: en
# adminUpdateAlert - Whether to alert admins about new plugin updates
adminUpdateAlert: true
folders:
# portalFolder - The folder for storing portals
portalFolder: plugins/Stargate/portals/
# gateFolder - The folder for storing gate layouts
gateFolder: plugins/Stargate/gates/
gates:
# maxGatesEachNetwork - The maximum number of gates allowed on a network - 0 for unlimited
maxGatesEachNetwork: 0
# defaultGateNetwork - The default gate network
defaultGateNetwork: central
cosmetic:
# rememberDestination - Whether to remember the cursor location between uses
rememberDestination: false
# sortNetworkDestinations - Whether to sort network lists alphabetically
sortNetworkDestinations: false
# mainSignColor - The color used for drawing signs (Default: BLACK).
mainSignColor: BLACK
# highlightSignColor - The color used for sign markings (Default: WHITE)
highlightSignColor: WHITE
perSignColors:
- 'ACACIA:default,default'
- 'BIRCH:default,default'
- 'CRIMSON:inverted,inverted'
- 'DARK_OAK:inverted,inverted'
- 'JUNGLE:default,default'
- 'OAK:default,default'
- 'SPRUCE:inverted,inverted'
- 'WARPED:inverted,inverted'
integrity:
# destroyedByExplosion - Whether to destroy gates with explosions (Creeper, TNT, etc.)
destroyedByExplosion: false
# verifyPortals - Whether all the non-sign blocks are checked to match the gate layout when a stargate is loaded.
verifyPortals: false
# protectEntrance - Whether to protect gate entrance material (More resource intensive. Only enable if using destroyable open/closed material)
protectEntrance: false
functionality:
enableBungee: false
# handleVehicles - Whether to allow vehicles through gates. This overrides other vehicle settings
handleVehicles: true
# handleEmptyVehicles - Whether to allow empty vehicles through gates (chest/hopper/tnt/furnace minecarts included)
handleEmptyVehicles: true
# handleCreatureTransportation - Whether to allow players to transport creatures by sending vehicles (minecarts, boats) through gates
handleCreatureTransportation: true
# handleNonPlayerVehicles - Whether to allow vehicles with a passenger which is not a player through gates. handleCreatureTransportation must be enabled
handleNonPlayerVehicles: true
# handleLeashedCreatures - Whether to allow creatures lead by a player to teleport with the player
handleLeashedCreatures: true
# I------------I-------------I #
# stargate economy options #
# I------------I-------------I #
economy:
# useEconomy - Whether to use an economy plugin
useEconomy: false
# createCost - The cost to create a gate
createCost: 0
# destroyCost - The cost to destroy a gate
destroyCost: 0
# useCost - The cost to use a gate
useCost: 0
# toOwner - Whether the charge for using a gate goes to the gate's owner
toOwner: false
# chargeFreeDestination - Whether a gate whose destination is a free gate is still charged
chargeFreeDestination: true
# freeGatesColored - Whether a free gate in the destination list is marked with a color
freeGatesColored: false
# freeGatesColor - The color to use for marking free gates
freeGatesColor: DARK_GREEN
# I-------I-------I #
# Debug options #
# I-------I-------I #
debugging:
# debug - Debug -- Only enable if you have issues, massive console output
debug: false
# permissionDebug - This will output any and all Permissions checks to console, used for permissions debugging (Requires debug: true)
permissionDebug: false

View File

@ -1,18 +1,18 @@
name: Stargate
main: net.knarcraft.stargate.Stargate
version: 0.9.2.0
version: 0.9.3.0
description: Stargate mod for Bukkit Revived
author: EpicKnarvik97
authors: [ Drakia, PseudoKnight, EpicKnarvik97 ]
website: https://git.knarcraft.net/EpicKnarvik97/Stargate
api-version: 1.17
api-version: 1.18
softdepend: [ Vault ]
commands:
stargate:
aliases:
- sg
description: Used to see stargate info
usage: /<command> <reload/about> - Used to see stargate info or reload the plugin
description: Used to see stargate info, reloading and editing config values
usage: /<command> <reload/about/config> - Used to see stargate info, reload the plugin or change config values
permissions:
stargate.*:
description: Wildcard permission which gives all Stargate permissions
@ -141,6 +141,9 @@ permissions:
stargate.admin.config:
description: Allows the player to change config values from the chat
default: false
stargate.admin.dye:
description: Allows this player to change the dye of any stargate's sign
default: false
stargate.server:
description: Allows the creation of a BungeeCord stargate going to any server
default: false
@ -152,4 +155,5 @@ permissions:
stargate.admin.hidden: true
stargate.admin.private: true
stargate.admin.bungee: true
stargate.admin.config: true
stargate.admin.config: true
stargate.admin.dye: true

View File

@ -32,6 +32,7 @@ public class GateLayoutTest {
@AfterAll
public static void tearDown() {
MockBukkit.getMock().getPluginManager().disablePlugins();
MockBukkit.unmock();
}