73 Commits

Author SHA1 Message Date
445638a561 Releases a small hotfix for sign color as version 0.9.2.3 2021-11-25 04:27:36 +01:00
7f9dc6756b Updates version to 0.9.2.2 2021-11-25 03:58:42 +01:00
b2bb995d7e Prevents teleportation of a leashed creature with a passenger 2021-11-25 03:54:09 +01:00
f92fd2de5d Prevents loading of gate files using non-blocks as part of the border 2021-11-25 03:39:15 +01:00
2ed0fe7817 Updates README with recent changes 2021-11-25 03:26:12 +01:00
27b964837f Fixes a potential exception when a portal with an invalid gate type is missing a sign 2021-11-25 03:25:58 +01:00
4b34ea3cf5 Fixes a potential exception when a gate's open-block or closed-block is not a block 2021-11-25 03:25:22 +01:00
0740cd0a66 Removes the error message displayed when teleportation is cancelled because handleLeashedCreatures is disabled
The message should be removed as it's inconsistent with how disabled vehicle teleportation is silent
2021-11-25 02:02:20 +01:00
bab51d76fd Prevents teleportation of players holding one or more creatures on a leash if handleLeashedCreatures is disabled 2021-11-25 01:53:47 +01:00
6ddc15eeef Merge branch 'config-reloading' into dev 2021-11-24 22:39:15 +01:00
14511f558d Updates readme and version to 0.9.2.1
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-24 22:38:44 +01:00
32975ca35d Rewrites a lot of the config command to only do the minimum necessary steps to load the changes
Adds a ConfigTag class for helping to decide the action necessary for updating a given config option
Splits the color setting in PortalSignDrawer as only one color is set at a time when the /config command is used
Updates the configOptions map when a config option is changed
2021-11-24 22:33:45 +01:00
6e7ac5dbb9 Makes the protectEntrance option protect the entrance from all block placement 2021-11-24 22:20:47 +01:00
2b4d15dab4 Adds some boldness to the description and fixes an inaccuracy
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-24 03:06:35 +01:00
22bb75d4df Moves some methods from EconomyConfig to EconomyHelper and tries to simplify EconomyConfig
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-23 07:20:48 +01:00
ab9a118d49 Prevents an empty deny reason from being displayed
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-22 22:01:43 +01:00
a80a8520ce Improves the description of the /sg command 2021-11-22 17:58:56 +01:00
48bb68d665 Adds a missing 'a' in a sentence
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-21 13:34:52 +01:00
1247c54899 Fixes some wrong migration information 2021-11-21 13:10:13 +01:00
37ac3d4877 Fixes a debug route
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-15 17:25:03 +01:00
70495220eb Simplifies some function calls
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-15 17:18:00 +01:00
10c3914a60 Makes the free gate color configurable 2021-11-15 00:35:28 +01:00
4699f717ec Ignores color codes and case when sorting destination names
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-14 14:35:45 +01:00
29c1a00fcd Makes the max portal name and network character limit more easily changeable 2021-11-13 19:28:17 +01:00
51f5420f9e Removes the replacement of spaces to underscores for the cleanString method
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-13 17:04:13 +01:00
e1a3d2d560 Makes a fixed sign always use the destination portal's actual name if possible 2021-11-13 17:02:13 +01:00
a84210d550 Fixes a couple of bugs which prevented portals using spaces in the name from being properly connected 2021-11-13 03:44:27 +01:00
351d1762e7 Updates changelog, and updates version to 0.9.2.0
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-12 15:50:32 +01:00
2c53b7d2a6 Makes portal names and networks case and color-insensitive and increases length limit to 13. #17
Ignores &[0-9a-f] color codes when counting towards the name and network string limits
Makes portal lists store cleaned portal and network names to ignore case and color
Names and networks will now match regardless of case and color
Increases portal name/network limit to 13 characters
2021-11-12 15:33:15 +01:00
42e02eb141 Makes the UUIDMigrationHelper final 2021-11-12 13:46:01 +01:00
ad310ddb9c Allows a sneaking player to see information about a silent stargate (0.9.1.2)
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-10 22:54:20 +01:00
3db630f60e Updates version and changelog
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-09 22:51:11 +01:00
7a03f49fb1 Translates the & character to make sure portal signs are colored on all servers 2021-11-09 22:47:38 +01:00
1c2cad2ec1 Updates version to 0.9.1.0, updates README and adds a permission for changing config values
Adds the stargate.admin.config permission, which is required to use /sg config
2021-11-09 21:16:53 +01:00
b4d908eaa0 Improves tab completion for Stargate commands by taking into account typed text
Sends tab completion for the config command to the config tab completer
2021-11-09 20:58:55 +01:00
8546fd4f78 Fully implements the config command 2021-11-09 20:57:06 +01:00
05328fc456 Adds a tab completer for the config sub-command 2021-11-09 20:56:43 +01:00
aba70b669e Adds a method to be able to read config options 2021-11-09 18:21:25 +01:00
d5f4b87e9b Changes how config values are loaded by using the ConfigOption class 2021-11-09 15:40:10 +01:00
85edaa4657 Adds a new class to represent a data type usable by configs 2021-11-09 15:38:42 +01:00
7c501cefe8 Gives all config options data types to make loading config values work properly 2021-11-09 15:38:10 +01:00
6466c7b0ff Adds the config command to the stargate auto completer
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
Additionally makes the reload command only auto-complete if the command sender can use it
2021-11-09 02:04:59 +01:00
37cf75ada1 Adds the config command as a child to the Stargate command 2021-11-09 02:01:58 +01:00
1ca2d36f5f Adds an unfinished implementation of the config command, which is only able to display config options for now 2021-11-09 02:01:11 +01:00
01b2907b01 Adds an enum containing information about all config options 2021-11-09 01:59:54 +01:00
94b9848b70 Updates version and README
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-08 15:17:29 +01:00
2a17714e8d Makes sure to only remove buttons from always-on portals if the block is a type of button 2021-11-08 15:16:51 +01:00
901f9c555c Prevents the sign location of a portal with no sing from being added to lookup blocks and controls 2021-11-08 15:15:58 +01:00
1efd89cdb0 Makes sure to not display portal information when placing a block 2021-11-08 15:14:21 +01:00
88bb02dfbd Adds translation for portal information shown when right-clicking
Adds a distinction between network and server when displaying portal information
Adds translated portal info strings for english and both flavors of Norwegian
2021-11-08 14:16:44 +01:00
4db6274dc3 Fixes underwater signs and buttons being replaced with AIR instead of water 2021-11-08 01:34:18 +01:00
9c963c9e8c Renames Portal to Stargate when displaying information about a clicked portal
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-07 14:02:33 +01:00
fc744b04dc Adds an option for a stargate without a sign #10 2021-11-07 13:41:19 +01:00
1565707809 De-activates an unregistered portal to prevent its sign to be re-drawn if destroyed while activated 2021-11-07 13:40:12 +01:00
527562bc60 Fixes code formatting 2021-11-07 04:29:25 +01:00
42e208402e Documents stargates using several border materials 2021-11-07 04:27:39 +01:00
7f91808baf Adds a new default stargate to display the possibility of using several border materials 2021-11-07 04:26:23 +01:00
0540498818 Moves the drawing of unregistered signs to the portal sign drawer 2021-11-07 04:04:14 +01:00
57ec7071cf Updates README changelog 2021-11-06 18:12:47 +01:00
5f2d7988e2 Fixes button updating
Fixes a bug causing signs to be removed
Makes the old button properly disappear
Saves the portal database(s) to store the new button location if necessary
2021-11-06 18:08:01 +01:00
ac25f2747f Adds String.format to some debug strings 2021-11-06 18:06:00 +01:00
aa3bb58b33 Fixes some bugs regarding sign drawing and button updating
Fixes a bug displaying a portal as usable even if it's been unregistered
Fixes a bug which causes the portal button to be re-generated, even if the portal has been unregistered
2021-11-06 15:33:06 +01:00
ee0e66e9be Fixes the order in which the portal's button is updated to fix one of the bugs in #15
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-06 14:49:56 +01:00
f90a09143f Makes sure to also clear bungee portals when clearing portals 2021-11-06 04:10:15 +01:00
8c4cf16375 Adds an option for silent stargates which don't print teleportation messages or errors to the player's chat #7 2021-11-05 23:39:18 +01:00
4566c15350 Updates version to 0.9.0.6 and updates README 2021-11-05 21:43:38 +01:00
0297d62d6d Sets the always on option to true for bungee portals and removes some unnecessary checks 2021-11-05 21:40:06 +01:00
80ff241d4b Makes stargates' buttons update when portals are loaded #14 2021-11-05 21:38:33 +01:00
f3292cff99 Makes containers used as buttons no longer open when right-clicked 2021-11-05 19:21:27 +01:00
8c37b11484 Increases the delay before setting the leash holder for teleported creatures as they sometimes got stuck
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-05 14:04:24 +01:00
e0ac9b41e7 Adds some sub-packages to the portal package to improve logical structure
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-04 00:07:03 +01:00
e5c1ad1f3a 0.9.0.5 - Adds three new options to disable features of vehicle teleportation with more granularity #9
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-03 15:55:56 +01:00
cab99e11b0 Adds leashed teleportation as a feature to the README
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2021-11-01 19:25:52 +01:00
51 changed files with 2102 additions and 566 deletions

137
README.md
View File

@ -3,16 +3,18 @@
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
- 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)
- **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
## Background
@ -34,10 +36,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
@ -58,7 +58,9 @@ stargate.option -- Allow use of all options
stargate.option.backwards -- Allow use of 'B'ackwards
stargate.option.show -- Allow use of 'S'how
stargate.option.nonetwork -- Allow use of 'N'oNetwork
stargate.option.random -- Allow use of 'Random' stargates
stargate.option.random -- Allow use of 'R'andom stargates
stargate.option.silent -- Allow use of S'i'lent stargates
stargate.option.nosign -- Allow use of 'E' (No sign)
stargate.create -- Allow creating Stargates on any network (Override all create permissions)
stargate.create.personal -- Allow creating Stargates on network {playername}
@ -77,11 +79,12 @@ stargate.free -- Allow free use/creation/destruction of Stargates
stargate.free.create -- Allow free creation of Stargates
stargate.free.destroy -- Allow free destruction of Stargates
stargate.admin -- Allow all admin features (Hidden/Private only so far)
stargate.admin -- Allow all admin features (Hidden/Private bypass, BungeeCord, Reload, Config)
stargate.admin.private -- Allow use of Private gates not owned by user
stargate.admin.hidden -- Allow access to Hidden gates not ownerd by user
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
```
## Default Permissions
@ -114,9 +117,9 @@ section). See the Custom Gate Layout section to learn how to add custom gates.
### Sign Layout:
- Line 1: Gate Name (Max 11 characters)
- Line 2: Destination Name \[Optional] (Max 11 characters, used for fixed-gates only)
- Line 3: Network name \[Optional] (Max 11 characters)
- Line 1: Gate Name (Max 13 characters)
- Line 2: Destination Name \[Optional] (Max 13 characters, used for fixed-gates only)
- Line 3: Network name \[Optional] (Max 13 characters)
- Line 4: Options \[Optional] :
- 'A' for always-on fixed gate
- 'H' for hidden networked gate
@ -126,10 +129,14 @@ section). See the Custom Gate Layout section to learn how to add custom gates.
- 'S' is for showing an always-on gate in the network list
- 'N' is for hiding the network name
- 'R' is for random gates. These follow standard permissions of gates, but have a random exit location every time a
player enters.
- 'U' is for a gate connecting to another through bungee
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 a gate without a sign. Only for fixed stargates
The options are the single letter, not the word. So to make a private hidden gate, your 4th line would be 'PH'.
The options are the single letter, not the word. So to make a private hidden gate, your 4th line would be 'PH'. The
&\[0-9a-f] color codes are not counted in the character limit, thus allowing a 13-character name with an additional 2
characters used for the color code.
#### Gate networks:
@ -199,7 +206,11 @@ The key `button` is used to define the type of button that is generated for this
a type of wall coral (dead or alive), a type of shulker box or a chest.
`X` and `-` are used to define block types for the layout (Any single-character can be used, such as `#`).
In the gate format, you can see we use `X` to show where obsidian must be, `-` where the controls (Button/sign) are.
In the gate format, you can see we use `X` to show where obsidian must be, `-` where the controls (Button/sign) are.
For more complex gate designs, it is possible to add more materials. If you add something like a=GLOWSTONE, `a` can then
be used in the gate layout, just as `X` is used. See the `squarenetherglowstonegate.gate` file for an example.
You will also notice a `*` in the gate layout, this is the "exit point" of the gate, the block at which the player will
teleport in front of.
@ -301,6 +312,9 @@ gates:
functionality:
enableBungee - Enable this for BungeeCord support. This allows portals across Bungee servers.
handleVehicles - Whether or not to handle vehicles going through gates. Set to false to disallow vehicles (Manned or not) going through gates.
handleEmptyVehicles - Whether or not to handle empty vehicles going through gates (chest/hopper/tnt/furnace minecarts included).
handleCreatureTransportation - Whether or not to handle players that transport creatures by sending vehicles (minecarts, boats) through gates.
handleNonPlayerVehicles - Whether or not to handle vehicles with a passenger which is not a player going through gates (pigs, horses, villagers, creepers, etc.). handleCreatureTransportation must be enabled.
handleLeashedCreatures - Whether or not to handle creatures leashed by a player going through gates. Set to false to disallow leashed creatures going through gates.
economy:
useEconomy - Whether or not to enable Economy using Vault (must have the Vault plugin)
@ -309,7 +323,8 @@ economy:
useCost - The cost to use a stargate
toOwner - Whether the money from gate-use goes to the owner or nobody
chargeFreeDestination - Enable to make players pay for teleportation even if the destination is free
freeGatesGreen - Enable to make gates that won't cost the player money show up as green
freeGatesColored - Enable to make gates that won't cost the player money show up as green
freeGatesColor - This allows you to specify the color of the markings and name of free stargates
debugging:
debug - Whether to show massive debug output
permissionDebug - Whether to show massive permission debug output
@ -364,10 +379,84 @@ bungeeDisabled=BungeeCord support is disabled.
bungeeDeny=You do not have permission to create BungeeCord gates.
bungeeEmpty=BungeeCord gates require both a destination and network.
bungeeSign=Teleport to
portalInfoTitle=[STARGATE INFO]
portalInfoName=Name: %name%
portalInfoDestination=Destination: %destination%
portalInfoNetwork=Network: %network%
portalInfoServer=Server: %server%
```
# Changes
#### \[Version 0.9.2.3] EpicKnarvik97 fork
- Fixes a typo which caused both colors to change into the highlightSignColor
#### \[Version 0.9.2.2] EpicKnarvik97 fork
- Prevents teleportation of a player holding creatures on a leash when handleLeashedCreatures is disabled, to prevent
players accidentally losing the creatures during teleportation
- Fixes a potential exception when a gate's open-block or closed-block is set to a material which isn't a block
- Fixes a potential exception when a portal without a sign has an invalid gate type
- Prevents loading of gate files using non-blocks as part of the border
- Prevents a player smuggling another player through a restricted stargate by sitting on a creature held in a lead by
the first player
#### \[Version 0.9.2.1] EpicKnarvik97 fork
- Makes sure to only reload whatever is necessary when config values are changed using commands, instead of reloading
the entire config file every time
- Protects portals from block placement when protectEntrance is enabled
#### \[Version 0.9.2.0] EpicKnarvik97 fork
- Increases max length of names and networks to 13 characters
- Excludes color codes from the counted character length to allow a colored, 13-character name
- Makes portal names and networks case- and color-agnostic to prevent some confusion caused by typos or sloppy
configuration
- Makes the free gate color configurable, and renames freeGatesGreen to freeGatesColored
#### \[Version 0.9.1.2] EpicKnarvik97 fork
- Allows a sneaking player to see information about a silent stargate with no sign
#### \[Version 0.9.1.1] EpicKnarvik97 fork
- Makes sure to translate the `&` character to fix a bug causing portal signs to not be colored on some servers
#### \[Version 0.9.1.0] EpicKnarvik97 fork
- Rewrites config loading as a part of the changes required to implement config commands
- This update adds commands to change all config values from the chat or the console, complete with tab completion
- Adds a new permission "stargate.admin.config" which is required to edit config values from the chat
#### \[Version 0.9.0.7] EpicKnarvik97 fork
- Stops registering the sign as a lookup block for stargates without a sign
- Only removes a stargate's button if it's actually a button-compatible block
- Only displays portal info if not placing a block
#### \[Version 0.9.0.6] EpicKnarvik97 fork
- Makes containers no longer open when used as buttons
- Validates and updates stargate buttons when the plugin is loaded or reloaded
- Adds an option to make a stargate silent (no text in chat when teleporting) for better immersion on RP servers
- Makes buttons update and/or remove themselves when their location or material changes
- Adds another default gate to show that it's possible to use any number of materials for a stargate's border
- Adds an option for stargates without a sign. Right-clicking such a stargate will display gate information
- Fixes a bug causing signs to be re-drawn after they're broken
- Makes buttons and signs be replaced by water instead of air when underwater
- Makes portal info shown when right-clicking a stargate fully customizable
#### \[Version 0.9.0.5] EpicKnarvik97 fork
- Adds an option to stargate functionality to disable all teleportation of creatures
- Adds an option to stargate functionality to disable all teleportation of empty minecarts
- Adds an option to stargate functionality to disable teleportation of creatures if no player is present in the vehicle
- Prevents a player in a vehicle from teleporting without the vehicle if vehicle teleportation is disabled
- Prevents an infinite number of teleportation messages if vehicle teleportation is detected but denied
#### \[Version 0.9.0.4] EpicKnarvik97 fork
- Adds teleportation of leashed creatures. By default, any creature connected to a player by a lead will be teleported

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,42 +1,42 @@
package net.knarcraft.stargate.config;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.Gate;
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.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.ServicesManager;
import java.util.UUID;
import java.util.Map;
/**
* The economy config keeps track of economy config values and performs economy actions such as payment for using a gate
*/
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 freeGatesGreen = false;
private final Map<ConfigOption, Object> configOptions;
/**
* Instantiates a new economy config
*
* @param newConfig <p>The file configuration to read values from</p>
* @param configOptions <p>The loaded config options to read</p>
*/
public EconomyConfig(FileConfiguration newConfig) {
loadEconomyConfig(newConfig);
public EconomyConfig(Map<ConfigOption, Object> configOptions) {
this.configOptions = configOptions;
try {
String freeColor = (String) configOptions.get(ConfigOption.FREE_GATES_COLOR);
PortalSignDrawer.setFreeColor(ChatColor.valueOf(freeColor.toUpperCase()));
} catch (IllegalArgumentException | NullPointerException ignored) {
PortalSignDrawer.setFreeColor(ChatColor.DARK_GREEN);
}
}
/**
@ -45,7 +45,7 @@ public final class EconomyConfig {
* @return <p>The gate use cost</p>
*/
public int getDefaultUseCost() {
return useCost;
return (Integer) configOptions.get(ConfigOption.USE_COST);
}
/**
@ -54,7 +54,7 @@ public final class EconomyConfig {
* @return <p>Whether economy is enabled</p>
*/
public boolean isEconomyEnabled() {
return economyEnabled;
return (boolean) configOptions.get(ConfigOption.USE_ECONOMY);
}
/**
@ -84,12 +84,12 @@ public final class EconomyConfig {
}
/**
* Gets whether free portals should be marked with green coloring
* Gets whether free portals should be marked with a different coloring
*
* @return <p>Whether free portals should be green</p>
* @return <p>Whether free portals should be colored</p>
*/
public boolean drawFreePortalsGreen() {
return freeGatesGreen;
public boolean drawFreePortalsColored() {
return (boolean) configOptions.get(ConfigOption.FREE_GATES_COLORED);
}
/**
@ -101,8 +101,8 @@ public final class EconomyConfig {
*
* @return <p>Whether to charge for free destinations</p>
*/
public boolean chargeFreeDestination() {
return chargeFreeDestination;
public boolean freeIfFreeDestination() {
return !((boolean) configOptions.get(ConfigOption.CHARGE_FREE_DESTINATION));
}
/**
@ -111,21 +111,7 @@ public final class EconomyConfig {
* @return <p>Whether to send payments to the portal owner</p>
*/
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);
}
/**
@ -134,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);
}
/**
@ -154,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);
}
/**
@ -192,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
*
@ -215,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 "";
@ -229,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
@ -247,7 +182,7 @@ public final class EconomyConfig {
} else {
Stargate.logInfo(Stargate.getString("vaultLoadError"));
}
economyEnabled = false;
configOptions.put(ConfigOption.USE_ECONOMY, false);
return false;
}
@ -257,46 +192,7 @@ public final class EconomyConfig {
* @return <p>True if the user has turned on economy and economy is available</p>
*/
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;
}
/**
@ -329,21 +225,6 @@ public final class EconomyConfig {
}
}
/**
* Loads all config values related to economy
*
* @param newConfig <p>The configuration containing the values to read</p>
*/
private void loadEconomyConfig(FileConfiguration newConfig) {
economyEnabled = newConfig.getBoolean("economy.useEconomy");
setDefaultCreateCost(newConfig.getInt("economy.createCost"));
setDefaultDestroyCost(newConfig.getInt("economy.destroyCost"));
setDefaultUseCost(newConfig.getInt("economy.useCost"));
toOwner = newConfig.getBoolean("economy.toOwner");
chargeFreeDestination = newConfig.getBoolean("economy.chargeFreeDestination");
freeGatesGreen = newConfig.getBoolean("economy.freeGatesGreen");
}
/**
* Determines if a player can do a gate action for free
*
@ -355,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

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

View File

@ -3,10 +3,10 @@ package net.knarcraft.stargate.config;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.BlockChangeRequest;
import net.knarcraft.stargate.listener.BungeeCordListener;
import net.knarcraft.stargate.portal.GateHandler;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.PortalRegistry;
import net.knarcraft.stargate.portal.property.gate.GateHandler;
import net.knarcraft.stargate.thread.BlockChangeThread;
import net.knarcraft.stargate.utility.FileHelper;
import net.knarcraft.stargate.utility.PortalFileHelper;
@ -18,6 +18,7 @@ import org.bukkit.plugin.messaging.Messenger;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Queue;
@ -45,8 +46,7 @@ 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;
/**
* Instantiates a new stargate config
@ -55,6 +55,7 @@ public final class StargateConfig {
*/
public StargateConfig(Logger logger) {
this.logger = logger;
configOptions = new HashMap<>();
dataFolderPath = Stargate.getInstance().getDataFolder().getPath().replaceAll("\\\\", "/");
portalFolder = dataFolderPath + "/portals/";
@ -62,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
*/
@ -78,7 +91,7 @@ public final class StargateConfig {
languageLoader.reload();
messageSender = new MessageSender(languageLoader);
if (debuggingEnabled) {
if (isDebuggingEnabled()) {
languageLoader.debug();
}
@ -90,6 +103,15 @@ public final class StargateConfig {
setupVaultEconomy();
}
/**
* Gets a copy of all loaded config options with its values
*
* @return <p>The loaded config options</p>
*/
public Map<ConfigOption, Object> getConfigOptions() {
return new HashMap<>(configOptions);
}
/**
* Gets the queue of open portals
*
@ -118,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);
}
/**
@ -127,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);
}
/**
@ -174,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();
@ -189,9 +222,6 @@ public final class StargateConfig {
//Clear all loaded portals
PortalRegistry.clearPortals();
//Clear all loaded gates
GateHandler.clearGates();
}
/**
@ -244,7 +274,7 @@ public final class StargateConfig {
//Update the language loader in case the loaded language changed
languageLoader.setChosenLanguage(languageName);
languageLoader.reload();
if (debuggingEnabled) {
if (isDebuggingEnabled()) {
languageLoader.debug();
}
@ -255,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";
@ -271,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();
@ -297,9 +327,7 @@ public final class StargateConfig {
FileConfiguration newConfig = Stargate.getInstance().getConfig();
boolean isMigrating = false;
if (newConfig.getString("lang") != null ||
newConfig.getString("gates.integrity.ignoreEntrance") != null ||
newConfig.getString("ignoreEntrance") != null) {
if (newConfig.getString("lang") != null || newConfig.getString("economy.freeGatesGreen") != null) {
migrateConfig(newConfig);
isMigrating = true;
}
@ -307,16 +335,30 @@ public final class StargateConfig {
//Copy missing default values if any values are missing
newConfig.options().copyDefaults(true);
//Load all options
for (ConfigOption option : ConfigOption.values()) {
Object optionValue;
String configNode = option.getConfigNode();
//Load the option using its correct data type
switch (option.getDataType()) {
case STRING -> {
String value = newConfig.getString(configNode);
optionValue = value != null ? value.trim() : "";
}
case BOOLEAN -> optionValue = newConfig.getBoolean(configNode);
case INTEGER -> optionValue = newConfig.getInt(configNode);
default -> throw new IllegalArgumentException("Invalid config data type encountered");
}
configOptions.put(option, optionValue);
}
//Get the language name from the config
languageName = newConfig.getString("language");
languageName = (String) configOptions.get(ConfigOption.LANGUAGE);
//Get important folders from the config
portalFolder = newConfig.getString("folders.portalFolder");
gateFolder = newConfig.getString("folders.gateFolder");
//Get enabled debug settings from the config
debuggingEnabled = newConfig.getBoolean("debugging.debug");
permissionDebuggingEnabled = newConfig.getBoolean("debugging.permissionDebug");
portalFolder = (String) configOptions.get(ConfigOption.PORTAL_FOLDER);
gateFolder = (String) configOptions.get(ConfigOption.GATE_FOLDER);
//If users have an outdated config, assume they also need to update their default gates
if (isMigrating) {
@ -324,10 +366,10 @@ public final class StargateConfig {
}
//Load all gate config values
stargateGateConfig = new StargateGateConfig(newConfig);
stargateGateConfig = new StargateGateConfig(configOptions);
//Load all economy config values
economyConfig = new EconomyConfig(newConfig);
economyConfig = new EconomyConfig(configOptions);
Stargate.getInstance().saveConfig();
}

View File

@ -3,33 +3,25 @@ package net.knarcraft.stargate.config;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.PortalSignDrawer;
import org.bukkit.ChatColor;
import org.bukkit.configuration.file.FileConfiguration;
import java.util.Map;
/**
* The Stargate gate config keeps track of all global config values related to gates
*/
public final class StargateGateConfig {
private int maxGatesEachNetwork = 0;
private boolean rememberDestination = false;
private boolean handleVehicles = true;
private boolean handleLeashedCreatures = true;
private boolean sortNetworkDestinations = false;
private boolean protectEntrance = false;
private boolean enableBungee = true;
private boolean verifyPortals = true;
private boolean destroyExplosion = false;
private String defaultGateNetwork = "central";
private static final int activeTime = 10;
private static final int openTime = 10;
private final Map<ConfigOption, Object> configOptions;
/**
* Instantiates a new stargate config
*
* @param newConfig <p>The file configuration to read values from</p>
* @param configOptions <p>The loaded config options to use</p>
*/
public StargateGateConfig(FileConfiguration newConfig) {
loadGateConfig(newConfig);
public StargateGateConfig(Map<ConfigOption, Object> configOptions) {
this.configOptions = configOptions;
loadGateConfig();
}
/**
@ -56,7 +48,7 @@ public final class StargateGateConfig {
* @return <p>Maximum number of gates for each network</p>
*/
public int maxGatesEachNetwork() {
return maxGatesEachNetwork;
return (int) configOptions.get(ConfigOption.MAX_GATES_EACH_NETWORK);
}
/**
@ -65,7 +57,7 @@ public final class StargateGateConfig {
* @return <p>Whether a portal's lastly used destination should be remembered</p>
*/
public boolean rememberDestination() {
return rememberDestination;
return (boolean) configOptions.get(ConfigOption.REMEMBER_DESTINATION);
}
/**
@ -74,7 +66,48 @@ public final class StargateGateConfig {
* @return <p>Whether vehicle teleportation should be handled</p>
*/
public boolean handleVehicles() {
return handleVehicles;
return (boolean) configOptions.get(ConfigOption.HANDLE_VEHICLES);
}
/**
* Gets whether vehicles with no passengers should be handled
*
* <p>The handle vehicles option overrides this option if disabled. This option allows empty passenger
* minecarts/boats, but also chest/tnt/hopper/furnace minecarts to teleport through stargates.</p>
*
* @return <p>Whether vehicles without passengers should be handled</p>
*/
public boolean handleEmptyVehicles() {
return (boolean) configOptions.get(ConfigOption.HANDLE_EMPTY_VEHICLES);
}
/**
* Gets whether vehicles containing creatures should be handled
*
* <p>The handle vehicles option overrides this option if disabled. This option allows creatures (pigs, pandas,
* zombies, etc.) to teleport through stargates if in a vehicle.</p>
*
* @return <p>Whether vehicles with creatures should be handled</p>
*/
public boolean handleCreatureTransportation() {
return (boolean) configOptions.get(ConfigOption.HANDLE_CREATURE_TRANSPORTATION);
}
/**
* Gets whether vehicles containing a creature, but not a player should be handled
*
* <p>The handle vehicles option, and the handle creature transportation option, override this option if disabled.
* This option allows creatures (pigs, pandas, zombies, etc.) to teleport through stargates if in a vehicle, even
* if no player is in the vehicle.
* As it is not possible to check if a creature is allowed through a stargate, they will be able to go through
* regardless of whether the initiating player is allowed to enter the stargate. Enabling this is necessary to
* teleport creatures using minecarts, but only handleCreatureTransportation is required to teleport creatures
* using a boat manned by a player.</p>
*
* @return <p>Whether non-empty vehicles without a player should be handled</p>
*/
public boolean handleNonPlayerVehicles() {
return (boolean) configOptions.get(ConfigOption.HANDLE_NON_PLAYER_VEHICLES);
}
/**
@ -83,7 +116,7 @@ public final class StargateGateConfig {
* @return <p>Whether leashed creatures should be handled</p>
*/
public boolean handleLeashedCreatures() {
return handleLeashedCreatures;
return (boolean) configOptions.get(ConfigOption.HANDLE_LEASHED_CREATURES);
}
/**
@ -92,7 +125,7 @@ public final class StargateGateConfig {
* @return <p>Whether network destinations should be sorted</p>
*/
public boolean sortNetworkDestinations() {
return sortNetworkDestinations;
return (boolean) configOptions.get(ConfigOption.SORT_NETWORK_DESTINATIONS);
}
/**
@ -101,7 +134,7 @@ public final class StargateGateConfig {
* @return <p>Whether portal entrances should be protected</p>
*/
public boolean protectEntrance() {
return protectEntrance;
return (boolean) configOptions.get(ConfigOption.PROTECT_ENTRANCE);
}
/**
@ -110,7 +143,7 @@ public final class StargateGateConfig {
* @return <p>Whether bungee support is enabled</p>
*/
public boolean enableBungee() {
return enableBungee;
return (boolean) configOptions.get(ConfigOption.ENABLE_BUNGEE);
}
/**
@ -119,7 +152,7 @@ public final class StargateGateConfig {
* @return <p>Whether portals need to be verified</p>
*/
public boolean verifyPortals() {
return verifyPortals;
return (boolean) configOptions.get(ConfigOption.VERIFY_PORTALS);
}
/**
@ -128,7 +161,7 @@ public final class StargateGateConfig {
* @return <p>Whether portals should be destroyed by explosions</p>
*/
public boolean destroyedByExplosion() {
return destroyExplosion;
return (boolean) configOptions.get(ConfigOption.DESTROYED_BY_EXPLOSION);
}
/**
@ -137,34 +170,16 @@ public final class StargateGateConfig {
* @return <p>The default portal network</p>
*/
public String getDefaultPortalNetwork() {
return defaultGateNetwork;
return (String) configOptions.get(ConfigOption.DEFAULT_GATE_NETWORK);
}
/**
* Loads all config values related to gates
*
* @param newConfig <p>The configuration containing the values to read</p>
*/
private void loadGateConfig(FileConfiguration newConfig) {
String defaultNetwork = newConfig.getString("gates.defaultGateNetwork");
defaultGateNetwork = defaultNetwork != null ? defaultNetwork.trim() : null;
maxGatesEachNetwork = newConfig.getInt("gates.maxGatesEachNetwork");
//Functionality
handleVehicles = newConfig.getBoolean("gates.functionality.handleVehicles");
handleLeashedCreatures = newConfig.getBoolean("gates.functionality.handleLeashedCreatures");
enableBungee = newConfig.getBoolean("gates.functionality.enableBungee");
//Integrity
protectEntrance = newConfig.getBoolean("gates.integrity.protectEntrance");
verifyPortals = newConfig.getBoolean("gates.integrity.verifyPortals");
destroyExplosion = newConfig.getBoolean("gates.integrity.destroyedByExplosion");
//Cosmetic
sortNetworkDestinations = newConfig.getBoolean("gates.cosmetic.sortNetworkDestinations");
rememberDestination = newConfig.getBoolean("gates.cosmetic.rememberDestination");
loadSignColor(newConfig.getString("gates.cosmetic.mainSignColor"),
newConfig.getString("gates.cosmetic.highlightSignColor"));
private void loadGateConfig() {
//Load the sign colors
loadSignColor((String) configOptions.get(ConfigOption.MAIN_SIGN_COLOR),
(String) configOptions.get(ConfigOption.HIGHLIGHT_SIGN_COLOR));
}
/**
@ -173,15 +188,13 @@ 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) {
try {
PortalSignDrawer.setColors(ChatColor.valueOf(mainSignColor.toUpperCase()),
ChatColor.valueOf(highlightSignColor.toUpperCase()));
return;
} catch (IllegalArgumentException | NullPointerException ignored) {
}
try {
PortalSignDrawer.setMainColor(ChatColor.valueOf(mainSignColor.toUpperCase()));
PortalSignDrawer.setHighlightColor(ChatColor.valueOf(highlightSignColor.toUpperCase()));
} catch (IllegalArgumentException | NullPointerException exception) {
Stargate.logWarning("You have specified an invalid color in your config.yml. Defaulting to BLACK and WHITE");
PortalSignDrawer.setMainColor(ChatColor.BLACK);
PortalSignDrawer.setHighlightColor(ChatColor.WHITE);
}
Stargate.logWarning("You have specified an invalid color in your config.yml. Defaulting to BLACK and WHITE");
PortalSignDrawer.setColors(ChatColor.BLACK, ChatColor.WHITE);
}
}

View File

@ -1,6 +1,7 @@
package net.knarcraft.stargate.listener;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.BlockChangeRequest;
import net.knarcraft.stargate.event.StargateDestroyEvent;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalCreator;
@ -9,6 +10,7 @@ import net.knarcraft.stargate.portal.PortalRegistry;
import net.knarcraft.stargate.utility.EconomyHelper;
import net.knarcraft.stargate.utility.MaterialHelper;
import net.knarcraft.stargate.utility.PermissionHelper;
import net.knarcraft.stargate.utility.PortalFileHelper;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.data.type.WallSign;
@ -23,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;
@ -81,12 +84,35 @@ public class BlockEventListener implements Listener {
return;
}
//Remove the sign if the no sign option is enabled
if (portal.getOptions().hasNoSign()) {
Material replaceMaterial = PortalFileHelper.decideRemovalMaterial(portal.getSignLocation(), portal);
BlockChangeRequest request = new BlockChangeRequest(portal.getSignLocation(), replaceMaterial, null);
Stargate.addBlockChangeRequest(request);
}
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("createMsg"));
Stargate.debug("onSignChange", "Initialized stargate: " + portal.getName());
Stargate.getInstance().getServer().getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(),
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
*
@ -131,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;
}
@ -160,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

@ -1,16 +1,19 @@
package net.knarcraft.stargate.listener;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.MessageSender;
import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.portal.PlayerTeleporter;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalActivator;
import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.VehicleTeleporter;
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 org.bukkit.GameMode;
import org.bukkit.block.Block;
import org.bukkit.block.data.type.WallSign;
@ -26,6 +29,8 @@ import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
/**
* This listener listens to any player-related events related to stargates
@ -90,7 +95,8 @@ public class PlayerEventListener implements Listener {
Entity playerVehicle = player.getVehicle();
//If the player is in a vehicle, but vehicle handling is disabled, just ignore the player
if (playerVehicle == null || Stargate.getGateConfig().handleVehicles()) {
if (playerVehicle == null || (playerVehicle instanceof LivingEntity &&
Stargate.getGateConfig().handleVehicles())) {
teleportPlayer(playerVehicle, player, entrancePortal, destination, event);
}
}
@ -118,7 +124,9 @@ public class PlayerEventListener implements Listener {
//Just teleport the player like normal
new PlayerTeleporter(destination, player).teleport(entrancePortal, event);
}
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
}
entrancePortal.getPortalOpener().closePortal(false);
}
@ -158,12 +166,14 @@ public class PlayerEventListener implements Listener {
//Decide if the user should be teleported to another bungee server
if (entrancePortal.getOptions().isBungee()) {
if (BungeeHelper.bungeeTeleport(player, entrancePortal, event)) {
if (BungeeHelper.bungeeTeleport(player, entrancePortal, event) && !entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
}
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);
}
/**
@ -181,7 +191,7 @@ public class PlayerEventListener implements Listener {
}
if (event.getAction() == Action.RIGHT_CLICK_BLOCK) {
handleRightClickBlock(event, player, block);
handleRightClickBlock(event, player, block, event.getHand());
} else if (event.getAction() == Action.LEFT_CLICK_BLOCK && block.getBlockData() instanceof WallSign) {
//Handle left click of a wall sign
handleSignClick(event, player, block, true);
@ -237,10 +247,12 @@ public class PlayerEventListener implements Listener {
* @return <p>True if the player should be denied</p>
*/
private boolean cannotAccessPortal(Player player, Portal portal) {
boolean deny = PermissionHelper.cannotAccessNetwork(player, portal.getNetwork());
boolean deny = PermissionHelper.cannotAccessNetwork(player, portal.getCleanNetwork());
if (PermissionHelper.portalAccessDenied(player, portal, deny)) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
if (!portal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
}
return true;
}
return false;
@ -252,19 +264,20 @@ public class PlayerEventListener implements Listener {
* @param event <p>The event triggering the right-click</p>
* @param player <p>The player doing the right-click</p>
* @param block <p>The block the player clicked</p>
* @param hand <p>The hand the player used to interact with the stargate</p>
*/
private void handleRightClickBlock(PlayerInteractEvent event, Player player, Block block) {
private void handleRightClickBlock(PlayerInteractEvent event, Player player, Block block, EquipmentSlot hand) {
if (block.getBlockData() instanceof WallSign) {
handleSignClick(event, player, block, false);
return;
}
if (MaterialHelper.isButtonCompatible(block.getType())) {
//Prevent a double click caused by a Spigot bug
if (clickIsBug(event, block)) {
return;
}
//Prevent a double click caused by a Spigot bug
if (clickIsBug(event, block)) {
return;
}
if (MaterialHelper.isButtonCompatible(block.getType())) {
Portal portal = PortalHandler.getByBlock(block);
if (portal == null) {
return;
@ -280,33 +293,70 @@ public class PlayerEventListener implements Listener {
}
PermissionHelper.openPortal(player, portal);
if (portal.getPortalOpener().isOpenFor(player)) {
if (portal.getPortalOpener().isOpenFor(player) && !MaterialHelper.isContainer(block.getType())) {
event.setUseInteractedBlock(Event.Result.ALLOW);
}
} else {
//Display information about the portal if it has no sign
ItemStack heldItem = player.getInventory().getItem(hand);
if (heldItem.getType().isAir() || !heldItem.getType().isBlock()) {
displayPortalInfo(block, player);
}
}
}
/**
* This function decides if a right click of a coral is caused by a Spigot bug
* Displays information about a clicked portal
*
* <p>The Spigot bug currently makes every right click of a coral trigger twice, causing the portal to close
* immediately. This fix should detect the bug without breaking wall coral buttons once the bug is fixed.</p>
* <p>This will only display portal info if the portal has no sign and is not silent.</p>
*
* @param block <p>The clicked block</p>
* @param player <p>The player that clicked the block</p>
*/
private void displayPortalInfo(Block block, Player player) {
Portal portal = PortalHandler.getByBlock(block);
if (portal == null) {
return;
}
//Display portal information as a portal without a sign does not display any
if (portal.getOptions().hasNoSign() && (!portal.getOptions().isSilent() || player.isSneaking())) {
MessageSender sender = Stargate.getMessageSender();
sender.sendSuccessMessage(player, ChatColor.GOLD + Stargate.getString("portalInfoTitle"));
sender.sendSuccessMessage(player, Stargate.replaceVars(Stargate.getString("portalInfoName"),
"%name%", portal.getName()));
sender.sendSuccessMessage(player, Stargate.replaceVars(Stargate.getString("portalInfoDestination"),
"%destination%", portal.getDestinationName()));
if (portal.getOptions().isBungee()) {
sender.sendSuccessMessage(player, Stargate.replaceVars(Stargate.getString("portalInfoServer"),
"%server%", portal.getNetwork()));
} else {
sender.sendSuccessMessage(player, Stargate.replaceVars(Stargate.getString("portalInfoNetwork"),
"%network%", portal.getNetwork()));
}
}
}
/**
* This function decides if a right click of a block is caused by a Spigot bug
*
* <p>The Spigot bug currently makes every right click of some blocks trigger twice, causing the portal to close
* immediately, or causing portal information printing twice. This fix should detect the bug without breaking
* clicking once the bug is fixed.</p>
*
* @param event <p>The event causing the right click</p>
* @param block <p>The block to check</p>
* @return <p>True if the click is a bug and should be cancelled</p>
*/
private boolean clickIsBug(PlayerInteractEvent event, Block block) {
if (MaterialHelper.isWallCoral(block.getType())) {
if (previousEvent != null &&
event.getPlayer() == previousEvent.getPlayer() && eventTime + 15 > System.currentTimeMillis()) {
previousEvent = null;
eventTime = 0;
return true;
}
previousEvent = event;
eventTime = System.currentTimeMillis();
if (previousEvent != null &&
event.getPlayer() == previousEvent.getPlayer() && eventTime + 15 > System.currentTimeMillis()) {
previousEvent = null;
eventTime = 0;
return true;
}
previousEvent = event;
eventTime = System.currentTimeMillis();
return false;
}

View File

@ -2,9 +2,9 @@ package net.knarcraft.stargate.listener;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.FromTheEndTeleportation;
import net.knarcraft.stargate.portal.PlayerTeleporter;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter;
import net.knarcraft.stargate.utility.PermissionHelper;
import org.bukkit.Location;
import org.bukkit.Material;

View File

@ -3,7 +3,8 @@ 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.VehicleTeleporter;
import net.knarcraft.stargate.portal.teleporter.Teleporter;
import net.knarcraft.stargate.portal.teleporter.VehicleTeleporter;
import net.knarcraft.stargate.utility.EconomyHelper;
import net.knarcraft.stargate.utility.EntityHelper;
import net.knarcraft.stargate.utility.PermissionHelper;
@ -89,7 +90,9 @@ public class VehicleEventListener implements Listener {
//On the assumption that a non-player cannot sit in the driver's seat and since some portals can only be open
// to one player at a time, we only need to check if the portal is open to the driver.
if (!entrancePortal.getPortalOpener().isOpenFor(player)) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
}
return;
}
@ -108,16 +111,21 @@ 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;
}
}
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
new VehicleTeleporter(destinationPortal, vehicle).teleport(entrancePortal);
entrancePortal.getPortalOpener().closePortal(false);
//Teleport the vehicle and inform the user if the vehicle was teleported
boolean teleported = new VehicleTeleporter(destinationPortal, vehicle).teleport(entrancePortal);
if (teleported) {
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
}
entrancePortal.getPortalOpener().closePortal(false);
}
}
/**
@ -149,18 +157,24 @@ public class VehicleEventListener implements Listener {
private static boolean playerCanTeleport(Player player, Portal entrancePortal, Portal destinationPortal) {
//Make sure the user can access the portal
if (PermissionHelper.cannotAccessPortal(player, entrancePortal, destinationPortal)) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
}
entrancePortal.getPortalOpener().closePortal(false);
return false;
}
//Check if the player is able to afford the teleport fee
int cost = Stargate.getEconomyConfig().getUseCost(player, entrancePortal, destinationPortal);
int cost = EconomyHelper.getUseCost(player, entrancePortal, destinationPortal);
boolean canAffordFee = cost <= 0 || Stargate.getEconomyConfig().canAffordFee(player, cost);
if (!canAffordFee) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("ecoInFunds"));
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("ecoInFunds"));
}
return false;
}
return canAffordFee;
return Teleporter.noLeashedCreaturesPreventTeleportation(player);
}
}

View File

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

View File

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

View File

@ -4,20 +4,26 @@ import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.container.RelativeBlockVector;
import net.knarcraft.stargate.event.StargateCreateEvent;
import net.knarcraft.stargate.portal.property.PortalLocation;
import net.knarcraft.stargate.portal.property.PortalOption;
import net.knarcraft.stargate.portal.property.PortalOptions;
import net.knarcraft.stargate.portal.property.PortalOwner;
import net.knarcraft.stargate.portal.property.gate.Gate;
import net.knarcraft.stargate.portal.property.gate.GateHandler;
import net.knarcraft.stargate.utility.DirectionHelper;
import net.knarcraft.stargate.utility.EconomyHelper;
import net.knarcraft.stargate.utility.PermissionHelper;
import net.knarcraft.stargate.utility.PortalFileHelper;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Directional;
import org.bukkit.entity.Player;
import org.bukkit.event.block.SignChangeEvent;
import java.util.List;
import java.util.Map;
import static net.knarcraft.stargate.Stargate.getMaxNameNetworkLength;
/**
* The portal creator can create and validate a new portal
*/
@ -45,16 +51,16 @@ public class PortalCreator {
*/
public Portal createPortal() {
BlockLocation signLocation = new BlockLocation(event.getBlock());
Block idParent = signLocation.getParent();
Block signControlBlock = signLocation.getParent();
//Return early if the sign is not placed on a block, or the block is not a control block
if (idParent == null || GateHandler.getGatesByControlBlock(idParent).length == 0) {
if (signControlBlock == null || GateHandler.getGatesByControlBlock(signControlBlock).length == 0) {
Stargate.debug("createPortal", "Control block not registered");
return null;
}
//The control block is already part of another portal
if (PortalHandler.getByBlock(idParent) != null) {
if (PortalHandler.getByBlock(signControlBlock) != null) {
Stargate.debug("createPortal", "idParent belongs to existing stargate");
return null;
}
@ -69,7 +75,8 @@ public class PortalCreator {
Map<PortalOption, Boolean> portalOptions = PortalHandler.getPortalOptions(player, destinationName, options);
//Get the yaw
float yaw = DirectionHelper.getYawFromLocationDifference(idParent.getLocation(), signLocation.getLocation());
float yaw = DirectionHelper.getYawFromLocationDifference(signControlBlock.getLocation(),
signLocation.getLocation());
//Get the direction the button should be facing
BlockFace buttonFacing = DirectionHelper.getBlockFaceFromYaw(yaw);
@ -80,7 +87,7 @@ public class PortalCreator {
Stargate.debug("createPortal", "Finished getting all portal info");
//Try and find a gate matching the new portal
Gate gate = PortalHandler.findMatchingGate(portalLocation, player);
Gate gate = PortalHandler.findMatchingGate(portalLocation, player.getWorld());
if ((gate == null) || (portalLocation.getButtonVector() == null)) {
Stargate.debug("createPortal", "Could not find matching gate layout");
return null;
@ -100,7 +107,8 @@ public class PortalCreator {
Stargate.debug("createPortal", builder.toString());
//Use default network if a proper alternative is not set
if (!portalOptions.get(PortalOption.BUNGEE) && (network.length() < 1 || network.length() > 11)) {
if (!portalOptions.get(PortalOption.BUNGEE) && (network.length() < 1 || network.length() >
getMaxNameNetworkLength())) {
network = Stargate.getDefaultNetwork();
}
@ -112,8 +120,8 @@ public class PortalCreator {
Stargate.debug("createPortal", "Player doesn't have create permissions on network. Trying personal");
if (PermissionHelper.canCreatePersonalPortal(player)) {
network = player.getName();
if (network.length() > 11) {
network = network.substring(0, 11);
if (network.length() > getMaxNameNetworkLength()) {
network = network.substring(0, getMaxNameNetworkLength());
}
Stargate.debug("createPortal", "Creating personal portal");
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createPersonal"));
@ -184,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;
}
@ -196,9 +206,8 @@ public class PortalCreator {
}
//Add button if the portal is not always on
if (!portalOptions.isAlwaysOn() && !portalOptions.isBungee()) {
generatePortalButton(portalLocation.getTopLeft(), portalLocation.getButtonVector(),
portalLocation.getButtonFacing());
if (!portalOptions.isAlwaysOn()) {
PortalFileHelper.generatePortalButton(portal, portalLocation.getButtonFacing());
}
//Register the new portal
@ -224,29 +233,30 @@ public class PortalCreator {
*/
private boolean checkIfNewPortalIsValid(int cost, String portalName) {
//Check if the portal name can fit on the sign with padding (>name<)
if (portal.getName().length() < 1 || portal.getName().length() > 11) {
Stargate.debug("createPortal", "Name length error");
if (portal.getCleanName().length() < 1 || portal.getCleanName().length() > getMaxNameNetworkLength()) {
Stargate.debug("createPortal", String.format("Name length error. %s is too long.",
portal.getCleanName()));
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createNameLength"));
return false;
}
if (portal.getOptions().isBungee()) {
//Check if the bungee portal's name has been duplicated
if (PortalHandler.getBungeePortals().get(portal.getName().toLowerCase()) != null) {
if (PortalHandler.getBungeePortals().get(portal.getCleanName()) != null) {
Stargate.debug("createPortal::Bungee", "Gate name duplicate");
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createExists"));
return false;
}
} else {
//Check if the portal name has been duplicated on the network
if (PortalHandler.getByName(portal.getName(), portal.getNetwork()) != null) {
if (PortalHandler.getByName(portal.getCleanName(), portal.getCleanNetwork()) != null) {
Stargate.debug("createPortal", "Gate name duplicate");
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createExists"));
return false;
}
//Check if the number of portals in the network has been surpassed
List<String> networkList = PortalHandler.getAllPortalNetworks().get(portal.getNetwork().toLowerCase());
List<String> networkList = PortalHandler.getAllPortalNetworks().get(portal.getCleanNetwork());
int maxGates = Stargate.getGateConfig().maxGatesEachNetwork();
if (maxGates > 0 && networkList != null && networkList.size() >= maxGates) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createFull"));
@ -256,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;
@ -267,25 +277,6 @@ public class PortalCreator {
return true;
}
/**
* Generates a button for a portal
*
* @param topLeft <p>The top-left block of the portal</p>
* @param buttonVector <p>A relative vector pointing at the button</p>
* @param buttonFacing <p>The direction the button should be facing</p>
*/
private void generatePortalButton(BlockLocation topLeft, RelativeBlockVector buttonVector,
BlockFace buttonFacing) {
//Go one block outwards to find the button's location rather than the control block's location
BlockLocation button = topLeft.getRelativeLocation(buttonVector.addToVector(
RelativeBlockVector.Property.OUT, 1), portal.getYaw());
Directional buttonData = (Directional) Bukkit.createBlockData(portal.getGate().getPortalButton());
buttonData.setFacing(buttonFacing);
button.getBlock().setBlockData(buttonData);
portal.getStructure().setButton(button);
}
/**
* Updates the open state of the newly created portal
*
@ -298,7 +289,7 @@ public class PortalCreator {
portal.getPortalOpener().openPortal(true);
} else if (portal.getOptions().isAlwaysOn()) {
//For a normal always-on portal, open both the portal and the destination
Portal destinationPortal = PortalHandler.getByName(destinationName, portal.getNetwork());
Portal destinationPortal = PortalHandler.getByName(destinationName, portal.getCleanNetwork());
if (destinationPortal != null) {
portal.getPortalOpener().openPortal(true);
destinationPortal.drawSign();

View File

@ -3,8 +3,14 @@ package net.knarcraft.stargate.portal;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.container.RelativeBlockVector;
import net.knarcraft.stargate.portal.property.PortalLocation;
import net.knarcraft.stargate.portal.property.PortalOption;
import net.knarcraft.stargate.portal.property.PortalStructure;
import net.knarcraft.stargate.portal.property.gate.Gate;
import net.knarcraft.stargate.portal.property.gate.GateHandler;
import net.knarcraft.stargate.utility.PermissionHelper;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
@ -60,7 +66,7 @@ public class PortalHandler {
*/
public static List<String> getDestinations(Portal entrancePortal, Player player, String network) {
List<String> destinations = new ArrayList<>();
for (String destination : PortalRegistry.getAllPortalNetworks().get(network.toLowerCase())) {
for (String destination : PortalRegistry.getAllPortalNetworks().get(network)) {
Portal portal = getByName(destination, network);
if (portal == null) {
continue;
@ -74,11 +80,12 @@ public class PortalHandler {
continue;
}
//Check if destination is this portal
if (destination.equalsIgnoreCase(entrancePortal.getName())) {
if (destination.equals(entrancePortal.getCleanName())) {
continue;
}
//Check if destination is a fixed portal not pointing to this portal
if (portal.getOptions().isFixed() && !portal.getDestinationName().equalsIgnoreCase(entrancePortal.getName())) {
if (portal.getOptions().isFixed() &&
!Portal.cleanString(portal.getDestinationName()).equals(entrancePortal.getCleanName())) {
continue;
}
//Allow random use by non-players (Minecarts)
@ -137,12 +144,12 @@ public class PortalHandler {
* Tries to find a gate matching the portal the user is trying to create
*
* @param portalLocation <p>The location data for the new portal</p>
* @param player <p>The player trying to create the new portal</p>
* @param world <p>The world the player is located in</p>
* @return <p>The matching gate type, or null if no such gate could be found</p>
*/
static Gate findMatchingGate(PortalLocation portalLocation, Player player) {
static Gate findMatchingGate(PortalLocation portalLocation, World world) {
Block signParent = portalLocation.getSignLocation().getParent();
BlockLocation parent = new BlockLocation(player.getWorld(), signParent.getX(), signParent.getY(),
BlockLocation parent = new BlockLocation(world, signParent.getX(), signParent.getY(),
signParent.getZ());
//Get all gates with the used type of control blocks
@ -176,10 +183,10 @@ public class PortalHandler {
* @param portal <p>The newly created portal</p>
*/
static void updatePortalsPointingAtNewPortal(Portal portal) {
for (String originName : PortalRegistry.getAllPortalNetworks().get(portal.getNetwork().toLowerCase())) {
Portal origin = getByName(originName, portal.getNetwork());
for (String originName : PortalRegistry.getAllPortalNetworks().get(portal.getCleanNetwork())) {
Portal origin = getByName(originName, portal.getCleanNetwork());
if (origin == null ||
!origin.getDestinationName().equalsIgnoreCase(portal.getName()) ||
!Portal.cleanString(origin.getDestinationName()).equals(portal.getCleanName()) ||
!origin.getStructure().isVerified()) {
continue;
}

View File

@ -5,6 +5,7 @@ import net.knarcraft.stargate.container.BlockChangeRequest;
import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.event.StargateCloseEvent;
import net.knarcraft.stargate.event.StargateOpenEvent;
import net.knarcraft.stargate.portal.property.PortalOptions;
import org.bukkit.Axis;
import org.bukkit.Material;
import org.bukkit.block.data.Orientable;
@ -125,7 +126,7 @@ public class PortalOpener {
return;
}
boolean thisIsDestination = destination.getDestinationName().equalsIgnoreCase(portal.getName());
boolean thisIsDestination = Portal.cleanString(destination.getDestinationName()).equals(portal.getCleanName());
//Only open destination if it's not-fixed or points at this portal, and is not already open
if (!options.isRandom() && (!destination.getOptions().isFixed() || thisIsDestination) && !destination.isOpen()) {
//Open the destination portal

View File

@ -4,8 +4,6 @@ import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.utility.PortalFileHelper;
import org.bukkit.World;
import org.bukkit.block.Sign;
import org.bukkit.block.data.type.WallSign;
import java.util.ArrayList;
import java.util.HashMap;
@ -37,6 +35,7 @@ public class PortalRegistry {
lookupControls.clear();
allPortals.clear();
allPortalNetworks.clear();
bungeePortals.clear();
}
/**
@ -64,7 +63,7 @@ public class PortalRegistry {
private static void clearPortals(List<Portal> portalsToRemove) {
//Store the names of the portals to remove as some maps require the name, not the object
List<String> portalNames = new ArrayList<>();
portalsToRemove.forEach((portal) -> portalNames.add(portal.getName()));
portalsToRemove.forEach((portal) -> portalNames.add(portal.getCleanName()));
//Clear all the lookup locations for the portals
lookupBlocks.keySet().removeIf((key) -> portalsToRemove.contains(lookupBlocks.get(key)));
@ -163,10 +162,11 @@ public class PortalRegistry {
*/
public static void unregisterPortal(Portal portal, boolean removeAll) {
Stargate.debug("Unregister", "Unregistering gate " + portal.getName());
portal.getPortalActivator().deactivate();
portal.getPortalOpener().closePortal(true);
String portalName = portal.getName().toLowerCase();
String networkName = portal.getNetwork().toLowerCase();
String portalName = portal.getCleanName();
String networkName = portal.getCleanNetwork();
//Remove portal from lookup blocks
for (BlockLocation block : portal.getStructure().getFrame()) {
@ -203,7 +203,7 @@ public class PortalRegistry {
//Update all portals in the same network with this portal as its destination
for (String originName : allPortalNetworks.get(networkName)) {
Portal origin = PortalHandler.getByName(originName, portal.getNetwork());
Portal origin = PortalHandler.getByName(originName, portal.getCleanNetwork());
if (origin == null || !origin.getDestinationName().equalsIgnoreCase(portalName) ||
!origin.getStructure().isVerified()) {
continue;
@ -219,17 +219,11 @@ public class PortalRegistry {
}
}
//Clear sign data
if (portal.getSignLocation().getBlock().getBlockData() instanceof WallSign) {
Sign sign = (Sign) portal.getSignLocation().getBlock().getState();
sign.setLine(0, portal.getName());
sign.setLine(1, "");
sign.setLine(2, "");
sign.setLine(3, "");
sign.update();
}
//Mark the portal's sign as unregistered
new PortalSignDrawer(portal).drawUnregisteredSign();
PortalFileHelper.saveAllPortals(portal.getWorld());
portal.setRegistered(false);
}
/**
@ -241,8 +235,8 @@ public class PortalRegistry {
portal.getOptions().setFixed(portal.getDestinationName().length() > 0 || portal.getOptions().isRandom() ||
portal.getOptions().isBungee());
String portalName = portal.getName().toLowerCase();
String networkName = portal.getNetwork().toLowerCase();
String portalName = portal.getCleanName();
String networkName = portal.getCleanNetwork();
//Bungee portals are stored in their own list
if (portal.getOptions().isBungee()) {
@ -250,14 +244,14 @@ public class PortalRegistry {
} else {
//Check if network exists in the lookup list. If not, register the new network
if (!portalLookupByNetwork.containsKey(networkName)) {
Stargate.debug("register", "Network " + portal.getNetwork() +
" not in lookupNamesNet, adding");
Stargate.debug("register", String.format("Network %s not in lookupNamesNet, adding",
portal.getNetwork()));
portalLookupByNetwork.put(networkName, new HashMap<>());
}
//Check if this network exists in the network list. If not, register the network
if (!allPortalNetworks.containsKey(networkName)) {
Stargate.debug("register", "Network " + portal.getNetwork() +
" not in allPortalsNet, adding");
Stargate.debug("register", String.format("Network %s not in allPortalsNet, adding",
portal.getNetwork()));
allPortalNetworks.put(networkName, new ArrayList<>());
}
@ -277,8 +271,10 @@ public class PortalRegistry {
lookupBlocks.put(block, portal);
}
//Register the sign and button to the lookup lists
lookupBlocks.put(portal.getSignLocation(), portal);
lookupControls.put(portal.getSignLocation(), portal);
if (!portal.getOptions().hasNoSign()) {
lookupBlocks.put(portal.getSignLocation(), portal);
lookupControls.put(portal.getSignLocation(), portal);
}
BlockLocation button = portal.getStructure().getButton();
if (button != null) {
@ -292,6 +288,7 @@ public class PortalRegistry {
}
allPortals.add(portal);
portal.setRegistered(true);
}
}

View File

@ -1,6 +1,7 @@
package net.knarcraft.stargate.portal;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.property.PortalLocation;
import net.knarcraft.stargate.utility.PermissionHelper;
import org.bukkit.ChatColor;
import org.bukkit.block.Block;
@ -14,7 +15,7 @@ public class PortalSignDrawer {
private final Portal portal;
private final static ChatColor errorColor = ChatColor.DARK_RED;
private final static ChatColor freeColor = ChatColor.DARK_GREEN;
private static ChatColor freeColor;
private static ChatColor mainColor;
private static ChatColor highlightColor;
@ -28,35 +29,67 @@ public class PortalSignDrawer {
}
/**
* Sets the main sign color
* Sets the highlighting sign color
*
* <p>The main sign color is used for most text on the sign, while the highlighting color is used for the markings
* 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
*
* @param freeColor <p>The new color to use for marking free stargates</p>
*/
public static void setFreeColor(ChatColor freeColor) {
PortalSignDrawer.freeColor = freeColor;
}
/**
* Draws the sign of the portal this sign drawer is responsible for
*/
public void drawSign() {
Block signBlock = portal.getSignLocation().getBlock();
BlockState state = signBlock.getState();
if (!(state instanceof Sign sign)) {
Stargate.logWarning("Sign block is not a Sign object");
Stargate.debug("Portal::drawSign", String.format("Block: %s @ %s", signBlock.getType(),
signBlock.getLocation()));
Sign sign = getSign();
if (sign == null) {
return;
}
drawSign(sign);
}
/**
* Gets the sign for this sign drawer's portal
*
* @return <p>The sign of this sign drawer's portal</p>
*/
private Sign getSign() {
Block signBlock = portal.getSignLocation().getBlock();
BlockState state = signBlock.getState();
if (!(state instanceof Sign sign)) {
if (!portal.getOptions().hasNoSign()) {
Stargate.logWarning("Sign block is not a Sign object");
Stargate.debug("Portal::drawSign", String.format("Block: %s @ %s", signBlock.getType(),
signBlock.getLocation()));
}
return null;
}
return sign;
}
/**
* Draws the sign of the portal this sign drawer is responsible for
*
@ -64,11 +97,8 @@ public class PortalSignDrawer {
*/
private void drawSign(Sign sign) {
//Clear sign
for (int index = 0; index <= 3; index++) {
sign.setLine(index, "");
}
setLine(sign, 0, highlightColor + "-" + mainColor +
portal.getName() + highlightColor + "-");
clearSign(sign);
setLine(sign, 0, highlightColor + "-" + mainColor + fixColor(portal.getName()) + highlightColor + "-");
if (!portal.getPortalActivator().isActive()) {
//Default sign text
@ -89,6 +119,30 @@ public class PortalSignDrawer {
sign.update();
}
/**
* Clears all lines of a sign, but does not update the sign
*
* @param sign <p>The sign to clear</p>
*/
private void clearSign(Sign sign) {
for (int index = 0; index <= 3; index++) {
sign.setLine(index, "");
}
}
/**
* Marks this sign drawer's portal as unregistered
*/
public void drawUnregisteredSign() {
Sign sign = getSign();
if (sign == null) {
return;
}
clearSign(sign);
sign.setLine(0, fixColor(portal.getName()));
sign.update();
}
/**
* Draws a sign with choose-able network locations
*
@ -99,46 +153,46 @@ public class PortalSignDrawer {
int maxIndex = destinations.getDestinations().size() - 1;
int signLineIndex = 0;
int destinationIndex = destinations.getDestinations().indexOf(portal.getDestinationName());
boolean freeGatesGreen = Stargate.getEconomyConfig().useEconomy() &&
Stargate.getEconomyConfig().drawFreePortalsGreen();
boolean freeGatesColored = Stargate.getEconomyConfig().useEconomy() &&
Stargate.getEconomyConfig().drawFreePortalsColored();
//Last, and not only entry. Draw the entry two back
if ((destinationIndex == maxIndex) && (maxIndex > 1)) {
drawNetworkSignLine(freeGatesGreen, sign, ++signLineIndex, destinationIndex - 2);
drawNetworkSignLine(freeGatesColored, sign, ++signLineIndex, destinationIndex - 2);
}
//Not first entry. Draw the previous entry
if (destinationIndex > 0) {
drawNetworkSignLine(freeGatesGreen, sign, ++signLineIndex, destinationIndex - 1);
drawNetworkSignLine(freeGatesColored, sign, ++signLineIndex, destinationIndex - 1);
}
//Draw the chosen entry (line 2 or 3)
drawNetworkSignChosenLine(freeGatesGreen, sign, ++signLineIndex);
drawNetworkSignChosenLine(freeGatesColored, sign, ++signLineIndex);
//Has another entry and space on the sign
if ((maxIndex >= destinationIndex + 1)) {
drawNetworkSignLine(freeGatesGreen, sign, ++signLineIndex, destinationIndex + 1);
drawNetworkSignLine(freeGatesColored, sign, ++signLineIndex, destinationIndex + 1);
}
//Has another entry and space on the sign
if ((maxIndex >= destinationIndex + 2) && (++signLineIndex <= 3)) {
drawNetworkSignLine(freeGatesGreen, sign, signLineIndex, destinationIndex + 2);
drawNetworkSignLine(freeGatesColored, sign, signLineIndex, destinationIndex + 2);
}
}
/**
* Draws the chosen destination on one sign line
*
* @param freeGatesGreen <p>Whether to display free gates in a green color</p>
* @param sign <p>The sign to draw on</p>
* @param signLineIndex <p>The line to draw on</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 freeGatesGreen, Sign sign, int signLineIndex) {
if (freeGatesGreen) {
private void drawNetworkSignChosenLine(boolean freeGatesColored, Sign sign, int signLineIndex) {
if (freeGatesColored) {
Portal destination = PortalHandler.getByName(portal.getDestinationName(), portal.getNetwork());
boolean green = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination);
ChatColor nameColor = (green ? freeColor : highlightColor);
setLine(sign, signLineIndex, nameColor + ">" + (green ? freeColor : mainColor) +
portal.getDestinationName() + nameColor + "<");
boolean free = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination);
ChatColor nameColor = (free ? freeColor : highlightColor);
setLine(sign, signLineIndex, nameColor + ">" + (free ? freeColor : mainColor) +
fixColor(portal.getDestinationName()) + nameColor + "<");
} else {
setLine(sign, signLineIndex, highlightColor + ">" + mainColor + portal.getDestinationName() +
highlightColor + "<");
setLine(sign, signLineIndex, highlightColor + ">" + mainColor +
fixColor(portal.getDestinationName()) + highlightColor + "<");
}
}
@ -156,36 +210,40 @@ public class PortalSignDrawer {
/**
* Draws one network destination on one sign line
*
* @param freeGatesGreen <p>Whether to display free gates in a green color</p>
* @param freeGatesColored <p>Whether to display free gates in a different color</p>
* @param sign <p>The sign to draw on</p>
* @param signLineIndex <p>The line to draw on</p>
* @param destinationIndex <p>The index of the destination to draw</p>
*/
private void drawNetworkSignLine(boolean freeGatesGreen, Sign sign, int signLineIndex, int destinationIndex) {
private void drawNetworkSignLine(boolean freeGatesColored, Sign sign, int signLineIndex, int destinationIndex) {
PortalActivator destinations = portal.getPortalActivator();
String destinationName = destinations.getDestinations().get(destinationIndex);
if (freeGatesGreen) {
if (freeGatesColored) {
Portal destination = PortalHandler.getByName(destinationName, portal.getNetwork());
boolean green = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination);
setLine(sign, signLineIndex, (green ? freeColor : mainColor) + destinationName);
boolean free = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination);
setLine(sign, signLineIndex, (free ? freeColor : mainColor) + fixColor(destinationName));
} else {
setLine(sign, signLineIndex, mainColor + destinationName);
setLine(sign, signLineIndex, mainColor + fixColor(destinationName));
}
}
/**
* Draws a bungee sign
* Draws the sign of a BungeeCord portal
*
* @param sign <p>The sign to re-draw</p>
*/
private void drawBungeeSign(Sign sign) {
setLine(sign, 1, Stargate.getString("bungeeSign"));
setLine(sign, 2, highlightColor + ">" + mainColor + portal.getDestinationName() + highlightColor + "<");
setLine(sign, 3, highlightColor + "[" + mainColor + portal.getNetwork() + highlightColor + "]");
setLine(sign, 2, highlightColor + ">" + mainColor + fixColor(portal.getDestinationName()) +
highlightColor + "<");
setLine(sign, 3, highlightColor + "[" + mainColor + fixColor(portal.getNetwork()) +
highlightColor + "]");
}
/**
* Draws an inactive sign
* Draws the sign of an in-active portal
*
* <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>
*/
@ -193,7 +251,8 @@ public class PortalSignDrawer {
setLine(sign, 1, Stargate.getString("signRightClick"));
setLine(sign, 2, Stargate.getString("signToUse"));
if (!portal.getOptions().isNoNetwork()) {
setLine(sign, 3, highlightColor + "(" + mainColor + portal.getNetwork() + highlightColor + ")");
setLine(sign, 3, highlightColor + "(" + mainColor + fixColor(portal.getNetwork()) +
highlightColor + ")");
} else {
setLine(sign, 3, "");
}
@ -205,16 +264,20 @@ public class PortalSignDrawer {
* @param sign <p>The sign to re-draw</p>
*/
private void drawFixedSign(Sign sign) {
Portal destinationPortal = PortalHandler.getByName(Portal.cleanString(portal.getDestinationName()),
portal.getCleanNetwork());
String destinationName = portal.getOptions().isRandom() ? Stargate.getString("signRandom") :
portal.getDestinationName();
setLine(sign, 1, highlightColor + ">" + mainColor + destinationName + highlightColor + "<");
(destinationPortal != null ? destinationPortal.getName() : portal.getDestinationName());
setLine(sign, 1, highlightColor + ">" + mainColor + fixColor(destinationName) + highlightColor + "<");
if (portal.getOptions().isNoNetwork()) {
setLine(sign, 2, "");
} else {
setLine(sign, 2, highlightColor + "(" + mainColor + portal.getNetwork() + highlightColor + ")");
setLine(sign, 2, highlightColor + "(" + mainColor + fixColor(portal.getNetwork()) +
highlightColor + ")");
}
Portal destination = PortalHandler.getByName(portal.getDestinationName(), portal.getNetwork());
Portal destination = PortalHandler.getByName(Portal.cleanString(portal.getDestinationName()),
portal.getNetwork());
if (destination == null && !portal.getOptions().isRandom()) {
setLine(sign, 3, errorColor + Stargate.getString("signDisconnected"));
} else {
@ -230,11 +293,24 @@ 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();
Stargate.logInfo(String.format("Gate layout on line %d does not exist [%s]", lineIndex, gateName));
}
/**
* Fixes coloring of signs as the & character isn't translated on all servers
*
* @param text <p>The text to fix the coloring of</p>
* @return <p>The text with the coloring fixed</p>
*/
private String fixColor(String text) {
return ChatColor.translateAlternateColorCodes('&', text);
}
}

View File

@ -1,4 +1,4 @@
package net.knarcraft.stargate.portal;
package net.knarcraft.stargate.portal.property;
import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.container.RelativeBlockVector;

View File

@ -1,4 +1,4 @@
package net.knarcraft.stargate.portal;
package net.knarcraft.stargate.portal.property;
/**
* Each enum value represents one option a portal can have/use
@ -48,7 +48,17 @@ public enum PortalOption {
/**
* This option allows a portal to teleport to another server connected through BungeeCord
*/
BUNGEE('u', "stargate.admin.bungee", 20);
BUNGEE('u', "stargate.admin.bungee", 20),
/**
* This option allows a portal which does not display a teleportation message, for better immersion
*/
SILENT('i', "stargate.option.silent", 21),
/**
* This option causes a fixed portal's sign to be removed after creation
*/
NO_SIGN('e', "stargate.option.nosign", 22);
private final char characterRepresentation;
private final String permissionString;

View File

@ -1,4 +1,4 @@
package net.knarcraft.stargate.portal;
package net.knarcraft.stargate.portal.property;
import net.knarcraft.stargate.Stargate;
@ -25,12 +25,17 @@ public class PortalOptions {
if (this.isAlwaysOn() && !isFixed) {
this.options.put(PortalOption.ALWAYS_ON, false);
Stargate.debug("Portal", "Can not create a non-fixed always-on gate. Setting AlwaysOn = false");
Stargate.debug("PortalOptions", "Can not create a non-fixed always-on gate. Setting AlwaysOn = false");
}
if (this.isRandom() && !this.isAlwaysOn()) {
if ((this.isRandom() || this.isBungee()) && !this.isAlwaysOn()) {
this.options.put(PortalOption.ALWAYS_ON, true);
Stargate.debug("Portal", "Gate marked as random, set to always-on");
Stargate.debug("PortalOptions", "Gate marked as random or bungee, set to always-on");
}
if (this.hasNoSign() && !this.isFixed) {
this.options.put(PortalOption.NO_SIGN, false);
Stargate.debug("PortalOptions", "Gate marked with no sign, but not fixed. Setting NoSign = false");
}
}
@ -165,4 +170,27 @@ public class PortalOptions {
return this.options.get(PortalOption.BUNGEE);
}
/**
* Gets whether this portal is silent
*
* <p>A silent portal does not output anything to the chat when teleporting. This option is mainly useful to keep
* the immersion during teleportation (for role-playing servers or similar).</p>
*
* @return <p>Whether this portal is silent</p>
*/
public boolean isSilent() {
return this.options.get(PortalOption.SILENT);
}
/**
* Gets whether this portal has no sign
*
* <p>An always-on portal is allowed to not have a sign as it will never be interacted with anyway.</p>
*
* @return <p>Whether this portal has no sign</p>
*/
public boolean hasNoSign() {
return this.options.get(PortalOption.NO_SIGN);
}
}

View File

@ -1,4 +1,4 @@
package net.knarcraft.stargate.portal;
package net.knarcraft.stargate.portal.property;
import net.knarcraft.stargate.Stargate;
import org.bukkit.Bukkit;

View File

@ -1,8 +1,10 @@
package net.knarcraft.stargate.portal;
package net.knarcraft.stargate.portal.property;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.container.RelativeBlockVector;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.property.gate.Gate;
/**
* The portal structure is responsible for the physical properties of a portal

View File

@ -1,4 +1,4 @@
package net.knarcraft.stargate.portal;
package net.knarcraft.stargate.portal.property.gate;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.BlockLocation;
@ -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

@ -1,4 +1,4 @@
package net.knarcraft.stargate.portal;
package net.knarcraft.stargate.portal.property.gate;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.utility.GateReader;
@ -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;
}
@ -243,6 +262,7 @@ public class GateHandler {
loadGateFromJar("nethergate.gate", gateFolder);
loadGateFromJar("watergate.gate", gateFolder);
loadGateFromJar("endgate.gate", gateFolder);
loadGateFromJar("squarenetherglowstonegate.gate", gateFolder);
}
/**

View File

@ -1,4 +1,4 @@
package net.knarcraft.stargate.portal;
package net.knarcraft.stargate.portal.property.gate;
import net.knarcraft.stargate.container.RelativeBlockVector;

View File

@ -1,7 +1,8 @@
package net.knarcraft.stargate.portal;
package net.knarcraft.stargate.portal.teleporter;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.event.StargateEntityPortalEvent;
import net.knarcraft.stargate.portal.Portal;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
@ -26,8 +27,9 @@ public class EntityTeleporter extends Teleporter {
* Teleports an entity to this teleporter's portal
*
* @param origin <p>The portal the entity is teleporting from</p>
* @return <p>True if the entity was teleported. False otherwise</p>
*/
public void teleport(Portal origin) {
public boolean teleport(Portal origin) {
Location traveller = teleportingEntity.getLocation();
Location exit = getExit(teleportingEntity, traveller);
@ -38,7 +40,7 @@ public class EntityTeleporter extends Teleporter {
if (!origin.equals(portal)) {
exit = triggerEntityPortalEvent(origin, exit);
if (exit == null) {
return;
return false;
}
}
@ -46,6 +48,7 @@ public class EntityTeleporter extends Teleporter {
loadChunks();
teleportingEntity.teleport(exit);
return true;
}
/**

View File

@ -1,7 +1,8 @@
package net.knarcraft.stargate.portal;
package net.knarcraft.stargate.portal.teleporter;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.event.StargatePlayerPortalEvent;
import net.knarcraft.stargate.portal.Portal;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerMoveEvent;

View File

@ -1,9 +1,10 @@
package net.knarcraft.stargate.portal;
package net.knarcraft.stargate.portal.teleporter;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.container.ChunkUnloadRequest;
import net.knarcraft.stargate.container.RelativeBlockVector;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.utility.DirectionHelper;
import net.knarcraft.stargate.utility.EntityHelper;
import org.bukkit.Chunk;
@ -190,9 +191,9 @@ public abstract class Teleporter {
*/
private Location adjustExitLocation(Location traveller, Location exitLocation) {
if (exitLocation != null) {
BlockData blockData = portal.getWorld().getBlockAt(exitLocation).getBlockData();
if ((blockData instanceof Bisected && ((Bisected) blockData).getHalf() == Bisected.Half.BOTTOM) ||
(blockData instanceof Slab) && ((Slab) blockData).getType() == Slab.Type.BOTTOM) {
BlockData blockData = exitLocation.getBlock().getBlockData();
if ((blockData instanceof Bisected bisected && bisected.getHalf() == Bisected.Half.BOTTOM) ||
(blockData instanceof Slab slab && slab.getType() == Slab.Type.BOTTOM)) {
//Prevent traveller from spawning inside a slab
Stargate.debug("adjustExitLocation", "Added a block to get above a slab");
exitLocation.add(0, 1, 0);
@ -249,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>
*/
@ -263,12 +292,13 @@ 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);
scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> {
new EntityTeleporter(portal, creature).teleport(origin);
scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> creature.setLeashHolder(player), 3);
scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> creature.setLeashHolder(player), 6);
}, 2);
}
}
@ -279,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

@ -1,6 +1,8 @@
package net.knarcraft.stargate.portal;
package net.knarcraft.stargate.portal.teleporter;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.StargateGateConfig;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.utility.DirectionHelper;
import org.bukkit.Location;
import org.bukkit.World;
@ -37,9 +39,10 @@ public class VehicleTeleporter extends EntityTeleporter {
* calling this method.</p>
*
* @param origin <p>The portal the vehicle is teleporting from</p>
* @return <p>True if the vehicle was teleported. False otherwise</p>
*/
@Override
public void teleport(Portal origin) {
public boolean teleport(Portal origin) {
Location traveller = teleportingVehicle.getLocation();
Location exit = getExit(teleportingVehicle, traveller);
@ -59,12 +62,12 @@ public class VehicleTeleporter extends EntityTeleporter {
if (!origin.equals(portal)) {
exit = triggerEntityPortalEvent(origin, exit);
if (exit == null) {
return;
return false;
}
}
//Teleport the vehicle
teleportVehicle(exit, newVelocity, origin);
return teleportVehicle(exit, newVelocity, origin);
}
/**
@ -73,13 +76,19 @@ public class VehicleTeleporter extends EntityTeleporter {
* @param exit <p>The location the vehicle should be teleported to</p>
* @param newVelocity <p>The velocity to give the vehicle right after teleportation</p>
* @param origin <p>The portal the vehicle teleported from</p>
* @return <p>True if the vehicle was teleported. False otherwise</p>
*/
private void teleportVehicle(Location exit, Vector newVelocity, Portal origin) {
private boolean teleportVehicle(Location exit, Vector newVelocity, Portal origin) {
//Load chunks to make sure not to teleport to the void
loadChunks();
List<Entity> passengers = teleportingVehicle.getPassengers();
if (!passengers.isEmpty()) {
//Check if the passengers are allowed according to current config settings
if (!vehiclePassengersAllowed(passengers)) {
return false;
}
if (!(teleportingVehicle instanceof LivingEntity)) {
//Teleport a normal vehicle with passengers (minecart or boat)
putPassengersInNewVehicle(passengers, exit, newVelocity, origin);
@ -88,11 +97,62 @@ public class VehicleTeleporter extends EntityTeleporter {
teleportLivingVehicle(exit, passengers, origin);
}
} else {
//Check if teleportation of empty vehicles is enabled
if (!Stargate.getGateConfig().handleEmptyVehicles()) {
return false;
}
//Teleport an empty vehicle
teleportingVehicle.teleport(exit);
scheduler.scheduleSyncDelayedTask(Stargate.getInstance(),
() -> teleportingVehicle.setVelocity(newVelocity), 1);
}
return true;
}
/**
* Checks whether current config values allow the teleportation of the given passengers
*
* @param passengers <p>The passengers to teleport</p>
* @return <p>True if the passengers are allowed to teleport</p>
*/
private boolean vehiclePassengersAllowed(List<Entity> passengers) {
StargateGateConfig config = Stargate.getGateConfig();
//Don't teleport if the vehicle contains a creature and creature transportation is disabled
if (containsNonPlayer(passengers) && !config.handleCreatureTransportation()) {
return false;
}
//Don't teleport if the player does not contain a player and non-player vehicles is disabled
return containsPlayer(passengers) || config.handleNonPlayerVehicles();
}
/**
* Checks whether a list of entities contains any non-players
*
* @param entities <p>The list of entities to check</p>
* @return <p>True if at least one entity is not a player</p>
*/
private boolean containsNonPlayer(List<Entity> entities) {
for (Entity entity : entities) {
if (!(entity instanceof Player)) {
return true;
}
}
return false;
}
/**
* Checks whether a list of entities contains at least one player
*
* @param entities <p>The list of entities to check</p>
* @return <p>True if at least one player is present among the passengers</p>
*/
private boolean containsPlayer(List<Entity> entities) {
for (Entity entity : entities) {
if (entity instanceof Player) {
return true;
}
}
return false;
}
/**

View File

@ -30,8 +30,7 @@ public class StarGateThread implements Runnable {
for (Portal portal : openPortalsQueue) {
//Skip always open and non-open gates
if (portal.getOptions().isAlwaysOn() || portal.getOptions().isRandom() || portal.getOptions().isBungee() ||
!portal.isOpen()) {
if (portal.getOptions().isAlwaysOn() || !portal.isOpen()) {
continue;
}
if (time > portal.getTriggeredTime() + Stargate.getGateConfig().getOpenTime()) {

View File

@ -1,9 +1,10 @@
package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.PlayerTeleporter;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerMoveEvent;
@ -71,7 +72,7 @@ public final class BungeeHelper {
//Build the message data and send it over the SGBungee BungeeCord channel
dataOutputStream.writeUTF("Forward");
//Send the message to the server defined in the entrance portal's network line
dataOutputStream.writeUTF(entrancePortal.getNetwork());
dataOutputStream.writeUTF(stripColor(entrancePortal.getNetwork()));
//Specify the sub-channel/tag to make it recognizable on arrival
dataOutputStream.writeUTF(bungeeSubChannel);
//Write the length of the message
@ -102,7 +103,7 @@ public final class BungeeHelper {
//Send a connect-message to connect the player to the server defined in the entrance portal's network line
dataOutputStream.writeUTF("Connect");
dataOutputStream.writeUTF(entrancePortal.getNetwork());
dataOutputStream.writeUTF(stripColor(entrancePortal.getNetwork()));
//Send the plugin message
player.sendPluginMessage(Stargate.getInstance(), bungeeChannel, byteArrayOutputStream.toByteArray());
@ -181,7 +182,9 @@ public final class BungeeHelper {
public static boolean bungeeTeleport(Player player, Portal entrancePortal, PlayerMoveEvent event) {
//Check if bungee is actually enabled
if (!Stargate.getGateConfig().enableBungee()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("bungeeDisabled"));
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("bungeeDisabled"));
}
entrancePortal.getPortalOpener().closePortal(false);
return false;
}
@ -205,4 +208,14 @@ public final class BungeeHelper {
return true;
}
/**
* Strips all color tags from a string
*
* @param string <p>The string to strip color from</p>
* @return <p>The string without color codes</p>
*/
private static String stripColor(String string) {
return ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', string));
}
}

View File

@ -1,8 +1,11 @@
package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.EconomyConfig;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalOwner;
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

@ -28,6 +28,17 @@ public final class MaterialHelper {
material.equals(Material.DEAD_TUBE_CORAL_WALL_FAN);
}
/**
* Checks whether the given material is a container
*
* @param material <p>The material to check</p>
* @return <p>True if the material is a container</p>
*/
public static boolean isContainer(Material material) {
return Tag.SHULKER_BOXES.isTagged(material) || material == Material.CHEST ||
material == Material.TRAPPED_CHEST || material == Material.ENDER_CHEST;
}
/**
* Checks whether the given material can be used as a button
*
@ -35,8 +46,7 @@ public final class MaterialHelper {
* @return <p>True if the material can be used as a button</p>
*/
public static boolean isButtonCompatible(Material material) {
return Tag.BUTTONS.isTagged(material) || isWallCoral(material) || Tag.SHULKER_BOXES.isTagged(material) ||
material == Material.CHEST || material == Material.TRAPPED_CHEST || material == Material.ENDER_CHEST;
return Tag.BUTTONS.isTagged(material) || isWallCoral(material) || isContainer(material);
}
}

View File

@ -2,12 +2,14 @@ package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.event.StargateAccessEvent;
import net.knarcraft.stargate.portal.PlayerTeleporter;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalOption;
import net.knarcraft.stargate.portal.property.PortalOption;
import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerMoveEvent;
import static net.knarcraft.stargate.Stargate.getMaxNameNetworkLength;
/**
* Helper class for deciding which actions a player is allowed to perform
*/
@ -27,13 +29,15 @@ public final class PermissionHelper {
Portal destination = portal.getPortalActivator().getDestination();
//For an always open portal, no action is necessary
if (portal.getOptions().isAlwaysOn() || portal.getOptions().isRandom() || portal.getOptions().isBungee()) {
if (portal.getOptions().isAlwaysOn()) {
return;
}
//Destination is invalid or the same portal. Send an error message
if (destination == null || destination == portal) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("invalidMsg"));
if (!portal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("invalidMsg"));
}
return;
}
@ -49,19 +53,25 @@ public final class PermissionHelper {
//Deny access if another player has activated the portal, and it's still in use
if (!portal.getOptions().isFixed() && portal.getPortalActivator().isActive() &&
portal.getActivePlayer() != player) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
if (!portal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
}
return;
}
//Check if the player can use the private gate
if (portal.getOptions().isPrivate() && !PermissionHelper.canUsePrivatePortal(player, portal)) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
if (!portal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
}
return;
}
//Destination is currently in use by another player, blocking teleportation
if (destination.isOpen() && !destination.getOptions().isAlwaysOn()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("blockMsg"));
if (!portal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("blockMsg"));
}
return;
}
@ -97,12 +107,12 @@ public final class PermissionHelper {
boolean deny = false;
if (entrancePortal.getOptions().isBungee()) {
if (!PermissionHelper.canAccessServer(player, entrancePortal.getNetwork())) {
if (!PermissionHelper.canAccessServer(player, entrancePortal.getCleanNetwork())) {
//If the portal is a bungee portal, and the player cannot access the server, deny
Stargate.debug("cannotAccessPortal", "Cannot access server");
deny = true;
}
} else if (PermissionHelper.cannotAccessNetwork(player, entrancePortal.getNetwork())) {
} else if (PermissionHelper.cannotAccessNetwork(player, entrancePortal.getCleanNetwork())) {
//If the player does not have access to the network, deny
Stargate.debug("cannotAccessPortal", "Cannot access network");
deny = true;
@ -192,8 +202,8 @@ public final class PermissionHelper {
}
//Is able to create personal gates (Assumption is made they can also access them)
String playerName = player.getName();
if (playerName.length() > 11) {
playerName = playerName.substring(0, 11);
if (playerName.length() > getMaxNameNetworkLength()) {
playerName = playerName.substring(0, getMaxNameNetworkLength());
}
return !network.equals(playerName) || !hasPermission(player, "stargate.create.personal");
}
@ -233,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();
}
/**
@ -337,7 +347,7 @@ public final class PermissionHelper {
* @return <p>True if the player is allowed to destroy the portal</p>
*/
public static boolean canDestroyPortal(Player player, Portal portal) {
String network = portal.getNetwork();
String network = portal.getCleanNetwork();
//Use a special check for bungee portals
if (portal.getOptions().isBungee()) {
@ -374,7 +384,9 @@ public final class PermissionHelper {
//Not open for this player
if (!entrancePortal.getPortalOpener().isOpenFor(player)) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
}
new PlayerTeleporter(entrancePortal, player).teleport(entrancePortal, event);
return true;
}
@ -386,14 +398,16 @@ public final class PermissionHelper {
//Player cannot access portal
if (PermissionHelper.cannotAccessPortal(player, entrancePortal, destination)) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
}
new PlayerTeleporter(entrancePortal, player).teleport(entrancePortal, event);
entrancePortal.getPortalOpener().closePortal(false);
return true;
}
//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

@ -1,16 +1,25 @@
package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.BlockChangeRequest;
import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.portal.Gate;
import net.knarcraft.stargate.portal.GateHandler;
import net.knarcraft.stargate.container.RelativeBlockVector;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.PortalLocation;
import net.knarcraft.stargate.portal.PortalOptions;
import net.knarcraft.stargate.portal.PortalOwner;
import net.knarcraft.stargate.portal.PortalRegistry;
import net.knarcraft.stargate.portal.property.PortalLocation;
import net.knarcraft.stargate.portal.property.PortalOptions;
import net.knarcraft.stargate.portal.property.PortalOwner;
import net.knarcraft.stargate.portal.property.gate.Gate;
import net.knarcraft.stargate.portal.property.gate.GateHandler;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.block.data.Waterlogged;
import java.io.BufferedWriter;
import java.io.File;
@ -114,7 +123,9 @@ public final class PortalFileHelper {
builder.append(options.isShown()).append(':');
builder.append(options.isNoNetwork()).append(':');
builder.append(options.isRandom()).append(':');
builder.append(options.isBungee());
builder.append(options.isBungee()).append(':');
builder.append(options.isSilent()).append(':');
builder.append(options.hasNoSign());
}
/**
@ -147,14 +158,17 @@ public final class PortalFileHelper {
int lineIndex = 0;
try {
Scanner scanner = new Scanner(database);
boolean needsToSaveDatabase = false;
while (scanner.hasNextLine()) {
//Read the line and do whatever needs to be done
readPortalLine(scanner, ++lineIndex, world);
needsToSaveDatabase = readPortalLine(scanner, ++lineIndex, world) || needsToSaveDatabase;
}
scanner.close();
//Do necessary tasks after all portals have loaded
doPostLoadTasks(world);
Stargate.debug("PortalFileHelper::loadPortals", String.format("Finished loading portals for %s. " +
"Starting post loading tasks", world));
doPostLoadTasks(world, needsToSaveDatabase);
return true;
} catch (Exception e) {
Stargate.logSevere(String.format("Exception while reading stargates from %s: %d", database.getName(),
@ -170,24 +184,25 @@ public final class PortalFileHelper {
* @param scanner <p>The scanner to read</p>
* @param lineIndex <p>The index of the read line</p>
* @param world <p>The world for which portals are currently being read</p>
* @return <p>True if the read portal has changed and the world's database needs to be saved</p>
*/
private static void readPortalLine(Scanner scanner, int lineIndex, World world) {
private static boolean readPortalLine(Scanner scanner, int lineIndex, World world) {
String line = scanner.nextLine().trim();
//Ignore empty and comment lines
if (line.startsWith("#") || line.isEmpty()) {
return;
return false;
}
//Check if the min. required portal data is present
String[] portalData = line.split(":");
if (portalData.length < 8) {
Stargate.logInfo(String.format("Invalid line - %s", lineIndex));
return;
return false;
}
//Load the portal defined in the current line
loadPortal(portalData, world, lineIndex);
return loadPortal(portalData, world, lineIndex);
}
/**
@ -196,9 +211,10 @@ public final class PortalFileHelper {
* <p>This will open always on portals, print info about loaded stargates and re-draw portal signs for loaded
* portals.</p>
*
* @param world <p>The world portals have been loaded for</p>
* @param world <p>The world portals have been loaded for</p>
* @param needsToSaveDatabase <p>Whether the portal database's file needs to be updated</p>
*/
private static void doPostLoadTasks(World world) {
private static void doPostLoadTasks(World world, boolean needsToSaveDatabase) {
//Open any always-on portals. Do this here as it should be more efficient than in the loop.
PortalHandler.verifyAllPortals();
int portalCount = PortalRegistry.getAllPortals().size();
@ -210,7 +226,15 @@ public final class PortalFileHelper {
//Re-draw the signs in case a bug in the config prevented the portal from loading and has been fixed since
for (Portal portal : PortalRegistry.getAllPortals()) {
portal.drawSign();
if (portal.isRegistered()) {
portal.drawSign();
updatePortalButton(portal);
}
}
//Save the portals to disk to update with any changes
Stargate.debug("PortalFileHelper::doPostLoadTasks", String.format("Saving database for world %s", world));
if (needsToSaveDatabase) {
saveAllPortals(world);
}
}
@ -220,8 +244,9 @@ public final class PortalFileHelper {
* @param portalData <p>The array describing the portal</p>
* @param world <p>The world to create the portal in</p>
* @param lineIndex <p>The line index to report in case the user needs to fix an error</p>
* @return <p>True if the portal's data has changed and its database needs to be updated</p>
*/
private static void loadPortal(String[] portalData, World world, int lineIndex) {
private static boolean loadPortal(String[] portalData, World world, int lineIndex) {
//Load min. required portal data
String name = portalData[0];
BlockLocation button = (portalData[2].length() > 0) ? new BlockLocation(world, portalData[2]) : null;
@ -237,12 +262,13 @@ public final class PortalFileHelper {
if (gate == null) {
//Mark the sign as invalid to reduce some player confusion
markPortalWithInvalidGate(portalLocation, portalData[7], lineIndex);
return;
return false;
}
//Load extra portal data
String destination = (portalData.length > 8) ? portalData[8] : "";
String network = (portalData.length > 9 && !portalData[9].isEmpty()) ? portalData[9] : Stargate.getDefaultNetwork();
String network = (portalData.length > 9 && !portalData[9].isEmpty()) ? portalData[9] :
Stargate.getDefaultNetwork();
String ownerString = (portalData.length > 10) ? portalData[10] : "";
//Get the owner from the owner string
@ -253,8 +279,123 @@ public final class PortalFileHelper {
PortalHandler.getPortalOptions(portalData));
//Register the portal, and close it in case it wasn't properly closed when the server stopped
boolean buttonLocationChanged = updateButtonVector(portal);
PortalHandler.registerPortal(portal);
portal.getPortalOpener().closePortal(true);
return buttonLocationChanged;
}
/**
* Updates a portal's button if it does not match the correct material
*
* @param portal <p>The portal update the button of</p>
*/
private static void updatePortalButton(Portal portal) {
BlockLocation buttonLocation = getButtonLocation(portal);
if (portal.getOptions().isAlwaysOn()) {
//Clear button if not already air or water
if (MaterialHelper.isButtonCompatible(buttonLocation.getType())) {
Material newMaterial = decideRemovalMaterial(buttonLocation, portal);
Stargate.addBlockChangeRequest(new BlockChangeRequest(buttonLocation, newMaterial, null));
}
} else {
//Replace button if the material does not match
if (buttonLocation.getType() != portal.getGate().getPortalButton()) {
generatePortalButton(portal, DirectionHelper.getBlockFaceFromYaw(portal.getYaw()));
}
}
}
/**
* Decides the material to use for removing a portal's button/sign
*
* @param location <p>The location of the button/sign to replace</p>
* @param portal <p>The portal the button/sign belongs to</p>
* @return <p>The material to use for removing the button/sign</p>
*/
public static Material decideRemovalMaterial(BlockLocation location, Portal portal) {
//Get the blocks to each side of the location
Location leftLocation = location.getRelativeLocation(-1, 0, 0, portal.getYaw());
Location rightLocation = location.getRelativeLocation(1, 0, 0, portal.getYaw());
//If the block is water or is waterlogged, assume the portal is underwater
if (isUnderwater(leftLocation) || isUnderwater(rightLocation)) {
return Material.WATER;
} else {
return Material.AIR;
}
}
/**
* Checks whether the given location is underwater
*
* <p>If the location has a water block, or a block which is waterlogged, it will be considered underwater.</p>
*
* @param location <p>The location to check</p>
* @return <p>True if the location is underwater</p>
*/
private static boolean isUnderwater(Location location) {
BlockData blockData = location.getBlock().getBlockData();
return blockData.getMaterial() == Material.WATER ||
(blockData instanceof Waterlogged waterlogged && waterlogged.isWaterlogged());
}
/**
* Updates the button vector for the given portal
*
* <p>As the button vector isn't saved, it is null when the portal is loaded. This method allows it to be
* explicitly set when necessary.</p>
*
* @param portal <p>The portal to update the button vector for</p>
* @return <p>True if the calculated button location is not the same as the one in the portal file</p>
*/
private static boolean updateButtonVector(Portal portal) {
for (RelativeBlockVector control : portal.getGate().getLayout().getControls()) {
BlockLocation controlLocation = portal.getLocation().getTopLeft().getRelativeLocation(control,
portal.getYaw());
BlockLocation buttonLocation = controlLocation.getRelativeLocation(
new RelativeBlockVector(0, 0, 1), portal.getYaw());
if (!buttonLocation.equals(portal.getLocation().getSignLocation())) {
portal.getLocation().setButtonVector(control);
BlockLocation oldButtonLocation = portal.getStructure().getButton();
if (oldButtonLocation != null && !oldButtonLocation.equals(buttonLocation)) {
Stargate.addBlockChangeRequest(new BlockChangeRequest(oldButtonLocation, Material.AIR, null));
portal.getStructure().setButton(buttonLocation);
return true;
}
}
}
return false;
}
/**
* Generates a button for a portal
*
* @param portal <p>The portal to generate button for</p>
* @param buttonFacing <p>The direction the button should be facing</p>
*/
public static void generatePortalButton(Portal portal, BlockFace buttonFacing) {
//Go one block outwards to find the button's location rather than the control block's location
BlockLocation button = getButtonLocation(portal);
Directional buttonData = (Directional) Bukkit.createBlockData(portal.getGate().getPortalButton());
buttonData.setFacing(buttonFacing);
button.getBlock().setBlockData(buttonData);
portal.getStructure().setButton(button);
}
/**
* Gets the location of a portal's button
*
* @param portal <p>The portal to find the button for</p>
* @return <p>The location of the portal's button</p>
*/
private static BlockLocation getButtonLocation(Portal portal) {
BlockLocation topLeft = portal.getTopLeft();
RelativeBlockVector buttonVector = portal.getLocation().getButtonVector();
return topLeft.getRelativeLocation(buttonVector.addToVector(RelativeBlockVector.Property.OUT, 1),
portal.getYaw());
}
}

View File

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

View File

@ -24,4 +24,5 @@ usecost=economy.useCost
toowner=economy.toOwner
chargefreedestination=economy.chargeFreeDestination
freegatesgreen=economy.freeGatesGreen
CheckUpdates=
CheckUpdates=
economy.freeGatesGreen=economy.freeGatesColored

View File

@ -8,7 +8,10 @@
# 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
# 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)
@ -24,7 +27,8 @@
# 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
# freeGatesGreen - Whether a free gate in the destination list is drawn green
# freeGatesColored - Whether a free gate in the destination list is marked with a color
# freeGatesColor - The color to use for marking free gates
# I-------I-------I #
# Debug options #
# I-------I-------I #
@ -50,6 +54,9 @@ gates:
functionality:
enableBungee: false
handleVehicles: true
handleEmptyVehicles: true
handleCreatureTransportation: true
handleNonPlayerVehicles: true
handleLeashedCreatures: true
economy:
useEconomy: false
@ -58,7 +65,8 @@ economy:
useCost: 0
toOwner: false
chargeFreeDestination: true
freeGatesGreen: false
freeGatesColored: false
freeGatesColor: DARK_GREEN
debugging:
debug: false
permissionDebug: false

View File

@ -0,0 +1,13 @@
portal-open=NETHER_PORTAL
portal-closed=AIR
button=OAK_BUTTON
toowner=false
X=OBSIDIAN
-=GLOWSTONE
A=GLOWSTONE
XAX
X...X
-...-
X.*.X
XAX

View File

@ -35,3 +35,9 @@ bungeeDisabled=BungeeCord support is disabled.
bungeeDeny=You do not have permission to create BungeeCord gates.
bungeeEmpty=BungeeCord gates require both a destination and network.
bungeeSign=Teleport to
portalInfoTitle=[STARGATE INFO]
portalInfoName=Name: %name%
portalInfoDestination=Destination: %destination%
portalInfoNetwork=Network: %network%
portalInfoServer=Server: %server%

View File

@ -35,3 +35,9 @@ bungeeDisabled=BungeeCord støtte er slått av.
bungeeDeny=Du har ikke tillatelse til å opprette BungeeCord porter.
bungeeEmpty=BungeeCord porter behøver bade en destinasjon og et nettverk.
bungeeSign=Teleporter til
portalInfoTitle=[STJERNEPORT INFO]
portalInfoName=Navn: %name%
portalInfoDestination=Destinasjon: %destination%
portalInfoNetwork=Nettverk: %network%
portalInfoServer=Server: %server%

View File

@ -35,3 +35,9 @@ bungeeDisabled=BungeeCord støtte er slått av.
bungeeDeny=Du har ikkje løyve til å opprette BungeeCord portar.
bungeeEmpty=BungeeCord portar treng bade ein destinasjon og eit nettverk.
bungeeSign=Teleporter til
portalInfoTitle=[STJERNEPORT INFO]
portalInfoName=Namn: %name%
portalInfoDestination=Destinasjon: %destination%
portalInfoNetwork=Nettverk: %network%
portalInfoServer=Server: %server%

View File

@ -1,6 +1,6 @@
name: Stargate
main: net.knarcraft.stargate.Stargate
version: 0.9.0.4
version: 0.9.2.3
description: Stargate mod for Bukkit Revived
author: EpicKnarvik97
authors: [ Drakia, PseudoKnight, EpicKnarvik97 ]
@ -11,8 +11,8 @@ 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
@ -97,6 +97,8 @@ permissions:
stargate.option.show: true
stargate.option.nonetwork: true
stargate.option.random: true
stargate.option.silent: true
stargate.option.nosign: true
stargate.option.hidden:
description: Allows the creation of a hidden stargate
default: false
@ -121,6 +123,12 @@ permissions:
stargate.option.random:
description: Allows the creation of a stargate with a random destination
default: false
stargate.option.silent:
description: Allows the creation of a stargate which does not output anything to the chat
default: false
stargate.option.nosign:
description: Allows the creation of a stargate which has no sign
default: false
stargate.admin.hidden:
description: Allows this player to see all hidden stargates
default: false
@ -130,14 +138,18 @@ permissions:
stargate.admin.bungee:
description: Allows the creation and destruction of a stargate between BungeeCord servers
default: false
stargate.admin.config:
description: Allows the player to change config values from the chat
default: false
stargate.server:
description: Allows the creation of a BungeeCord stargate going to any server
default: false
stargate.admin:
description: Allow all admin features and commands (Hidden/Private bypass, BungeeCord, Reload)
description: Allow all admin features and commands (Hidden/Private bypass, BungeeCord, Reload, Config)
default: op
children:
stargate.admin.reload: true
stargate.admin.hidden: true
stargate.admin.private: true
stargate.admin.bungee: true
stargate.admin.bungee: true
stargate.admin.config: true

View File

@ -5,6 +5,8 @@ import be.seeseemelk.mockbukkit.ServerMock;
import be.seeseemelk.mockbukkit.WorldMock;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.RelativeBlockVector;
import net.knarcraft.stargate.portal.property.gate.GateHandler;
import net.knarcraft.stargate.portal.property.gate.GateLayout;
import org.bukkit.Material;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;