Compare commits
	
		
			175 Commits
		
	
	
		
			0.9.0.2
			...
			vertical-s
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 2dcf7b7af0 | |||
| af9142bb05 | |||
| 116e816a18 | |||
| 0f0b8b7087 | |||
| e4539c3623 | |||
| e1ca1fe8b0 | |||
| 9ac3c11345 | |||
| 13cdccfc1d | |||
| 6954d46af4 | |||
| a1f25a794e | |||
| 31b3423246 | |||
| a35c07dc9c | |||
| 5aed252181 | |||
| ef97da9177 | |||
| a26cc30092 | |||
| 4fda4c3905 | |||
| 2b23e6fc56 | |||
| c09063c49e | |||
| b5e2565626 | |||
| fbabe7b117 | |||
| 5e456a1326 | |||
| 11d3dc7a92 | |||
| 1c87d803ff | |||
| 2076fda4d1 | |||
| 524130c4e0 | |||
| ce5f3ef52f | |||
| cae34d395b | |||
| 643a48392b | |||
| 92c3eadf8f | |||
| 92f452df00 | |||
| 6eb7649e0d | |||
| 5c2cbaae58 | |||
| 0c69dc8991 | |||
| 68bed24137 | |||
| 5c1f9036c2 | |||
| 8488c5abdb | |||
| e3189e9ab2 | |||
| 8c334ff5f0 | |||
| 4dfce3d325 | |||
| 00462799b9 | |||
| 9e78e32db4 | |||
| 28bb6f2109 | |||
| 61b05bcce9 | |||
| 5f4a90aabb | |||
| a481ccf017 | |||
| 28d84450fb | |||
| 99bceb9165 | |||
| a521454020 | |||
| 6c32de59a8 | |||
| 497551d889 | |||
| 8643a44df6 | |||
| e7b711efcf | |||
| 56d59f0d2a | |||
| 248caee620 | |||
| 7f08763624 | |||
| 95293204d5 | |||
| 8a5c094ce1 | |||
| 5e79df9f44 | |||
| a3ed1058e6 | |||
| f70ba24e95 | |||
| f6438eb872 | |||
| 2bf5422b2a | |||
| f95ee0b85d | |||
| 1e06e0e01d | |||
| bddf8c55d5 | |||
| 99ee5c6978 | |||
| 05a5fb2160 | |||
| d9f535cd07 | |||
| 62952611b8 | |||
| 29fdc8f849 | |||
| 043c5f2408 | |||
| a74d47e999 | |||
| e86be3e848 | |||
| 366cd3107e | |||
| 02f6c6e9fc | |||
| 97670c9367 | |||
| 2773079a09 | |||
| 071f1895de | |||
| 4cae54e46f | |||
| 7d41b75bac | |||
| 404b4d0543 | |||
| 842fd9c452 | |||
| 2bb0e8670d | |||
| acbdcd3ce3 | |||
| 948f92f140 | |||
| 5d1d6ffaf0 | |||
| a7dc02eef0 | |||
| 9177773a0e | |||
| fc5bac937a | |||
| f8ae83bc08 | |||
| cfb4910977 | |||
| a61a03be33 | |||
| 445638a561 | |||
| 7f9dc6756b | |||
| b2bb995d7e | |||
| f92fd2de5d | |||
| 2ed0fe7817 | |||
| 27b964837f | |||
| 4b34ea3cf5 | |||
| 0740cd0a66 | |||
| bab51d76fd | |||
| 6ddc15eeef | |||
| 14511f558d | |||
| 32975ca35d | |||
| 6e7ac5dbb9 | |||
| 2b4d15dab4 | |||
| 22bb75d4df | |||
| ab9a118d49 | |||
| a80a8520ce | |||
| 48bb68d665 | |||
| 1247c54899 | |||
| 37ac3d4877 | |||
| 70495220eb | |||
| 10c3914a60 | |||
| 4699f717ec | |||
| 29c1a00fcd | |||
| 51f5420f9e | |||
| e1a3d2d560 | |||
| a84210d550 | |||
| 351d1762e7 | |||
| 2c53b7d2a6 | |||
| 42e02eb141 | |||
| ad310ddb9c | |||
| 3db630f60e | |||
| 7a03f49fb1 | |||
| 1c2cad2ec1 | |||
| b4d908eaa0 | |||
| 8546fd4f78 | |||
| 05328fc456 | |||
| aba70b669e | |||
| d5f4b87e9b | |||
| 85edaa4657 | |||
| 7c501cefe8 | |||
| 6466c7b0ff | |||
| 37cf75ada1 | |||
| 1ca2d36f5f | |||
| 01b2907b01 | |||
| 94b9848b70 | |||
| 2a17714e8d | |||
| 901f9c555c | |||
| 1efd89cdb0 | |||
| 88bb02dfbd | |||
| 4db6274dc3 | |||
| 9c963c9e8c | |||
| fc744b04dc | |||
| 1565707809 | |||
| 527562bc60 | |||
| 42e208402e | |||
| 7f91808baf | |||
| 0540498818 | |||
| 57ec7071cf | |||
| 5f2d7988e2 | |||
| ac25f2747f | |||
| aa3bb58b33 | |||
| ee0e66e9be | |||
| f90a09143f | |||
| 8c4cf16375 | |||
| 4566c15350 | |||
| 0297d62d6d | |||
| 80ff241d4b | |||
| f3292cff99 | |||
| 8c37b11484 | |||
| e0ac9b41e7 | |||
| e5c1ad1f3a | |||
| cab99e11b0 | |||
| 3c4d10ae3f | |||
| aff0082906 | |||
| 20c3c93c06 | |||
| dab9378a67 | |||
| 62661f65f4 | |||
| b8d98c26d4 | |||
| 8bb9c464d6 | |||
| 2b5d791581 | |||
| 2a61480684 | |||
| 91a0316e6e | 
							
								
								
									
										19
									
								
								HEADER
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								HEADER
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
Stargate - A portal plugin for Bukkit
 | 
			
		||||
Copyright (C) 2011 Shaun (sturmeh)
 | 
			
		||||
Copyright (C) 2011 Dinnerbone
 | 
			
		||||
Copyright (C) 2011-2013 Steven "Drakia" Scott <Contact@TheDgtl.net>
 | 
			
		||||
Copyright (C) 2015-2020 Michael Smith (PseudoKnight)
 | 
			
		||||
Copyright (C) 2021-2022 Kristian Knarvik (EpicKnarvik97)
 | 
			
		||||
 | 
			
		||||
This program is free software: you can redistribute it and/or modify
 | 
			
		||||
it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
(at your option) any later version.
 | 
			
		||||
 | 
			
		||||
This program is distributed in the hope that it will be useful,
 | 
			
		||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
GNU Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
							
								
								
									
										10
									
								
								Jenkinsfile
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								Jenkinsfile
									
									
									
									
										vendored
									
									
								
							@@ -1,7 +1,7 @@
 | 
			
		||||
pipeline {
 | 
			
		||||
    agent any
 | 
			
		||||
    tools {
 | 
			
		||||
        jdk 'JDK16'
 | 
			
		||||
        jdk 'JDK17'
 | 
			
		||||
    }
 | 
			
		||||
    stages {
 | 
			
		||||
        stage('Build') {
 | 
			
		||||
@@ -16,10 +16,16 @@ pipeline {
 | 
			
		||||
                sh 'mvn test'
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        stage('Verify') {
 | 
			
		||||
            steps {
 | 
			
		||||
                echo 'Verifying...'
 | 
			
		||||
                sh 'mvn verify -Dmaven.test.skip=true'
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        stage('Deploy') {
 | 
			
		||||
             steps {
 | 
			
		||||
                echo 'Deploying...'
 | 
			
		||||
                sh 'mvn verify -Dmaven.test.skip=true'
 | 
			
		||||
                sh 'mvn deploy -Dmaven.install.skip=true -Dmaven.test.skip=true'
 | 
			
		||||
                archiveArtifacts artifacts: '**/target/*.jar', fingerprint: true
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										245
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										245
									
								
								README.md
									
									
									
									
									
								
							@@ -3,16 +3,22 @@
 | 
			
		||||
Create gates that allow for instant-teleportation between large distances. Gates can be always-open or triggered; they
 | 
			
		||||
can share a network or be split into clusters; they can be hidden on a network or accessible to everybody.
 | 
			
		||||
 | 
			
		||||
- Player permissions -- let players build their own networks.
 | 
			
		||||
- Vault economy support -- can add costs for create, destroy and use.
 | 
			
		||||
- Ability to create custom gate configurations. Three different default gate configurations are available.
 | 
			
		||||
- Message customization
 | 
			
		||||
- Multiple built-in languages (de, en, es, fr, hu, it, nb-no, nl, nn-no, pt-br, ru)
 | 
			
		||||
- Teleport across worlds or servers (BungeeCord supported)
 | 
			
		||||
- Vehicle teleportation -- teleport minecarts, boats, horses, pigs and striders
 | 
			
		||||
- 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, ja, nb-no, nl, nn-no, pt-br, ru, zh_cn)
 | 
			
		||||
- **Teleport across worlds or servers** (BungeeCord supported)
 | 
			
		||||
- **Vehicle teleportation** -- teleport minecarts, boats, horses, pigs and striders
 | 
			
		||||
- **Leashed teleportation** -- teleport any creature in a leash with the player
 | 
			
		||||
- **Underwater portals** -- portals can be placed underwater as long as a waterproof button is used
 | 
			
		||||
- **API available** -- using the API, a lot of behavior can be changed
 | 
			
		||||
- **Button customization** -- a large amount of materials usable as buttons (buttons, wall corals, shulkers, chests)
 | 
			
		||||
- **Config commands** -- All main config values can be changed from the commandline
 | 
			
		||||
- **Color customization** -- Stargate signs can be colored in many ways. Colors can be set globally, or on a per sign
 | 
			
		||||
  type basis
 | 
			
		||||
- **RGB and dye support** -- Signs can use RGB colors (using hex codes) as their main and highlighting colors, and can
 | 
			
		||||
  also be dyed on a per-sign basis
 | 
			
		||||
 | 
			
		||||
## Background
 | 
			
		||||
 | 
			
		||||
@@ -20,6 +26,11 @@ This was originally TheDgtl's Bukkit port of the Stargate plugin for hMod by Din
 | 
			
		||||
of [PseudoKnight's fork](https://github.com/PseudoKnight/Stargate-Bukkit). This fork's main purpose is to create a clean
 | 
			
		||||
version of Stargate compliant with Spigot 1.17, even if it means changing the entire project's previous structure.
 | 
			
		||||
 | 
			
		||||
## License
 | 
			
		||||
 | 
			
		||||
Stargate is licensed under the GNU Lesser General Public License Version 3.0. This includes every source and resource
 | 
			
		||||
file. See the HEADER file for a more detailed license description.
 | 
			
		||||
 | 
			
		||||
## Migration
 | 
			
		||||
 | 
			
		||||
This plugin should be compatible with configurations from the Stargate plugin all the way back. The nethergate.gate
 | 
			
		||||
@@ -34,10 +45,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 +67,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 +88,13 @@ 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
 | 
			
		||||
  stargate.admin.dye -- Allows this player to change the dye of any stargate's sign
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Default Permissions
 | 
			
		||||
@@ -114,9 +127,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 +139,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 +216,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.
 | 
			
		||||
 | 
			
		||||
@@ -282,18 +303,21 @@ while the per-gate costs re defined in the .gate files. To define a certain cost
 | 
			
		||||
# Configuration
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
language - The language to use (Included languages: en, de, es, fr, hu, it, nb-no, nl, nn-no, pt-br, ru)
 | 
			
		||||
language - The language to use (Included languages: en, de, es, fr, hu, it, ja, nb-no, nl, nn-no, pt-br, ru, zh_cn)
 | 
			
		||||
adminUpdateAlert - Whether to alert admins about an available update when joining the server
 | 
			
		||||
folders:
 | 
			
		||||
  portalFolder - The folder your portal databases are saved in
 | 
			
		||||
  gateFolder - The folder containing your .gate files
 | 
			
		||||
gates:
 | 
			
		||||
  maxGatesEachNetwork - If non-zero, will define the maximum amount of gates allowed on any network.
 | 
			
		||||
  defaultGateNetwork - The default gate network
 | 
			
		||||
  exitVelocity - The velocity to give players exiting stargates, relative to the entry velocity (1 = same as entry velocity)
 | 
			
		||||
  cosmetic:
 | 
			
		||||
    rememberDestination - Whether to set the first destination as the last used destination for all gates
 | 
			
		||||
    sortNetworkDestinations - If true, network lists will be sorted alphabetically.
 | 
			
		||||
    mainSignColor - This allows you to specify the color of the gate signs.
 | 
			
		||||
    highlightSignColor - This allows you to specify the color of the sign markings.
 | 
			
		||||
    mainSignColor - This allows you to specify the color of the gate signs. Use a color code such as WHITE,BLACK,YELLOW or a hex color code such as '#ed76d9'. You need quotes around hex color codes.
 | 
			
		||||
    highlightSignColor - This allows you to specify the color of the sign markings. Use a color code such as WHITE,BLACK,YELLOW or a hex color code such as '#ed76d9'. You need quotes around hex color codes.
 | 
			
		||||
    perSignColors: - A list of per-sign color specifications. Format: "SIGN_TYPE:mainColor,highlight_color". The SIGN_TYPE is OAK for an oak sign, DARK_OAK for a dark oak sign and so on. The colors can be "default" to use the color specified in "mainSignColor" or "highlightSignColor", "inverted" to use the inverse color of the default color, a normal color such as BLACK,WHITE,YELLOW or a hex color code such as #ed76d9.
 | 
			
		||||
  integrity:
 | 
			
		||||
    destroyedByExplosion - Whether to destroy a stargate with explosions, or stop an explosion if it contains a gates controls.
 | 
			
		||||
    verifyPortals - Whether or not all the non-sign blocks are checked to match the gate layout when an old stargate is loaded at startup.
 | 
			
		||||
@@ -301,6 +325,11 @@ 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.
 | 
			
		||||
    enableCraftBookRemoveOnEjectFix - Whether to enable a fix that causes loss of NBT data, but allows vehicle teleportation to work when CraftBook's remove minecart/boat on eject setting is enabled
 | 
			
		||||
economy:
 | 
			
		||||
  useEconomy - Whether or not to enable Economy using Vault (must have the Vault plugin)
 | 
			
		||||
  createCost - The cost to create a stargate
 | 
			
		||||
@@ -308,15 +337,18 @@ 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
 | 
			
		||||
advanced:
 | 
			
		||||
  waitForPlayerAfterTeleportDelay - The amount of ticks to wait before adding a player as passenger of a vehicle. On slow servers, a value of 6 is required to avoid client glitches after teleporting on a vehicle.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
# Message Customization
 | 
			
		||||
 | 
			
		||||
It is possible to customize all the messages Stargate displays, including the [Stargate] prefix. You can find the
 | 
			
		||||
It is possible to customize all the messages Stargate displays, including the \[Stargate] prefix. You can find the
 | 
			
		||||
strings in plugins/Stargate/lang/chosenLanguage.txt.
 | 
			
		||||
 | 
			
		||||
If a string is removed, or left blank, it will default to the default english string. There are some special cases
 | 
			
		||||
@@ -363,10 +395,167 @@ 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.4.2] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Avoids a NullPointerException if Dynmap is present, but isn't properly loaded.
 | 
			
		||||
- Avoids some potential NullPointerExceptions related to Dynmap integration
 | 
			
		||||
- Fixes end portals hijacking BungeeCord teleportation
 | 
			
		||||
- Fixes a problem where a player might not be properly teleported from an end portal Stargate in the end to the
 | 
			
		||||
  over-world.
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.4.1] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Reverts to Spigot API 1.18
 | 
			
		||||
- Adds Dynmap integration
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.4.0] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Updates Stargate to 1.19
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.3.7] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Adds the Japanese language file provided by spigot user furplag
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.3.6] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Adds the simplified Chinese language file provided by spigot user YKDZ
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.3.5] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Fixes the wait for player delay being too low by default
 | 
			
		||||
- Performs some minor code optimizations and restructuring
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.3.4] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Includes passengers of passengers when teleporting entities
 | 
			
		||||
- Fixes a bug which caused Stargate to use more CPU for no reason
 | 
			
		||||
- Teleports boats/minecarts like other vehicles unless *enableCraftBookRemoveOnEjectFix* is enabled
 | 
			
		||||
- Adds the *waitForPlayerAfterTeleportDelay* config option which allows changing the delay between vehicle teleportation
 | 
			
		||||
  and the player being teleported to the vehicle
 | 
			
		||||
- Makes boats keep their wood type even when re-created
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.3.3] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Prevents Zombified Piglins from randomly spawning at Stargates
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.3.2] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Adds a config option to set the exit velocity of any players exiting a stargate
 | 
			
		||||
- Adjusts vehicle teleportation a bit to prevent passengers' exit rotation from being wrong
 | 
			
		||||
- Improves the checking for buggy double-clicks on non-button blocks
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.3.1] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Ignores the type of air when checking if a stargate is valid
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.3.0] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Adds support for RGB colors (use hex color codes)
 | 
			
		||||
- Adds support for dyed and glowing signs
 | 
			
		||||
- Adds support for specifying sign colors per sign type
 | 
			
		||||
- Adds a tab-completable config sub-command for easily changing per-sign colors
 | 
			
		||||
- Allows a per-sign color to be set as the inverse of the default color of the given type
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.2.5] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Updates Java version to JDK 17
 | 
			
		||||
- Updates Spigot API version to 1.18
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.2.4] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Adds update checking, which will display a notice in the console when updates are available
 | 
			
		||||
- Adds an alert about an available update when an admin joins the server
 | 
			
		||||
- Adds the adminUpdateAlert config option to allow the admin notices to be turned off
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.2.3] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Fixes a typo which caused both colors to change into the highlightSignColor
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.2.2] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Prevents teleportation of a player holding creatures on a leash when handleLeashedCreatures is disabled, to prevent
 | 
			
		||||
  players accidentally losing the creatures during teleportation
 | 
			
		||||
- Fixes a potential exception when a gate's open-block or closed-block is set to a material which isn't a block
 | 
			
		||||
- Fixes a potential exception when a portal without a sign has an invalid gate type
 | 
			
		||||
- Prevents loading of gate files using non-blocks as part of the border
 | 
			
		||||
- Prevents a player smuggling another player through a restricted stargate by sitting on a creature held in a lead by
 | 
			
		||||
  the first player
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.2.1] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Makes sure to only reload whatever is necessary when config values are changed using commands, instead of reloading
 | 
			
		||||
  the entire config file every time
 | 
			
		||||
- Protects portals from block placement when protectEntrance is enabled
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.2.0] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Increases max length of names and networks to 13 characters
 | 
			
		||||
- 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
 | 
			
		||||
  with the player through stargates, even if the player is in a vehicle. This behavior can be disabled in the config
 | 
			
		||||
  file.
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.0.3] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Adds a missing error message when a player in a vehicle cannot pay the teleportation fee
 | 
			
		||||
- Adds UUID migration to automatically update player names to UUID when possible
 | 
			
		||||
 | 
			
		||||
#### \[Version 0.9.0.2] EpicKnarvik97 fork
 | 
			
		||||
 | 
			
		||||
- Fixes a bug causing Stargates using NETHER_PORTAL blocks to generate nether portals in the nether.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										100
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								pom.xml
									
									
									
									
									
								
							@@ -4,7 +4,7 @@
 | 
			
		||||
 | 
			
		||||
    <groupId>net.knarcraft</groupId>
 | 
			
		||||
    <artifactId>Stargate</artifactId>
 | 
			
		||||
    <version>0.9.0.2</version>
 | 
			
		||||
    <version>0.9.4.3-SNAPSHOT</version>
 | 
			
		||||
 | 
			
		||||
    <licenses>
 | 
			
		||||
        <license>
 | 
			
		||||
@@ -15,70 +15,140 @@
 | 
			
		||||
 | 
			
		||||
    <properties>
 | 
			
		||||
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 | 
			
		||||
        <maven.compiler.source>16</maven.compiler.source>
 | 
			
		||||
        <maven.compiler.target>16</maven.compiler.target>
 | 
			
		||||
        <java.version>16</java.version>
 | 
			
		||||
    </properties>
 | 
			
		||||
 | 
			
		||||
    <repositories>
 | 
			
		||||
        <repository>
 | 
			
		||||
            <id>knarcraft-repo</id>
 | 
			
		||||
            <url>https://git.knarcraft.net/api/packages/EpicKnarvik97/maven</url>
 | 
			
		||||
        </repository>
 | 
			
		||||
        <repository>
 | 
			
		||||
            <id>spigot-repo</id>
 | 
			
		||||
            <url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
 | 
			
		||||
        </repository>
 | 
			
		||||
        <repository>
 | 
			
		||||
            <id>vault-repo</id>
 | 
			
		||||
            <url>http://nexus.hc.to/content/repositories/pub_releases</url>
 | 
			
		||||
            <url>https://nexus.hc.to/content/repositories/pub_releases</url>
 | 
			
		||||
        </repository>
 | 
			
		||||
        <repository>
 | 
			
		||||
            <id>dynmap</id>
 | 
			
		||||
            <url>https://repo.mikeprimm.com/</url>
 | 
			
		||||
        </repository>
 | 
			
		||||
        <repository>
 | 
			
		||||
            <id>papermc</id>
 | 
			
		||||
            <url>https://repo.papermc.io/repository/maven-public/</url>
 | 
			
		||||
        </repository>
 | 
			
		||||
    </repositories>
 | 
			
		||||
    <distributionManagement>
 | 
			
		||||
        <repository>
 | 
			
		||||
            <id>knarcraft-repo</id>
 | 
			
		||||
            <url>https://git.knarcraft.net/api/packages/EpicKnarvik97/maven</url>
 | 
			
		||||
        </repository>
 | 
			
		||||
        <snapshotRepository>
 | 
			
		||||
            <id>knarcraft-repo</id>
 | 
			
		||||
            <url>https://git.knarcraft.net/api/packages/EpicKnarvik97/maven</url>
 | 
			
		||||
        </snapshotRepository>
 | 
			
		||||
    </distributionManagement>
 | 
			
		||||
 | 
			
		||||
    <dependencies>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.spigotmc</groupId>
 | 
			
		||||
            <artifactId>spigot-api</artifactId>
 | 
			
		||||
            <version>1.17.1-R0.1-SNAPSHOT</version>
 | 
			
		||||
            <version>1.19.3-R0.1-SNAPSHOT</version>
 | 
			
		||||
            <scope>provided</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>net.milkbowl.vault</groupId>
 | 
			
		||||
            <artifactId>VaultAPI</artifactId>
 | 
			
		||||
            <version>1.7</version>
 | 
			
		||||
            <scope>provided</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.junit.jupiter</groupId>
 | 
			
		||||
            <artifactId>junit-jupiter-api</artifactId>
 | 
			
		||||
            <version>5.8.0-M1</version>
 | 
			
		||||
            <version>5.9.0</version>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.github.seeseemelk</groupId>
 | 
			
		||||
            <artifactId>MockBukkit-v1.17</artifactId>
 | 
			
		||||
            <version>1.7.0</version>
 | 
			
		||||
            <artifactId>MockBukkit-v1.18</artifactId>
 | 
			
		||||
            <version>2.85.2</version>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.jetbrains</groupId>
 | 
			
		||||
            <artifactId>annotations</artifactId>
 | 
			
		||||
            <version>19.0.0</version>
 | 
			
		||||
            <scope>compile</scope>
 | 
			
		||||
            <version>23.0.0</version>
 | 
			
		||||
            <scope>provided</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>junit</groupId>
 | 
			
		||||
            <artifactId>junit</artifactId>
 | 
			
		||||
            <version>4.13.1</version>
 | 
			
		||||
            <version>4.13.2</version>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>us.dynmap</groupId>
 | 
			
		||||
            <artifactId>dynmap-api</artifactId>
 | 
			
		||||
            <version>3.1-beta-2</version>
 | 
			
		||||
            <scope>provided</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>net.knarcraft</groupId>
 | 
			
		||||
            <artifactId>knarlib</artifactId>
 | 
			
		||||
            <version>1.0-SNAPSHOT</version>
 | 
			
		||||
            <scope>compile</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
    </dependencies>
 | 
			
		||||
 | 
			
		||||
    <build>
 | 
			
		||||
        <sourceDirectory>src/main/java</sourceDirectory>
 | 
			
		||||
        <plugins>
 | 
			
		||||
            <plugin>
 | 
			
		||||
                <groupId>org.apache.maven.plugins</groupId>
 | 
			
		||||
                <artifactId>maven-compiler-plugin</artifactId>
 | 
			
		||||
                <version>3.6.1</version>
 | 
			
		||||
                <version>3.8.1</version>
 | 
			
		||||
                <configuration>
 | 
			
		||||
                    <source>16</source>
 | 
			
		||||
                    <target>16</target>
 | 
			
		||||
                    <source>${java.version}</source>
 | 
			
		||||
                    <target>${java.version}</target>
 | 
			
		||||
                </configuration>
 | 
			
		||||
            </plugin>
 | 
			
		||||
            <plugin>
 | 
			
		||||
                <groupId>org.apache.maven.plugins</groupId>
 | 
			
		||||
                <artifactId>maven-shade-plugin</artifactId>
 | 
			
		||||
                <version>3.2.4</version>
 | 
			
		||||
                <executions>
 | 
			
		||||
                    <execution>
 | 
			
		||||
                        <phase>package</phase>
 | 
			
		||||
                        <goals>
 | 
			
		||||
                            <goal>shade</goal>
 | 
			
		||||
                        </goals>
 | 
			
		||||
                        <configuration>
 | 
			
		||||
                            <createDependencyReducedPom>false</createDependencyReducedPom>
 | 
			
		||||
                            <filters>
 | 
			
		||||
                                <filter>
 | 
			
		||||
                                    <artifact>net.knarcraft:knarlib</artifact>
 | 
			
		||||
                                    <includes>
 | 
			
		||||
                                        <include>net/knarcraft/knarlib/**</include>
 | 
			
		||||
                                    </includes>
 | 
			
		||||
                                </filter>
 | 
			
		||||
                                <filter>
 | 
			
		||||
                                    <excludes>
 | 
			
		||||
                                        <exclude>*.MF</exclude>
 | 
			
		||||
                                        <exclude>*.yml</exclude>
 | 
			
		||||
                                    </excludes>
 | 
			
		||||
                                </filter>
 | 
			
		||||
                            </filters>
 | 
			
		||||
                        </configuration>
 | 
			
		||||
                    </execution>
 | 
			
		||||
                </executions>
 | 
			
		||||
            </plugin>
 | 
			
		||||
        </plugins>
 | 
			
		||||
        <resources>
 | 
			
		||||
            <resource>
 | 
			
		||||
                <directory>src/main/resources</directory>
 | 
			
		||||
                <filtering>true</filtering>
 | 
			
		||||
            </resource>
 | 
			
		||||
        </resources>
 | 
			
		||||
    </build>
 | 
			
		||||
</project>
 | 
			
		||||
							
								
								
									
										180
									
								
								src/main/java/net/knarcraft/stargate/SimpleVectorOperation.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								src/main/java/net/knarcraft/stargate/SimpleVectorOperation.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,180 @@
 | 
			
		||||
package net.knarcraft.stargate;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.Axis;
 | 
			
		||||
import org.bukkit.block.BlockFace;
 | 
			
		||||
import org.bukkit.util.BlockVector;
 | 
			
		||||
import org.bukkit.util.Vector;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A class for performing rotational operations on vectors
 | 
			
		||||
 *
 | 
			
		||||
 * @author Kristian Knarvik
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class SimpleVectorOperation {
 | 
			
		||||
 | 
			
		||||
    private static final Map<BlockFace, Double> rotationAngles = new HashMap<>();
 | 
			
		||||
    private static final Map<BlockFace, Vector> rotationAxes = new HashMap<>();
 | 
			
		||||
    private static final Map<BlockFace, Axis> normalAxes = new HashMap<>();
 | 
			
		||||
    private static final BlockFace defaultDirection = BlockFace.SOUTH;
 | 
			
		||||
    private static final Axis defaultVerticalAxis = Axis.Y;
 | 
			
		||||
 | 
			
		||||
    private final Axis normalAxis;
 | 
			
		||||
    private boolean flipZAxis = false;
 | 
			
		||||
    private final BlockFace facing;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a vector operation to rotate vectors in the direction of a sign face
 | 
			
		||||
     *
 | 
			
		||||
     * @param signFace <p>The sign face of a gate's sign</p>
 | 
			
		||||
     */
 | 
			
		||||
    public SimpleVectorOperation(BlockFace signFace) {
 | 
			
		||||
        if (normalAxes.isEmpty()) {
 | 
			
		||||
            initializeIrisNormalAxes();
 | 
			
		||||
            initializeOperations();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.facing = signFace;
 | 
			
		||||
        this.normalAxis = normalAxes.get(signFace);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the block face of a sign given upon instantiation
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The block face of a sign given upon instantiation</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockFace getFacing() {
 | 
			
		||||
        return facing;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the normal axis orthogonal to the opening plane
 | 
			
		||||
     *
 | 
			
		||||
     * <p>Said another way, get the axis going directly towards or away from a stargate's entrance.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The normal axis orthogonal to the opening plane</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Axis getNormalAxis() {
 | 
			
		||||
        return normalAxis;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets whether to flip the Z- axis
 | 
			
		||||
     *
 | 
			
		||||
     * @param flipZAxis <p>Whether to flip the z-axis</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setFlipZAxis(boolean flipZAxis) {
 | 
			
		||||
        this.flipZAxis = flipZAxis;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Performs an operation from the real space to the vector space
 | 
			
		||||
     *
 | 
			
		||||
     * @param vector <p>The vector to perform the operation on</p>
 | 
			
		||||
     * @return vector <p>A new vector with the operation applied</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Vector performToAbstractSpaceOperation(@NotNull Vector vector) {
 | 
			
		||||
        Vector clone = vector.clone();
 | 
			
		||||
        clone.rotateAroundAxis(rotationAxes.get(facing), rotationAngles.get(facing));
 | 
			
		||||
        if (flipZAxis) {
 | 
			
		||||
            clone.setZ(-clone.getZ());
 | 
			
		||||
        }
 | 
			
		||||
        return clone;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Performs an operation from the vector space to the real space
 | 
			
		||||
     *
 | 
			
		||||
     * @param vector <p>The vector to perform the inverse operation on</p>
 | 
			
		||||
     * @return vector <p>A new vector with the operation applied</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Vector performToRealSpaceOperation(@NotNull Vector vector) {
 | 
			
		||||
        Vector clone = vector.clone();
 | 
			
		||||
        if (flipZAxis) {
 | 
			
		||||
            clone.setZ(-clone.getZ());
 | 
			
		||||
        }
 | 
			
		||||
        return clone.rotateAroundAxis(rotationAxes.get(facing), -rotationAngles.get(facing));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Performs an operation from the vector space to the real space
 | 
			
		||||
     *
 | 
			
		||||
     * @param vector <p>The vector to perform the inverse operation on</p>
 | 
			
		||||
     * @return vector <p>A new vector with the operation applied</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockVector performToRealSpaceOperation(@NotNull BlockVector vector) {
 | 
			
		||||
        return performToRealSpaceOperation((Vector) vector).toBlockVector();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the operations used for rotating to each block-face
 | 
			
		||||
     */
 | 
			
		||||
    private static void initializeOperations() {
 | 
			
		||||
        Map<Axis, Vector> axisVectors = new HashMap<>();
 | 
			
		||||
        axisVectors.put(Axis.Y, new Vector(0, 1, 0));
 | 
			
		||||
        axisVectors.put(Axis.X, new Vector(1, 0, 0));
 | 
			
		||||
        axisVectors.put(Axis.Z, new Vector(0, 0, 1));
 | 
			
		||||
 | 
			
		||||
        //Use the cross product to find the correct axis
 | 
			
		||||
        for (BlockFace face : normalAxes.keySet()) {
 | 
			
		||||
            Vector crossProduct = face.getDirection().crossProduct(defaultDirection.getDirection());
 | 
			
		||||
            if (face == defaultDirection || face == defaultDirection.getOppositeFace()) {
 | 
			
		||||
                rotationAxes.put(face, axisVectors.get(defaultVerticalAxis));
 | 
			
		||||
            } else if (Math.abs(crossProduct.getZ()) > 0) {
 | 
			
		||||
                rotationAxes.put(face, axisVectors.get(Axis.Z));
 | 
			
		||||
            } else if (Math.abs(crossProduct.getY()) > 0) {
 | 
			
		||||
                rotationAxes.put(face, axisVectors.get(Axis.Y));
 | 
			
		||||
            } else {
 | 
			
		||||
                rotationAxes.put(face, axisVectors.get(Axis.X));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        calculateRotations();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Calculates the required rotations based on the default rotation
 | 
			
		||||
     */
 | 
			
		||||
    private static void calculateRotations() {
 | 
			
		||||
        double halfRotation = Math.PI;
 | 
			
		||||
        double quarterRotation = halfRotation / 2;
 | 
			
		||||
 | 
			
		||||
        Vector defaultDirectionVector = defaultDirection.getDirection();
 | 
			
		||||
        boolean defaultDirectionPositive = defaultDirectionVector.getX() + defaultDirectionVector.getY() +
 | 
			
		||||
                defaultDirectionVector.getZ() > 0;
 | 
			
		||||
 | 
			
		||||
        for (BlockFace blockFace : normalAxes.keySet()) {
 | 
			
		||||
            if (defaultDirection == blockFace) {
 | 
			
		||||
                //The default direction requires no rotation
 | 
			
		||||
                rotationAngles.put(blockFace, 0d);
 | 
			
		||||
            } else if (defaultDirection.getOppositeFace() == blockFace) {
 | 
			
		||||
                //The opposite direction requires a half rotation
 | 
			
		||||
                rotationAngles.put(blockFace, halfRotation);
 | 
			
		||||
            } else {
 | 
			
		||||
                //All the other used directions require a quarter rotation
 | 
			
		||||
                Vector faceDirectionVector = blockFace.getDirection();
 | 
			
		||||
                boolean faceDirectionPositive = faceDirectionVector.getX() + faceDirectionVector.getY() +
 | 
			
		||||
                        faceDirectionVector.getZ() > 0;
 | 
			
		||||
                double rotation = defaultDirectionPositive && faceDirectionPositive ? quarterRotation : -quarterRotation;
 | 
			
		||||
                rotationAngles.put(blockFace, rotation);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the iris normal axes corresponding to each block face
 | 
			
		||||
     */
 | 
			
		||||
    private static void initializeIrisNormalAxes() {
 | 
			
		||||
        normalAxes.put(BlockFace.EAST, Axis.Z);
 | 
			
		||||
        normalAxes.put(BlockFace.WEST, Axis.Z);
 | 
			
		||||
        normalAxes.put(BlockFace.NORTH, Axis.X);
 | 
			
		||||
        normalAxes.put(BlockFace.SOUTH, Axis.X);
 | 
			
		||||
        normalAxes.put(BlockFace.UP, Axis.Y);
 | 
			
		||||
        normalAxes.put(BlockFace.DOWN, Axis.Y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package net.knarcraft.stargate;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.knarlib.util.UpdateChecker;
 | 
			
		||||
import net.knarcraft.stargate.command.CommandStarGate;
 | 
			
		||||
import net.knarcraft.stargate.command.StarGateTabCompleter;
 | 
			
		||||
import net.knarcraft.stargate.config.EconomyConfig;
 | 
			
		||||
@@ -10,6 +11,7 @@ import net.knarcraft.stargate.container.BlockChangeRequest;
 | 
			
		||||
import net.knarcraft.stargate.container.ChunkUnloadRequest;
 | 
			
		||||
import net.knarcraft.stargate.listener.BlockEventListener;
 | 
			
		||||
import net.knarcraft.stargate.listener.EntityEventListener;
 | 
			
		||||
import net.knarcraft.stargate.listener.EntitySpawnListener;
 | 
			
		||||
import net.knarcraft.stargate.listener.PlayerEventListener;
 | 
			
		||||
import net.knarcraft.stargate.listener.PluginEventListener;
 | 
			
		||||
import net.knarcraft.stargate.listener.PortalEventListener;
 | 
			
		||||
@@ -37,23 +39,45 @@ import java.util.Queue;
 | 
			
		||||
import java.util.logging.Level;
 | 
			
		||||
import java.util.logging.Logger;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Stargate - A portal plugin for Bukkit
 | 
			
		||||
Copyright (C) 2011 Shaun (sturmeh)
 | 
			
		||||
Copyright (C) 2011 Dinnerbone
 | 
			
		||||
Copyright (C) 2011-2013 Steven "Drakia" Scott <Contact@TheDgtl.net>
 | 
			
		||||
Copyright (C) 2015-2020 Michael Smith (PseudoKnight)
 | 
			
		||||
Copyright (C) 2021-2022 Kristian Knarvik (EpicKnarvik97)
 | 
			
		||||
 | 
			
		||||
The following license notice applies to all source and resource files in the Stargate project:
 | 
			
		||||
 | 
			
		||||
This program is free software: you can redistribute it and/or modify
 | 
			
		||||
it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
(at your option) any later version.
 | 
			
		||||
 | 
			
		||||
This program is distributed in the hope that it will be useful,
 | 
			
		||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
GNU Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The main class of the Stargate plugin
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class Stargate extends JavaPlugin {
 | 
			
		||||
 | 
			
		||||
    //Used for changing gate open/closed material.
 | 
			
		||||
    private static final Queue<BlockChangeRequest> blockChangeRequestQueue = new LinkedList<>();
 | 
			
		||||
    private static final Queue<ChunkUnloadRequest> chunkUnloadQueue = new PriorityQueue<>();
 | 
			
		||||
 | 
			
		||||
    private static Logger logger;
 | 
			
		||||
    private static Stargate stargate;
 | 
			
		||||
 | 
			
		||||
    private static String pluginVersion;
 | 
			
		||||
 | 
			
		||||
    private static PluginManager pluginManager;
 | 
			
		||||
    private static StargateConfig stargateConfig;
 | 
			
		||||
    private static String updateAvailable = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Empty constructor necessary for Spigot
 | 
			
		||||
@@ -74,6 +98,26 @@ public class Stargate extends JavaPlugin {
 | 
			
		||||
        super(loader, descriptionFile, dataFolder, file);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Stores information about an available update
 | 
			
		||||
     *
 | 
			
		||||
     * <p>If a non-null version is given, joining admins will be alerted about the new update.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param version <p>The version of the new update available</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void setUpdateAvailable(String version) {
 | 
			
		||||
        updateAvailable = version;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets information about an available update
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The version number if an update is available. Null otherwise</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String getUpdateAvailable() {
 | 
			
		||||
        return updateAvailable;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets an instance of this plugin
 | 
			
		||||
     *
 | 
			
		||||
@@ -139,6 +183,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
 | 
			
		||||
     *
 | 
			
		||||
@@ -245,24 +299,6 @@ public class Stargate extends JavaPlugin {
 | 
			
		||||
        return stargateConfig.getLanguageLoader().getBackupString(name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Replaces a list of variables in a string in the order they are given
 | 
			
		||||
     *
 | 
			
		||||
     * @param input  <p>The input containing the variables</p>
 | 
			
		||||
     * @param search <p>The variables to replace</p>
 | 
			
		||||
     * @param values <p>The replacement values</p>
 | 
			
		||||
     * @return <p>The input string with the search values replaced with the given values</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String replaceVars(String input, String[] search, String[] values) {
 | 
			
		||||
        if (search.length != values.length) {
 | 
			
		||||
            throw new IllegalArgumentException("The number of search values and replace values do not match.");
 | 
			
		||||
        }
 | 
			
		||||
        for (int i = 0; i < search.length; i++) {
 | 
			
		||||
            input = replaceVars(input, search[i], values[i]);
 | 
			
		||||
        }
 | 
			
		||||
        return input;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Replaces a variable in a string
 | 
			
		||||
     *
 | 
			
		||||
@@ -306,6 +342,9 @@ public class Stargate extends JavaPlugin {
 | 
			
		||||
        PluginDescriptionFile pluginDescriptionFile = this.getDescription();
 | 
			
		||||
        pluginManager = getServer().getPluginManager();
 | 
			
		||||
        FileConfiguration newConfig = this.getConfig();
 | 
			
		||||
        this.saveDefaultConfig();
 | 
			
		||||
        newConfig.options().copyDefaults(true);
 | 
			
		||||
 | 
			
		||||
        logger = Logger.getLogger("Minecraft");
 | 
			
		||||
        Server server = getServer();
 | 
			
		||||
        stargate = this;
 | 
			
		||||
@@ -324,6 +363,10 @@ public class Stargate extends JavaPlugin {
 | 
			
		||||
        runThreads();
 | 
			
		||||
 | 
			
		||||
        this.registerCommands();
 | 
			
		||||
 | 
			
		||||
        //Check for any available updates
 | 
			
		||||
        UpdateChecker.checkForUpdate(this, "https://api.spigotmc.org/legacy/update.php?resource=97784",
 | 
			
		||||
                Stargate::getPluginVersion, Stargate::setUpdateAvailable);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -349,6 +392,7 @@ public class Stargate extends JavaPlugin {
 | 
			
		||||
        pluginManager.registerEvents(new WorldEventListener(), this);
 | 
			
		||||
        pluginManager.registerEvents(new PluginEventListener(this), this);
 | 
			
		||||
        pluginManager.registerEvents(new TeleportEventListener(), this);
 | 
			
		||||
        pluginManager.registerEvents(new EntitySpawnListener(), this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -389,4 +433,5 @@ public class Stargate extends JavaPlugin {
 | 
			
		||||
    public static StargateConfig getStargateConfig() {
 | 
			
		||||
        return stargateConfig;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
package net.knarcraft.stargate.command;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import org.bukkit.ChatColor;
 | 
			
		||||
import net.md_5.bungee.api.ChatColor;
 | 
			
		||||
import org.bukkit.command.Command;
 | 
			
		||||
import org.bukkit.command.CommandExecutor;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
@@ -23,8 +23,9 @@ public class CommandAbout implements CommandExecutor {
 | 
			
		||||
        commandSender.sendMessage(textColor + "Go to " + highlightColor +
 | 
			
		||||
                "https://git.knarcraft.net/EpicKnarvik97/Stargate " + textColor + "for the official repository");
 | 
			
		||||
        String author = Stargate.getStargateConfig().getLanguageLoader().getString("author");
 | 
			
		||||
        if (!author.isEmpty())
 | 
			
		||||
        if (!author.isEmpty()) {
 | 
			
		||||
            commandSender.sendMessage(textColor + "Language created by " + highlightColor + author);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										429
									
								
								src/main/java/net/knarcraft/stargate/command/CommandConfig.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										429
									
								
								src/main/java/net/knarcraft/stargate/command/CommandConfig.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,429 @@
 | 
			
		||||
package net.knarcraft.stargate.command;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.config.ConfigOption;
 | 
			
		||||
import net.knarcraft.stargate.config.ConfigTag;
 | 
			
		||||
import net.knarcraft.stargate.config.DynmapManager;
 | 
			
		||||
import net.knarcraft.stargate.config.OptionDataType;
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import net.knarcraft.stargate.portal.PortalRegistry;
 | 
			
		||||
import net.knarcraft.stargate.portal.PortalSignDrawer;
 | 
			
		||||
import net.md_5.bungee.api.ChatColor;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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) {
 | 
			
		||||
                if (selectedOption.getDataType() == OptionDataType.STRING_LIST) {
 | 
			
		||||
                    updateListConfigValue(selectedOption, commandSender, args);
 | 
			
		||||
                } else {
 | 
			
		||||
                    updateConfigValue(selectedOption, commandSender, args[1]);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                //Display info and the current value of the given config value
 | 
			
		||||
                printConfigOptionValue(commandSender, selectedOption);
 | 
			
		||||
            }
 | 
			
		||||
            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.of(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 -> updateBooleanConfigValue(selectedOption, value, configuration);
 | 
			
		||||
            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 DOUBLE -> {
 | 
			
		||||
                Double doubleValue = getDouble(commandSender, selectedOption, value);
 | 
			
		||||
                if (doubleValue == null) {
 | 
			
		||||
                    return;
 | 
			
		||||
                } else {
 | 
			
		||||
                    Stargate.getStargateConfig().getConfigOptionsReference().put(selectedOption, doubleValue);
 | 
			
		||||
                    configuration.set(selectedOption.getConfigNode(), doubleValue);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            case STRING -> {
 | 
			
		||||
                updateStringConfigValue(selectedOption, commandSender, value);
 | 
			
		||||
                configuration.set(selectedOption.getConfigNode(), value);
 | 
			
		||||
            }
 | 
			
		||||
            default -> {
 | 
			
		||||
                Stargate.getStargateConfig().getConfigOptionsReference().put(selectedOption, value);
 | 
			
		||||
                configuration.set(selectedOption.getConfigNode(), value);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        saveAndReload(selectedOption, commandSender);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates a boolean config value
 | 
			
		||||
     *
 | 
			
		||||
     * @param selectedOption <p>The option which should be updated</p>
 | 
			
		||||
     * @param value          <p>The new value of the config option</p>
 | 
			
		||||
     * @param configuration  <p>The configuration file to save to</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void updateBooleanConfigValue(ConfigOption selectedOption, String value, FileConfiguration configuration) {
 | 
			
		||||
        boolean newValue = Boolean.parseBoolean(value);
 | 
			
		||||
        if (selectedOption == ConfigOption.ENABLE_BUNGEE && newValue != Stargate.getGateConfig().enableBungee()) {
 | 
			
		||||
            Stargate.getStargateConfig().startStopBungeeListener(newValue);
 | 
			
		||||
        }
 | 
			
		||||
        Stargate.getStargateConfig().getConfigOptionsReference().put(selectedOption, newValue);
 | 
			
		||||
        configuration.set(selectedOption.getConfigNode(), newValue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates a string config value
 | 
			
		||||
     *
 | 
			
		||||
     * @param selectedOption <p>The option which should be updated</p>
 | 
			
		||||
     * @param commandSender  <p>The command sender that changed the value</p>
 | 
			
		||||
     * @param value          <p>The new value of the config option</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void updateStringConfigValue(ConfigOption selectedOption, CommandSender commandSender, String value) {
 | 
			
		||||
        if (selectedOption == ConfigOption.GATE_FOLDER || selectedOption == ConfigOption.PORTAL_FOLDER ||
 | 
			
		||||
                selectedOption == ConfigOption.DEFAULT_GATE_NETWORK) {
 | 
			
		||||
            if (value.contains("../") || value.contains("..\\")) {
 | 
			
		||||
                commandSender.sendMessage(ChatColor.RED + "Path traversal characters cannot be used");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (ConfigTag.COLOR.isTagged(selectedOption)) {
 | 
			
		||||
            if (!registerColor(selectedOption, value, commandSender)) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (selectedOption == ConfigOption.LANGUAGE) {
 | 
			
		||||
            Stargate.getStargateConfig().getLanguageLoader().setChosenLanguage(value);
 | 
			
		||||
        }
 | 
			
		||||
        Stargate.getStargateConfig().getConfigOptionsReference().put(selectedOption, value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates a config value
 | 
			
		||||
     *
 | 
			
		||||
     * @param selectedOption <p>The option which should be updated</p>
 | 
			
		||||
     * @param commandSender  <p>The command sender that changed the value</p>
 | 
			
		||||
     * @param arguments      <p>The arguments for the new config option</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void updateListConfigValue(ConfigOption selectedOption, CommandSender commandSender, String[] arguments) {
 | 
			
		||||
        FileConfiguration configuration = Stargate.getInstance().getConfig();
 | 
			
		||||
 | 
			
		||||
        if (selectedOption == ConfigOption.PER_SIGN_COLORS) {
 | 
			
		||||
            if (arguments.length < 4) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(commandSender, "Usage: /sg config perSignColors " +
 | 
			
		||||
                        "<SIGN_TYPE> <MAIN_COLOR> <HIGHLIGHTING_COLOR>");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            String colorString = parsePerSignColorInput(commandSender, arguments);
 | 
			
		||||
            if (colorString == null) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Update the per-sign colors according to input
 | 
			
		||||
            updatePerSignColors(arguments[1], colorString, configuration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        saveAndReload(selectedOption, commandSender);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses the input given for changing the per-color string
 | 
			
		||||
     *
 | 
			
		||||
     * @param commandSender <p>The command sender that triggered the command</p>
 | 
			
		||||
     * @param arguments     <p>The arguments given by the user</p>
 | 
			
		||||
     * @return <p>The per-sign color string to update with, or null if the input was invalid</p>
 | 
			
		||||
     */
 | 
			
		||||
    private String parsePerSignColorInput(CommandSender commandSender, String[] arguments) {
 | 
			
		||||
        //Make sure the sign type is an actual sign
 | 
			
		||||
        if (Material.matchMaterial(arguments[1] + "_SIGN") == null) {
 | 
			
		||||
            Stargate.getMessageSender().sendErrorMessage(commandSender, "The given sign type is invalid");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        String colorString = arguments[1] + ":";
 | 
			
		||||
 | 
			
		||||
        //Validate the colors given by the user
 | 
			
		||||
        String[] errorMessage = new String[]{"The given main sign color is invalid!", "The given highlight sign color is invalid!"};
 | 
			
		||||
        String[] newColors = new String[2];
 | 
			
		||||
        for (int i = 0; i < 2; i++) {
 | 
			
		||||
            if (validatePerSignColor(arguments[i + 2])) {
 | 
			
		||||
                newColors[i] = arguments[i + 2];
 | 
			
		||||
            } else {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(commandSender, errorMessage[i]);
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        colorString += String.join(",", newColors);
 | 
			
		||||
        return colorString;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the per-sign colors with the given input
 | 
			
		||||
     *
 | 
			
		||||
     * @param signType      <p>The sign type that is updated</p>
 | 
			
		||||
     * @param colorString   <p>The new color string to replace any previous value with</p>
 | 
			
		||||
     * @param configuration <p>The file configuration to update with the new per-sign colors</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void updatePerSignColors(String signType, String colorString, FileConfiguration configuration) {
 | 
			
		||||
        List<String> newColorStrings = new ArrayList<>();
 | 
			
		||||
        List<?> oldColors = (List<?>) Stargate.getStargateConfig().getConfigOptionsReference().get(ConfigOption.PER_SIGN_COLORS);
 | 
			
		||||
        for (Object object : oldColors) {
 | 
			
		||||
            newColorStrings.add(String.valueOf(object));
 | 
			
		||||
        }
 | 
			
		||||
        newColorStrings.removeIf((item) -> item.startsWith(signType));
 | 
			
		||||
        newColorStrings.add(colorString);
 | 
			
		||||
 | 
			
		||||
        Stargate.getStargateConfig().getConfigOptionsReference().put(ConfigOption.PER_SIGN_COLORS, newColorStrings);
 | 
			
		||||
        configuration.set(ConfigOption.PER_SIGN_COLORS.getConfigNode(), newColorStrings);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Tries to validate one of the colors given when changing per-sign colors
 | 
			
		||||
     *
 | 
			
		||||
     * @param color <p>The color chosen by the user</p>
 | 
			
		||||
     * @return <p>True if the given color is valid</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean validatePerSignColor(String color) {
 | 
			
		||||
        ChatColor newHighlightColor = parseColor(color);
 | 
			
		||||
        return newHighlightColor != null || color.equalsIgnoreCase("default") ||
 | 
			
		||||
                color.equalsIgnoreCase("inverted");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Saves the configuration file and reloads as necessary
 | 
			
		||||
     *
 | 
			
		||||
     * @param selectedOption <p>The config option that was changed</p>
 | 
			
		||||
     * @param commandSender  <p>The command sender that executed the config command</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void saveAndReload(ConfigOption selectedOption, CommandSender commandSender) {
 | 
			
		||||
        //Save the config file and reload if necessary
 | 
			
		||||
        Stargate.getInstance().saveConfig();
 | 
			
		||||
 | 
			
		||||
        Stargate.getMessageSender().sendSuccessMessage(commandSender, "Config updated");
 | 
			
		||||
 | 
			
		||||
        //Reload whatever is necessary
 | 
			
		||||
        reloadIfNecessary(commandSender, selectedOption);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Registers the chat color if
 | 
			
		||||
     *
 | 
			
		||||
     * @param selectedOption <p>The option to change</p>
 | 
			
		||||
     * @param commandSender  <p>The command sender to alert if the color is invalid</p>
 | 
			
		||||
     * @param value          <p>The new option value</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean registerColor(ConfigOption selectedOption, String value, CommandSender commandSender) {
 | 
			
		||||
        ChatColor parsedColor = parseColor(value);
 | 
			
		||||
        if (parsedColor == null) {
 | 
			
		||||
            commandSender.sendMessage(ChatColor.RED + "Invalid color given");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (selectedOption == ConfigOption.FREE_GATES_COLOR) {
 | 
			
		||||
            PortalSignDrawer.setFreeColor(parsedColor);
 | 
			
		||||
        } else if (selectedOption == ConfigOption.MAIN_SIGN_COLOR) {
 | 
			
		||||
            PortalSignDrawer.setMainColor(parsedColor);
 | 
			
		||||
        } else if (selectedOption == ConfigOption.HIGHLIGHT_SIGN_COLOR) {
 | 
			
		||||
            PortalSignDrawer.setHighlightColor(parsedColor);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses a chat color
 | 
			
		||||
     *
 | 
			
		||||
     * @param value <p>The value to parse</p>
 | 
			
		||||
     * @return <p>The parsed color or null</p>
 | 
			
		||||
     */
 | 
			
		||||
    private ChatColor parseColor(String value) {
 | 
			
		||||
        try {
 | 
			
		||||
            return ChatColor.of(value.toUpperCase());
 | 
			
		||||
        } catch (IllegalArgumentException | NullPointerException ignored) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets an integer from a string
 | 
			
		||||
     *
 | 
			
		||||
     * @param commandSender  <p>The command sender that sent the config command</p>
 | 
			
		||||
     * @param selectedOption <p>The option the command sender is trying to change</p>
 | 
			
		||||
     * @param value          <p>The value given</p>
 | 
			
		||||
     * @return <p>An integer, or null if it was invalid</p>
 | 
			
		||||
     */
 | 
			
		||||
    private Integer getInteger(CommandSender commandSender, ConfigOption selectedOption, String value) {
 | 
			
		||||
        try {
 | 
			
		||||
            int intValue = Integer.parseInt(value);
 | 
			
		||||
 | 
			
		||||
            if ((selectedOption == ConfigOption.USE_COST || selectedOption == ConfigOption.CREATE_COST) && intValue < 0) {
 | 
			
		||||
                commandSender.sendMessage(ChatColor.RED + "This config option cannot be negative.");
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return intValue;
 | 
			
		||||
        } catch (NumberFormatException exception) {
 | 
			
		||||
            commandSender.sendMessage(ChatColor.RED + "Invalid number given");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a double from a string
 | 
			
		||||
     *
 | 
			
		||||
     * @param commandSender  <p>The command sender that sent the config command</p>
 | 
			
		||||
     * @param selectedOption <p>The option the command sender is trying to change</p>
 | 
			
		||||
     * @param value          <p>The value given</p>
 | 
			
		||||
     * @return <p>A double, or null if it was invalid</p>
 | 
			
		||||
     */
 | 
			
		||||
    private Double getDouble(CommandSender commandSender, ConfigOption selectedOption, String value) {
 | 
			
		||||
        try {
 | 
			
		||||
            double doubleValue = Double.parseDouble(value);
 | 
			
		||||
 | 
			
		||||
            if (selectedOption == ConfigOption.EXIT_VELOCITY && doubleValue < 0) {
 | 
			
		||||
                commandSender.sendMessage(ChatColor.RED + "This config option cannot be negative.");
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return doubleValue;
 | 
			
		||||
        } catch (NumberFormatException exception) {
 | 
			
		||||
            commandSender.sendMessage(ChatColor.RED + "Invalid number given");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reloads the config if necessary
 | 
			
		||||
     *
 | 
			
		||||
     * @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.requiresColorReload(configOption)) {
 | 
			
		||||
                Stargate.getStargateConfig().getStargateGateConfig().loadPerSignColors();
 | 
			
		||||
            }
 | 
			
		||||
            if (ConfigTag.requiresPortalReload(configOption)) {
 | 
			
		||||
                //Just unload and reload the portals
 | 
			
		||||
                Stargate.getStargateConfig().unloadAllPortals();
 | 
			
		||||
                Stargate.getStargateConfig().loadAllPortals();
 | 
			
		||||
            }
 | 
			
		||||
            if (ConfigTag.requiresLanguageReload(configOption)) {
 | 
			
		||||
                //Reload the language loader
 | 
			
		||||
                Stargate.getStargateConfig().getLanguageLoader().reload();
 | 
			
		||||
                //Re-draw all portal signs
 | 
			
		||||
                for (Portal portal : PortalRegistry.getAllPortals()) {
 | 
			
		||||
                    portal.drawSign();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (ConfigTag.requiresEconomyReload(configOption)) {
 | 
			
		||||
                //Load or unload Vault and Economy as necessary
 | 
			
		||||
                Stargate.getStargateConfig().reloadEconomy();
 | 
			
		||||
            }
 | 
			
		||||
            if (ConfigTag.requiresDynmapReload(configOption)) {
 | 
			
		||||
                //Regenerate all Dynmap markers
 | 
			
		||||
                DynmapManager.addAllPortalMarkers();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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) {
 | 
			
		||||
        Object defaultValue = option.getDefaultValue();
 | 
			
		||||
        String stringValue = String.valueOf(defaultValue);
 | 
			
		||||
        if (option.getDataType() == OptionDataType.STRING_LIST) {
 | 
			
		||||
            stringValue = "[" + String.join(",", (String[]) defaultValue) + "]";
 | 
			
		||||
        }
 | 
			
		||||
        return ChatColor.GOLD + option.getName() + ChatColor.WHITE + " - " + ChatColor.GREEN + option.getDescription() +
 | 
			
		||||
                ChatColor.DARK_GRAY + " (Default: " + ChatColor.GRAY + stringValue + ChatColor.DARK_GRAY + ")";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,12 +1,14 @@
 | 
			
		||||
package net.knarcraft.stargate.command;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import org.bukkit.ChatColor;
 | 
			
		||||
import net.md_5.bungee.api.ChatColor;
 | 
			
		||||
import org.bukkit.command.Command;
 | 
			
		||||
import org.bukkit.command.CommandExecutor;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This command represents any command which starts with stargate
 | 
			
		||||
 *
 | 
			
		||||
@@ -23,6 +25,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 = Arrays.copyOfRange(args, 1, args.length);
 | 
			
		||||
                return new CommandConfig().onCommand(commandSender, command, s, subArgs);
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -31,4 +36,5 @@ public class CommandStarGate implements CommandExecutor {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,236 @@
 | 
			
		||||
package net.knarcraft.stargate.command;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.config.ConfigOption;
 | 
			
		||||
import net.knarcraft.stargate.config.OptionDataType;
 | 
			
		||||
import net.md_5.bungee.api.ChatColor;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
import org.bukkit.Tag;
 | 
			
		||||
import org.bukkit.command.Command;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
import org.bukkit.command.TabCompleter;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static net.knarcraft.knarlib.util.TabCompletionHelper.filterMatchingStartsWith;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This is the completer for stargates config sub-command (/sg config)
 | 
			
		||||
 */
 | 
			
		||||
public class ConfigTabCompleter implements TabCompleter {
 | 
			
		||||
 | 
			
		||||
    private List<String> signTypes;
 | 
			
		||||
    private List<String> booleans;
 | 
			
		||||
    private List<String> integers;
 | 
			
		||||
    private List<String> chatColors;
 | 
			
		||||
    private List<String> languages;
 | 
			
		||||
    private List<String> extendedColors;
 | 
			
		||||
    private List<String> doubles;
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
 | 
			
		||||
                                      @NotNull String[] args) {
 | 
			
		||||
        if (signTypes == null || booleans == null || integers == null || chatColors == null || languages == null) {
 | 
			
		||||
            initializeAutoCompleteLists();
 | 
			
		||||
        }
 | 
			
		||||
        if (args.length > 1) {
 | 
			
		||||
            ConfigOption selectedOption = ConfigOption.getByName(args[0]);
 | 
			
		||||
            if (selectedOption == null) {
 | 
			
		||||
                return new ArrayList<>();
 | 
			
		||||
            } else if (selectedOption.getDataType() == OptionDataType.STRING_LIST) {
 | 
			
		||||
                return getPossibleStringListOptionValues(selectedOption, args);
 | 
			
		||||
            } else {
 | 
			
		||||
                return getPossibleOptionValues(selectedOption, args[1]);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            List<String> configOptionNames = new ArrayList<>();
 | 
			
		||||
            for (ConfigOption option : ConfigOption.values()) {
 | 
			
		||||
                configOptionNames.add(option.getName());
 | 
			
		||||
            }
 | 
			
		||||
            return filterMatchingStartsWith(configOptionNames, args[0]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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) {
 | 
			
		||||
        switch (selectedOption) {
 | 
			
		||||
            case LANGUAGE:
 | 
			
		||||
                //Return available languages
 | 
			
		||||
                return filterMatchingStartsWith(languages, 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 filterMatchingStartsWith(chatColors, typedText);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //If the config value is a boolean, show the two boolean values
 | 
			
		||||
        if (selectedOption.getDataType() == OptionDataType.BOOLEAN) {
 | 
			
		||||
            return filterMatchingStartsWith(booleans, typedText);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //If the config value is an integer, display some valid numbers
 | 
			
		||||
        if (selectedOption.getDataType() == OptionDataType.INTEGER) {
 | 
			
		||||
            if (typedText.trim().isEmpty()) {
 | 
			
		||||
                return integers;
 | 
			
		||||
            } else {
 | 
			
		||||
                return new ArrayList<>();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //If the config value is a double, display some valid numbers
 | 
			
		||||
        if (selectedOption.getDataType() == OptionDataType.DOUBLE) {
 | 
			
		||||
            if (typedText.trim().isEmpty()) {
 | 
			
		||||
                return doubles;
 | 
			
		||||
            } else {
 | 
			
		||||
                return new ArrayList<>();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get possible values for the selected string list option
 | 
			
		||||
     *
 | 
			
		||||
     * @param selectedOption <p>The selected option</p>
 | 
			
		||||
     * @param args           <p>The arguments given by the user</p>
 | 
			
		||||
     * @return <p>Some or all of the valid values for the option</p>
 | 
			
		||||
     */
 | 
			
		||||
    private List<String> getPossibleStringListOptionValues(ConfigOption selectedOption, String[] args) {
 | 
			
		||||
        if (selectedOption == ConfigOption.PER_SIGN_COLORS) {
 | 
			
		||||
            return getPerSignColorCompletion(args);
 | 
			
		||||
        } else {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the tab completion values for completing the per-sign color text
 | 
			
		||||
     *
 | 
			
		||||
     * @param args <p>The arguments given by the user</p>
 | 
			
		||||
     * @return <p>The options to give the user</p>
 | 
			
		||||
     */
 | 
			
		||||
    private List<String> getPerSignColorCompletion(String[] args) {
 | 
			
		||||
        if (args.length < 3) {
 | 
			
		||||
            return filterMatchingStartsWith(signTypes, args[1]);
 | 
			
		||||
        } else if (args.length < 4) {
 | 
			
		||||
            return filterMatchingStartsWith(extendedColors, args[2]);
 | 
			
		||||
        } else if (args.length < 5) {
 | 
			
		||||
            return filterMatchingStartsWith(extendedColors, args[3]);
 | 
			
		||||
        }
 | 
			
		||||
        return new ArrayList<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Puts a single string value into a string list
 | 
			
		||||
     *
 | 
			
		||||
     * @param value <p>The string to make into a list</p>
 | 
			
		||||
     * @return <p>A list containing the string value</p>
 | 
			
		||||
     */
 | 
			
		||||
    private List<String> putStringInList(String value) {
 | 
			
		||||
        List<String> list = new ArrayList<>();
 | 
			
		||||
        list.add(value);
 | 
			
		||||
        return list;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes all lists of auto-completable values
 | 
			
		||||
     */
 | 
			
		||||
    private void initializeAutoCompleteLists() {
 | 
			
		||||
        booleans = new ArrayList<>();
 | 
			
		||||
        booleans.add("true");
 | 
			
		||||
        booleans.add("false");
 | 
			
		||||
 | 
			
		||||
        integers = new ArrayList<>();
 | 
			
		||||
        integers.add("0");
 | 
			
		||||
        integers.add("5");
 | 
			
		||||
 | 
			
		||||
        signTypes = new ArrayList<>();
 | 
			
		||||
        for (Material material : Material.values()) {
 | 
			
		||||
            if (Tag.STANDING_SIGNS.isTagged(material)) {
 | 
			
		||||
                signTypes.add(material.toString().replace("_SIGN", ""));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        getColors();
 | 
			
		||||
        initializeLanguages();
 | 
			
		||||
 | 
			
		||||
        extendedColors = new ArrayList<>(chatColors);
 | 
			
		||||
        extendedColors.add("default");
 | 
			
		||||
        extendedColors.add("inverted");
 | 
			
		||||
 | 
			
		||||
        doubles = new ArrayList<>();
 | 
			
		||||
        doubles.add("5");
 | 
			
		||||
        doubles.add("1");
 | 
			
		||||
        doubles.add("0.5");
 | 
			
		||||
        doubles.add("0.1");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the list of chat colors
 | 
			
		||||
     */
 | 
			
		||||
    private void getColors() {
 | 
			
		||||
        chatColors = new ArrayList<>();
 | 
			
		||||
        for (ChatColor color : getChatColors()) {
 | 
			
		||||
            chatColors.add(color.getName());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets available chat colors
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The available chat colors</p>
 | 
			
		||||
     */
 | 
			
		||||
    private List<ChatColor> getChatColors() {
 | 
			
		||||
        List<ChatColor> chatColors = new ArrayList<>();
 | 
			
		||||
        char[] colors = new char[]{'a', 'b', 'c', 'd', 'e', 'f', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
 | 
			
		||||
        for (char color : colors) {
 | 
			
		||||
            chatColors.add(ChatColor.getByChar(color));
 | 
			
		||||
        }
 | 
			
		||||
        chatColors.add(ChatColor.of("#ed76d9"));
 | 
			
		||||
        chatColors.add(ChatColor.of("#ffecb7"));
 | 
			
		||||
        return chatColors;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the list of all available languages
 | 
			
		||||
     */
 | 
			
		||||
    private void initializeLanguages() {
 | 
			
		||||
        languages = new ArrayList<>();
 | 
			
		||||
        languages.add("de");
 | 
			
		||||
        languages.add("en");
 | 
			
		||||
        languages.add("es");
 | 
			
		||||
        languages.add("fr");
 | 
			
		||||
        languages.add("hu");
 | 
			
		||||
        languages.add("it");
 | 
			
		||||
        languages.add("ja");
 | 
			
		||||
        languages.add("nb-no");
 | 
			
		||||
        languages.add("nl");
 | 
			
		||||
        languages.add("nn-no");
 | 
			
		||||
        languages.add("pt-br");
 | 
			
		||||
        languages.add("ru");
 | 
			
		||||
        languages.add("zh_cn");
 | 
			
		||||
        //TODO: Generate this list dynamically by listing the language files in the jar and adding the user's custom 
 | 
			
		||||
        // language files
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -3,10 +3,12 @@ package net.knarcraft.stargate.command;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -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 = Arrays.copyOfRange(args, 1, args.length);
 | 
			
		||||
            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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										290
									
								
								src/main/java/net/knarcraft/stargate/config/ConfigOption.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								src/main/java/net/knarcraft/stargate/config/ConfigOption.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,290 @@
 | 
			
		||||
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"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The colors to use for each type of sign
 | 
			
		||||
     */
 | 
			
		||||
    PER_SIGN_COLORS("gates.cosmetic.perSignColors", "The per-sign color specification", new String[]{
 | 
			
		||||
            "'ACACIA:default,default'", "'BIRCH:default,default'", "'CRIMSON:inverted,inverted'", "'DARK_OAK:inverted,inverted'",
 | 
			
		||||
            "'JUNGLE:default,default'", "'OAK:default,default'", "'SPRUCE:inverted,inverted'", "'WARPED:inverted,inverted'"}),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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 a fix that makes teleportation of minecarts/boats work even with craftbook's vehicle removal
 | 
			
		||||
     */
 | 
			
		||||
    ENABLE_CRAFT_BOOK_REMOVE_ON_EJECT_FIX("gates.functionality.enableCraftBookRemoveOnEjectFix",
 | 
			
		||||
            "Whether to enable a fix that causes loss of NBT data, but allows vehicle teleportation to work " +
 | 
			
		||||
                    "when CraftBook's remove minecart/boat on eject setting is enabled", false),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The delay between teleporting a vehicle and adding the player as passenger
 | 
			
		||||
     */
 | 
			
		||||
    WAIT_FOR_PLAYER_AFTER_TELEPORT_DELAY("advanced.waitForPlayerAfterTeleportDelay",
 | 
			
		||||
            "The amount of ticks to wait before adding a player as passenger of a vehicle. On slow servers, " +
 | 
			
		||||
                    "a value of 6 is required to avoid client glitches after teleporting on a vehicle.", 6),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether to enable economy support for taking payment from players creating/destroying/using stargates
 | 
			
		||||
     */
 | 
			
		||||
    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),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether to alert admins about new updates
 | 
			
		||||
     */
 | 
			
		||||
    ADMIN_UPDATE_ALERT("adminUpdateAlert", "Whether to alert admins about new plugin updates", true),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The velocity of players exiting a stargate, relative to the entry velocity
 | 
			
		||||
     */
 | 
			
		||||
    EXIT_VELOCITY("gates.exitVelocity", "The velocity of players exiting stargates, relative to the entry velocity", 0.1D),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether to enable showing Stargates in Dynmap
 | 
			
		||||
     */
 | 
			
		||||
    ENABLE_DYNMAP("dynmap.enableDynmap", "Whether to display Stargates in Dynmap's map", true),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether to hide Dynmap icons by default
 | 
			
		||||
     */
 | 
			
		||||
    DYNMAP_ICONS_DEFAULT_HIDDEN("dynmap.dynmapIconsHiddenByDefault",
 | 
			
		||||
            "Whether to hide Stargate's Dynmap icons by default, requiring the user to enable them.", true);
 | 
			
		||||
 | 
			
		||||
    private final String configNode;
 | 
			
		||||
    private final String description;
 | 
			
		||||
    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_LIST;
 | 
			
		||||
        } else if (defaultValue instanceof String) {
 | 
			
		||||
            this.dataType = OptionDataType.STRING;
 | 
			
		||||
        } else if (defaultValue instanceof Boolean) {
 | 
			
		||||
            this.dataType = OptionDataType.BOOLEAN;
 | 
			
		||||
        } else if (defaultValue instanceof Integer) {
 | 
			
		||||
            this.dataType = OptionDataType.INTEGER;
 | 
			
		||||
        } else if (defaultValue instanceof Double) {
 | 
			
		||||
            this.dataType = OptionDataType.DOUBLE;
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new IllegalArgumentException("Unknown config data type encountered: " + defaultValue);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										96
									
								
								src/main/java/net/knarcraft/stargate/config/ConfigTag.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								src/main/java/net/knarcraft/stargate/config/ConfigTag.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
package net.knarcraft.stargate.config;
 | 
			
		||||
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A config tag groups config values by a property
 | 
			
		||||
 */
 | 
			
		||||
public enum ConfigTag {
 | 
			
		||||
 | 
			
		||||
    COLOR(new ConfigOption[]{ConfigOption.FREE_GATES_COLOR, ConfigOption.MAIN_SIGN_COLOR,
 | 
			
		||||
            ConfigOption.HIGHLIGHT_SIGN_COLOR, ConfigOption.PER_SIGN_COLORS}),
 | 
			
		||||
    FOLDER(new ConfigOption[]{ConfigOption.GATE_FOLDER, ConfigOption.PORTAL_FOLDER}),
 | 
			
		||||
    DYNMAP(new ConfigOption[]{ConfigOption.ENABLE_DYNMAP, ConfigOption.DYNMAP_ICONS_DEFAULT_HIDDEN});
 | 
			
		||||
 | 
			
		||||
    private final ConfigOption[] taggedOptions;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new config tag
 | 
			
		||||
     *
 | 
			
		||||
     * @param taggedOptions <p>The config options included in this tag</p>
 | 
			
		||||
     */
 | 
			
		||||
    ConfigTag(ConfigOption[] taggedOptions) {
 | 
			
		||||
        this.taggedOptions = taggedOptions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a config tag includes the given config option
 | 
			
		||||
     *
 | 
			
		||||
     * @param option <p>The config option to check</p>
 | 
			
		||||
     * @return <p>True of the config option is tagged</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isTagged(ConfigOption option) {
 | 
			
		||||
        return Arrays.stream(taggedOptions).anyMatch((item) -> item == option);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a given config option requires a "reload of colors" to take effect
 | 
			
		||||
     *
 | 
			
		||||
     * @param configOption <p>The config option to check</p>
 | 
			
		||||
     * @return <p>True if changing the config option requires a "reload of colors" to take effect</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean requiresColorReload(ConfigOption configOption) {
 | 
			
		||||
        return (COLOR.isTagged(configOption) && configOption != ConfigOption.FREE_GATES_COLOR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a given config option requires a full reload to take effect
 | 
			
		||||
     *
 | 
			
		||||
     * @param option <p>The config option to check</p>
 | 
			
		||||
     * @return <p>True if changing the config option requires a full reload to take effect</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean requiresFullReload(ConfigOption option) {
 | 
			
		||||
        return FOLDER.isTagged(option);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a given config option requires a re-load of all Dynmap markers
 | 
			
		||||
     *
 | 
			
		||||
     * @param configOption <p>The config option to check</p>
 | 
			
		||||
     * @return <p>True if changing the config option requires a reload of all dynmap markers</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean requiresDynmapReload(ConfigOption configOption) {
 | 
			
		||||
        return DYNMAP.isTagged(configOption);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a given config option requires a portal reload to take effect
 | 
			
		||||
     *
 | 
			
		||||
     * @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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										134
									
								
								src/main/java/net/knarcraft/stargate/config/DynmapManager.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								src/main/java/net/knarcraft/stargate/config/DynmapManager.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,134 @@
 | 
			
		||||
package net.knarcraft.stargate.config;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import net.knarcraft.stargate.portal.PortalRegistry;
 | 
			
		||||
import org.bukkit.Location;
 | 
			
		||||
import org.bukkit.World;
 | 
			
		||||
import org.dynmap.DynmapAPI;
 | 
			
		||||
import org.dynmap.markers.GenericMarker;
 | 
			
		||||
import org.dynmap.markers.Marker;
 | 
			
		||||
import org.dynmap.markers.MarkerIcon;
 | 
			
		||||
import org.dynmap.markers.MarkerSet;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A manager for dealing with everything Dynmap
 | 
			
		||||
 */
 | 
			
		||||
public final class DynmapManager {
 | 
			
		||||
 | 
			
		||||
    private static MarkerSet markerSet;
 | 
			
		||||
    private static MarkerIcon portalIcon;
 | 
			
		||||
 | 
			
		||||
    private DynmapManager() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the dynmap manager
 | 
			
		||||
     *
 | 
			
		||||
     * @param dynmapAPI <p>A reference</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void initialize(DynmapAPI dynmapAPI) {
 | 
			
		||||
        if (dynmapAPI == null || dynmapAPI.getMarkerAPI() == null) {
 | 
			
		||||
            markerSet = null;
 | 
			
		||||
            portalIcon = null;
 | 
			
		||||
        } else {
 | 
			
		||||
            markerSet = dynmapAPI.getMarkerAPI().createMarkerSet("stargate", "Stargate", null, false);
 | 
			
		||||
            if (markerSet != null) {
 | 
			
		||||
                markerSet.setHideByDefault(Stargate.getStargateConfig().hideDynmapIcons());
 | 
			
		||||
            }
 | 
			
		||||
            portalIcon = dynmapAPI.getMarkerAPI().getMarkerIcon("portal");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds all portal markers for all current portals
 | 
			
		||||
     */
 | 
			
		||||
    public static void addAllPortalMarkers() {
 | 
			
		||||
        if (markerSet == null || Stargate.getStargateConfig().isDynmapDisabled()) {
 | 
			
		||||
            //Remove any existing markers if dynmap has been disabled after startup
 | 
			
		||||
            if (markerSet != null) {
 | 
			
		||||
                markerSet.getMarkers().forEach(GenericMarker::deleteMarker);
 | 
			
		||||
            }
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        markerSet.setHideByDefault(Stargate.getStargateConfig().hideDynmapIcons());
 | 
			
		||||
        //Remove all existing markers for a clean start
 | 
			
		||||
        markerSet.getMarkers().forEach(GenericMarker::deleteMarker);
 | 
			
		||||
 | 
			
		||||
        for (Portal portal : PortalRegistry.getAllPortals()) {
 | 
			
		||||
            addPortalMarker(portal);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a portal marker for the given portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal <p>The portal to add a marker for</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void addPortalMarker(Portal portal) {
 | 
			
		||||
        if (markerSet == null || Stargate.getStargateConfig().isDynmapDisabled()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        World world = portal.getWorld();
 | 
			
		||||
        if (portal.getOptions().isHidden() || world == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Location location = portal.getBlockAt(portal.getGate().getLayout().getExit());
 | 
			
		||||
        Marker marker = markerSet.createMarker(getPortalMarkerId(portal), portal.getName(), world.getName(),
 | 
			
		||||
                location.getX(), location.getY(), location.getZ(), portalIcon, false);
 | 
			
		||||
        if (marker == null) {
 | 
			
		||||
            Stargate.logWarning(String.format(
 | 
			
		||||
                    """
 | 
			
		||||
                            Unable to create marker for portal
 | 
			
		||||
                            Portal marker id: %s
 | 
			
		||||
                            Portal name: %s
 | 
			
		||||
                            Portal world: %s
 | 
			
		||||
                            Portal location: %s,%s,%s""",
 | 
			
		||||
                    getPortalMarkerId(portal), portal.getName(), world.getName(), location.getX(), location.getY(),
 | 
			
		||||
                    location.getZ()));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        String networkPrompt;
 | 
			
		||||
        if (portal.getOptions().isBungee()) {
 | 
			
		||||
            networkPrompt = "Server";
 | 
			
		||||
        } else {
 | 
			
		||||
            networkPrompt = "Network";
 | 
			
		||||
        }
 | 
			
		||||
        String markerDescription = String.format("<b>Name:</b> %s<br /><b>%s:</b> %s<br /><b>Destination:</b> " +
 | 
			
		||||
                        "%s<br /><b>Owner:</b> %s<br />", portal.getName(), networkPrompt, portal.getNetwork(),
 | 
			
		||||
                portal.getDestinationName(), portal.getOwner().getName());
 | 
			
		||||
        marker.setDescription(markerDescription);
 | 
			
		||||
        marker.setLabel(portal.getName(), true);
 | 
			
		||||
        if (portalIcon != null) {
 | 
			
		||||
            marker.setMarkerIcon(portalIcon);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes the portal marker for the given portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal <p>The portal to remove the marker for</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void removePortalMarker(Portal portal) {
 | 
			
		||||
        if (markerSet == null || Stargate.getStargateConfig().isDynmapDisabled()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        Marker marker = markerSet.findMarker(getPortalMarkerId(portal));
 | 
			
		||||
        if (marker != null) {
 | 
			
		||||
            marker.deleteMarker();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the id used for the given portal's marker
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal <p>The portal to get a marker id for</p>
 | 
			
		||||
     * @return <p></p>
 | 
			
		||||
     */
 | 
			
		||||
    private static String getPortalMarkerId(Portal portal) {
 | 
			
		||||
        return portal.getNetwork() + "-:-" + portal.getName();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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.md_5.bungee.api.ChatColor;
 | 
			
		||||
import net.milkbowl.vault.economy.Economy;
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.configuration.file.FileConfiguration;
 | 
			
		||||
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.of(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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,8 @@
 | 
			
		||||
package net.knarcraft.stargate.config;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.knarlib.property.ColorConversion;
 | 
			
		||||
import net.knarcraft.knarlib.util.FileHelper;
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.utility.FileHelper;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
import java.io.BufferedWriter;
 | 
			
		||||
@@ -136,7 +137,8 @@ public final class LanguageLoader {
 | 
			
		||||
            String> currentLanguageValues) throws IOException {
 | 
			
		||||
        //Get language values
 | 
			
		||||
        BufferedReader bufferedReader = FileHelper.getBufferedReaderFromInputStream(inputStream);
 | 
			
		||||
        Map<String, String> internalLanguageValues = FileHelper.readKeyValuePairs(bufferedReader);
 | 
			
		||||
        Map<String, String> internalLanguageValues = FileHelper.readKeyValuePairs(bufferedReader, "=",
 | 
			
		||||
                ColorConversion.NORMAL);
 | 
			
		||||
 | 
			
		||||
        //If currentLanguageValues is null; the chosen language has not been used before
 | 
			
		||||
        if (currentLanguageValues == null) {
 | 
			
		||||
@@ -221,7 +223,7 @@ public final class LanguageLoader {
 | 
			
		||||
            } else {
 | 
			
		||||
                bufferedReader = FileHelper.getBufferedReaderFromInputStream(inputStream);
 | 
			
		||||
            }
 | 
			
		||||
            strings = FileHelper.readKeyValuePairs(bufferedReader);
 | 
			
		||||
            strings = FileHelper.readKeyValuePairs(bufferedReader, "=", ColorConversion.NORMAL);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            if (Stargate.getStargateConfig().isDebuggingEnabled()) {
 | 
			
		||||
                Stargate.getConsoleLogger().info("[Stargate] Unable to load language " + lang);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
package net.knarcraft.stargate.config;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.ChatColor;
 | 
			
		||||
import net.md_5.bungee.api.ChatColor;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,33 @@
 | 
			
		||||
package net.knarcraft.stargate.config;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An enum defining the different data types an option can have
 | 
			
		||||
 */
 | 
			
		||||
public enum OptionDataType {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The data type if the option is a String
 | 
			
		||||
     */
 | 
			
		||||
    STRING,
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The data type if the option is a Boolean
 | 
			
		||||
     */
 | 
			
		||||
    BOOLEAN,
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The data type if the option is a string list
 | 
			
		||||
     */
 | 
			
		||||
    STRING_LIST,
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The data type if the option is an Integer
 | 
			
		||||
     */
 | 
			
		||||
    INTEGER,
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The data type if the option is a double
 | 
			
		||||
     */
 | 
			
		||||
    DOUBLE
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,23 +1,26 @@
 | 
			
		||||
package net.knarcraft.stargate.config;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.knarlib.property.ColorConversion;
 | 
			
		||||
import net.knarcraft.knarlib.util.FileHelper;
 | 
			
		||||
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;
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.World;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
import org.bukkit.configuration.file.FileConfiguration;
 | 
			
		||||
import org.bukkit.plugin.messaging.Messenger;
 | 
			
		||||
import org.dynmap.DynmapAPI;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Queue;
 | 
			
		||||
@@ -45,8 +48,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 +57,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 +65,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 +93,7 @@ public final class StargateConfig {
 | 
			
		||||
        languageLoader.reload();
 | 
			
		||||
 | 
			
		||||
        messageSender = new MessageSender(languageLoader);
 | 
			
		||||
        if (debuggingEnabled) {
 | 
			
		||||
        if (isDebuggingEnabled()) {
 | 
			
		||||
            languageLoader.debug();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -88,6 +103,20 @@ public final class StargateConfig {
 | 
			
		||||
 | 
			
		||||
        //Set up vault economy if vault has been loaded
 | 
			
		||||
        setupVaultEconomy();
 | 
			
		||||
        DynmapAPI dynmapAPI = (DynmapAPI) Bukkit.getPluginManager().getPlugin("dynmap");
 | 
			
		||||
        if (dynmapAPI != null) {
 | 
			
		||||
            DynmapManager.initialize(dynmapAPI);
 | 
			
		||||
            DynmapManager.addAllPortalMarkers();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -118,7 +147,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 +156,25 @@ public final class StargateConfig {
 | 
			
		||||
     * @return <p>Whether permission debugging is enabled</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isPermissionDebuggingEnabled() {
 | 
			
		||||
        return permissionDebuggingEnabled;
 | 
			
		||||
        return (boolean) configOptions.get(ConfigOption.PERMISSION_DEBUG);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether Dynmap integration is disabled
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether Dynmap integration is disabled</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isDynmapDisabled() {
 | 
			
		||||
        return !((boolean) configOptions.get(ConfigOption.ENABLE_DYNMAP));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether Dynmap icons should be hidden by default
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether Dynmap icons should be hidden by default</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean hideDynmapIcons() {
 | 
			
		||||
        return (boolean) configOptions.get(ConfigOption.DYNMAP_ICONS_DEFAULT_HIDDEN);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -167,6 +214,9 @@ public final class StargateConfig {
 | 
			
		||||
            startStopBungeeListener(stargateGateConfig.enableBungee());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Reload portal markers
 | 
			
		||||
        DynmapManager.addAllPortalMarkers();
 | 
			
		||||
 | 
			
		||||
        messageSender.sendErrorMessage(sender, languageLoader.getString("reloaded"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -174,6 +224,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 +250,6 @@ public final class StargateConfig {
 | 
			
		||||
 | 
			
		||||
        //Clear all loaded portals
 | 
			
		||||
        PortalRegistry.clearPortals();
 | 
			
		||||
 | 
			
		||||
        //Clear all loaded gates
 | 
			
		||||
        GateHandler.clearGates();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -244,7 +302,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 +313,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 +329,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();
 | 
			
		||||
@@ -289,6 +347,15 @@ public final class StargateConfig {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether admins should be alerted about new plugin updates
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether admins should be alerted about new updates</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean alertAdminsAboutUpdates() {
 | 
			
		||||
        return (boolean) configOptions.get(ConfigOption.ADMIN_UPDATE_ALERT);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads all config values
 | 
			
		||||
     */
 | 
			
		||||
@@ -297,9 +364,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 +372,32 @@ 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_LIST -> optionValue = newConfig.getStringList(configNode);
 | 
			
		||||
                case STRING -> {
 | 
			
		||||
                    String value = newConfig.getString(configNode);
 | 
			
		||||
                    optionValue = value != null ? value.trim() : "";
 | 
			
		||||
                }
 | 
			
		||||
                case BOOLEAN -> optionValue = newConfig.getBoolean(configNode);
 | 
			
		||||
                case INTEGER -> optionValue = newConfig.getInt(configNode);
 | 
			
		||||
                case DOUBLE -> optionValue = newConfig.getDouble(configNode);
 | 
			
		||||
                default -> throw new IllegalArgumentException("Invalid config data type encountered");
 | 
			
		||||
            }
 | 
			
		||||
            configOptions.put(option, optionValue);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //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 +405,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();
 | 
			
		||||
    }
 | 
			
		||||
@@ -368,7 +449,8 @@ public final class StargateConfig {
 | 
			
		||||
        Map<String, String> migrationFields;
 | 
			
		||||
        try {
 | 
			
		||||
            migrationFields = FileHelper.readKeyValuePairs(FileHelper.getBufferedReaderFromInputStream(
 | 
			
		||||
                    FileHelper.getInputStreamForInternalFile("/config-migrations.txt")));
 | 
			
		||||
                            FileHelper.getInputStreamForInternalFile("/config-migrations.txt")), "=",
 | 
			
		||||
                    ColorConversion.NORMAL);
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            Stargate.debug("Stargate::migrateConfig", "Unable to load config migration file");
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
@@ -467,4 +549,5 @@ public final class StargateConfig {
 | 
			
		||||
    public LanguageLoader getLanguageLoader() {
 | 
			
		||||
        return languageLoader;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,34 +1,34 @@
 | 
			
		||||
package net.knarcraft.stargate.config;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.knarlib.util.ColorHelper;
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.portal.PortalSignDrawer;
 | 
			
		||||
import org.bukkit.ChatColor;
 | 
			
		||||
import org.bukkit.configuration.file.FileConfiguration;
 | 
			
		||||
import net.md_5.bungee.api.ChatColor;
 | 
			
		||||
import org.bukkit.Color;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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 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();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -55,7 +55,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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -64,7 +64,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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -73,7 +73,80 @@ 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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether leashed creatures should be teleported with a teleporting player
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether leashed creatures should be handled</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean handleLeashedCreatures() {
 | 
			
		||||
        return (boolean) configOptions.get(ConfigOption.HANDLE_LEASHED_CREATURES);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether the CraftBook vehicle removal fix is enabled
 | 
			
		||||
     *
 | 
			
		||||
     * <p>If enabled, minecarts and boats should be re-created instead of teleported.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>True if the CraftBook vehicle removal fix is enabled</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean enableCraftBookRemoveOnEjectFix() {
 | 
			
		||||
        return (boolean) configOptions.get(ConfigOption.ENABLE_CRAFT_BOOK_REMOVE_ON_EJECT_FIX);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the delay to use before adding a player as passenger of a teleported vehicle
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The delay to use before adding a player as passenger of a teleported vehicle</p>
 | 
			
		||||
     */
 | 
			
		||||
    public int waitForPlayerAfterTeleportDelay() {
 | 
			
		||||
        if ((int) configOptions.get(ConfigOption.WAIT_FOR_PLAYER_AFTER_TELEPORT_DELAY) < 2) {
 | 
			
		||||
            configOptions.put(ConfigOption.WAIT_FOR_PLAYER_AFTER_TELEPORT_DELAY, 6);
 | 
			
		||||
        }
 | 
			
		||||
        return (int) configOptions.get(ConfigOption.WAIT_FOR_PLAYER_AFTER_TELEPORT_DELAY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -82,7 +155,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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -91,7 +164,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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -100,7 +173,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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -109,7 +182,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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -118,7 +191,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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -127,33 +200,108 @@ public final class StargateGateConfig {
 | 
			
		||||
     * @return <p>The default portal network</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getDefaultPortalNetwork() {
 | 
			
		||||
        return defaultGateNetwork;
 | 
			
		||||
        return (String) configOptions.get(ConfigOption.DEFAULT_GATE_NETWORK);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the exit velocity of players using stargates, relative to the entry velocity
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The relative exit velocity</p>
 | 
			
		||||
     */
 | 
			
		||||
    public double getExitVelocity() {
 | 
			
		||||
        return (double) configOptions.get(ConfigOption.EXIT_VELOCITY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads all config values related to gates
 | 
			
		||||
     *
 | 
			
		||||
     * @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");
 | 
			
		||||
    private void loadGateConfig() {
 | 
			
		||||
        //Load the sign colors
 | 
			
		||||
        String mainSignColor = (String) configOptions.get(ConfigOption.MAIN_SIGN_COLOR);
 | 
			
		||||
        String highlightSignColor = (String) configOptions.get(ConfigOption.HIGHLIGHT_SIGN_COLOR);
 | 
			
		||||
        loadPerSignColor(mainSignColor, highlightSignColor);
 | 
			
		||||
        loadPerSignColors();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        //Functionality
 | 
			
		||||
        handleVehicles = newConfig.getBoolean("gates.functionality.handleVehicles");
 | 
			
		||||
        enableBungee = newConfig.getBoolean("gates.functionality.enableBungee");
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads the per-sign colors specified in the config file
 | 
			
		||||
     */
 | 
			
		||||
    public void loadPerSignColors() {
 | 
			
		||||
        List<?> perSignColors = (List<?>) configOptions.get(ConfigOption.PER_SIGN_COLORS);
 | 
			
		||||
        ChatColor[] defaultColors = new ChatColor[]{PortalSignDrawer.getMainColor(), PortalSignDrawer.getHighlightColor()};
 | 
			
		||||
        List<Map<Material, ChatColor>> colorMaps = new ArrayList<>();
 | 
			
		||||
        colorMaps.add(new HashMap<>());
 | 
			
		||||
        colorMaps.add(new HashMap<>());
 | 
			
		||||
 | 
			
		||||
        //Integrity
 | 
			
		||||
        protectEntrance = newConfig.getBoolean("gates.integrity.protectEntrance");
 | 
			
		||||
        verifyPortals = newConfig.getBoolean("gates.integrity.verifyPortals");
 | 
			
		||||
        destroyExplosion = newConfig.getBoolean("gates.integrity.destroyedByExplosion");
 | 
			
		||||
        for (Object signColorSpecification : perSignColors) {
 | 
			
		||||
            parsePerSignColors(signColorSpecification, defaultColors, colorMaps);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Cosmetic
 | 
			
		||||
        sortNetworkDestinations = newConfig.getBoolean("gates.cosmetic.sortNetworkDestinations");
 | 
			
		||||
        rememberDestination = newConfig.getBoolean("gates.cosmetic.rememberDestination");
 | 
			
		||||
        loadSignColor(newConfig.getString("gates.cosmetic.mainSignColor"),
 | 
			
		||||
                newConfig.getString("gates.cosmetic.highlightSignColor"));
 | 
			
		||||
        PortalSignDrawer.setPerSignMainColors(colorMaps.get(0));
 | 
			
		||||
        PortalSignDrawer.setPerSignHighlightColors(colorMaps.get(1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses a per-sign color specification object and stores the result
 | 
			
		||||
     *
 | 
			
		||||
     * @param signColorSpecification <p>The sign color specification to parse</p>
 | 
			
		||||
     * @param defaultColors          <p>The specified default colors</p>
 | 
			
		||||
     * @param colorMaps              <p>The list of color maps to save the resulting colors to</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void parsePerSignColors(Object signColorSpecification, ChatColor[] defaultColors,
 | 
			
		||||
                                    List<Map<Material, ChatColor>> colorMaps) {
 | 
			
		||||
        String[] specificationData = String.valueOf(signColorSpecification).split(":");
 | 
			
		||||
        Material[] signMaterials = new Material[]{Material.matchMaterial(specificationData[0] + "_SIGN"),
 | 
			
		||||
                Material.matchMaterial(specificationData[0] + "_WALL_SIGN")};
 | 
			
		||||
 | 
			
		||||
        if (specificationData.length != 2) {
 | 
			
		||||
            Stargate.logWarning("You have an invalid per-sign line in your config.yml file. Please fix it!");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        String[] colors = specificationData[1].split(",");
 | 
			
		||||
        if (colors.length != 2) {
 | 
			
		||||
            Stargate.logWarning("You have an invalid per-sign line in your config.yml file. Please fix it!");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        for (int colorIndex = 0; colorIndex < 2; colorIndex++) {
 | 
			
		||||
            if (colors[colorIndex].equalsIgnoreCase("default")) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            loadPerSignColor(colors, colorIndex, defaultColors, signMaterials, colorMaps);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads a per-sign color
 | 
			
		||||
     *
 | 
			
		||||
     * @param colors        <p>The colors specified in the config file</p>
 | 
			
		||||
     * @param colorIndex    <p>The index of the color to load</p>
 | 
			
		||||
     * @param defaultColors <p>The specified default colors</p>
 | 
			
		||||
     * @param signMaterials <p>The materials to load this color for</p>
 | 
			
		||||
     * @param colorMaps     <p>The list of color maps to save the resulting color to</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void loadPerSignColor(String[] colors, int colorIndex, ChatColor[] defaultColors, Material[] signMaterials,
 | 
			
		||||
                                  List<Map<Material, ChatColor>> colorMaps) {
 | 
			
		||||
        ChatColor parsedColor;
 | 
			
		||||
        if (colors[colorIndex].equalsIgnoreCase("inverted")) {
 | 
			
		||||
            //Convert from ChatColor to awt.Color to Bukkit.Color then invert and convert to ChatColor
 | 
			
		||||
            java.awt.Color color = defaultColors[colorIndex].getColor();
 | 
			
		||||
            parsedColor = ColorHelper.fromColor(ColorHelper.invert(Color.fromRGB(color.getRed(), color.getGreen(),
 | 
			
		||||
                    color.getBlue())));
 | 
			
		||||
        } else {
 | 
			
		||||
            try {
 | 
			
		||||
                parsedColor = ChatColor.of(colors[colorIndex]);
 | 
			
		||||
            } catch (IllegalArgumentException | NullPointerException exception) {
 | 
			
		||||
                Stargate.logWarning("You have specified an invalid per-sign color in your config.yml. Custom color for \"" +
 | 
			
		||||
                        signMaterials[0] + "\" disabled");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (parsedColor != null) {
 | 
			
		||||
            for (Material signMaterial : signMaterials) {
 | 
			
		||||
                colorMaps.get(colorIndex).put(signMaterial, parsedColor);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -161,17 +309,20 @@ 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) {
 | 
			
		||||
            }
 | 
			
		||||
    private void loadPerSignColor(String mainSignColor, String highlightSignColor) {
 | 
			
		||||
        try {
 | 
			
		||||
            PortalSignDrawer.setMainColor(ChatColor.of(mainSignColor.toUpperCase()));
 | 
			
		||||
        } catch (IllegalArgumentException | NullPointerException exception) {
 | 
			
		||||
            Stargate.logWarning("You have specified an invalid main sign color in your config.yml. Defaulting to BLACK");
 | 
			
		||||
            PortalSignDrawer.setMainColor(ChatColor.BLACK);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            PortalSignDrawer.setHighlightColor(ChatColor.of(highlightSignColor.toUpperCase()));
 | 
			
		||||
        } catch (IllegalArgumentException | NullPointerException exception) {
 | 
			
		||||
            Stargate.logWarning("You have specified an invalid highlighting sign color in your config.yml. Defaulting to WHITE");
 | 
			
		||||
            PortalSignDrawer.setHighlightColor(ChatColor.WHITE);
 | 
			
		||||
        }
 | 
			
		||||
        Stargate.logWarning("You have specified an invalid color in your config.yml. Defaulting to BLACK and WHITE");
 | 
			
		||||
        PortalSignDrawer.setColors(ChatColor.BLACK, ChatColor.WHITE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
package net.knarcraft.stargate.container;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.util.Vector;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This stores a block location as a vector relative to a position
 | 
			
		||||
 *
 | 
			
		||||
@@ -58,16 +60,20 @@ public class RelativeBlockVector {
 | 
			
		||||
     * @return <p>A new relative block vector with the property altered</p>
 | 
			
		||||
     */
 | 
			
		||||
    public RelativeBlockVector addToVector(Property propertyToAddTo, int valueToAdd) {
 | 
			
		||||
        switch (propertyToAddTo) {
 | 
			
		||||
            case RIGHT:
 | 
			
		||||
                return new RelativeBlockVector(this.right + valueToAdd, this.down, this.out);
 | 
			
		||||
            case DOWN:
 | 
			
		||||
                return new RelativeBlockVector(this.right, this.down + valueToAdd, this.out);
 | 
			
		||||
            case OUT:
 | 
			
		||||
                return new RelativeBlockVector(this.right, this.down, this.out + valueToAdd);
 | 
			
		||||
            default:
 | 
			
		||||
                throw new IllegalArgumentException("Invalid relative block vector property given");
 | 
			
		||||
        }
 | 
			
		||||
        return switch (propertyToAddTo) {
 | 
			
		||||
            case RIGHT -> new RelativeBlockVector(this.right + valueToAdd, this.down, this.out);
 | 
			
		||||
            case DOWN -> new RelativeBlockVector(this.right, this.down + valueToAdd, this.out);
 | 
			
		||||
            case OUT -> new RelativeBlockVector(this.right, this.down, this.out + valueToAdd);
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a relative vector in the real space representing this relative block vector
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A vector representing this relative block vector</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Vector toVector() {
 | 
			
		||||
        return new Vector(this.right, -this.down, this.out);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										67
									
								
								src/main/java/net/knarcraft/stargate/container/SignData.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/main/java/net/knarcraft/stargate/container/SignData.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
package net.knarcraft.stargate.container;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.knarlib.util.ColorHelper;
 | 
			
		||||
import net.md_5.bungee.api.ChatColor;
 | 
			
		||||
import org.bukkit.DyeColor;
 | 
			
		||||
import org.bukkit.block.Sign;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A class that keeps track of the sign colors for a given sign
 | 
			
		||||
 */
 | 
			
		||||
public class SignData {
 | 
			
		||||
 | 
			
		||||
    private final Sign sign;
 | 
			
		||||
    private final ChatColor mainSignColor;
 | 
			
		||||
    private final ChatColor highlightSignColor;
 | 
			
		||||
    private final DyeColor dyedColor;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new sign colors object
 | 
			
		||||
     *
 | 
			
		||||
     * @param sign               <p>The sign the colors belong to</p>
 | 
			
		||||
     * @param mainSignColor      <p>The main color to use for the sign</p>
 | 
			
		||||
     * @param highlightSignColor <p>The highlighting color to use for the sign</p>
 | 
			
		||||
     */
 | 
			
		||||
    public SignData(Sign sign, ChatColor mainSignColor, ChatColor highlightSignColor) {
 | 
			
		||||
        this.sign = sign;
 | 
			
		||||
        this.mainSignColor = mainSignColor;
 | 
			
		||||
        this.highlightSignColor = highlightSignColor;
 | 
			
		||||
        this.dyedColor = sign.getColor();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the sign of this sign colors object
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The sign of this sign colors object</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Sign getSign() {
 | 
			
		||||
        return sign;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the main color of the sign
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The main color of the sign</p>
 | 
			
		||||
     */
 | 
			
		||||
    public ChatColor getMainSignColor() {
 | 
			
		||||
        if (dyedColor != DyeColor.BLACK) {
 | 
			
		||||
            return ColorHelper.fromColor(dyedColor.getColor());
 | 
			
		||||
        } else {
 | 
			
		||||
            return mainSignColor;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the highlighting color of the sign
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The highlighting color of the sign</p>
 | 
			
		||||
     */
 | 
			
		||||
    public ChatColor getHighlightSignColor() {
 | 
			
		||||
        if (dyedColor != DyeColor.BLACK) {
 | 
			
		||||
            return ColorHelper.fromColor(ColorHelper.invert(dyedColor.getColor()));
 | 
			
		||||
        } else {
 | 
			
		||||
            return highlightSignColor;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 * <p>This event can be used to overwrite the location the entity is teleported to.</p>
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class StargateEntityPortalEvent extends StargateEvent {
 | 
			
		||||
public class StargateEntityPortalEvent extends StargateEvent implements StargateTeleportEvent {
 | 
			
		||||
 | 
			
		||||
    private static final HandlerList handlers = new HandlerList();
 | 
			
		||||
    final Entity travellingEntity;
 | 
			
		||||
@@ -58,6 +58,7 @@ public class StargateEntityPortalEvent extends StargateEvent {
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Location of the exit point</p>
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public Location getExit() {
 | 
			
		||||
        return exit;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 * <p>This event can be used to overwrite the location the player is teleported to.</p>
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class StargatePlayerPortalEvent extends StargatePlayerEvent {
 | 
			
		||||
public class StargatePlayerPortalEvent extends StargatePlayerEvent implements StargateTeleportEvent {
 | 
			
		||||
 | 
			
		||||
    private static final HandlerList handlers = new HandlerList();
 | 
			
		||||
    private final Portal destination;
 | 
			
		||||
@@ -47,6 +47,7 @@ public class StargatePlayerPortalEvent extends StargatePlayerEvent {
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Location of the exit point</p>
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public Location getExit() {
 | 
			
		||||
        return exit;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
package net.knarcraft.stargate.event;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.Location;
 | 
			
		||||
import org.bukkit.event.Cancellable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A generic teleportation event
 | 
			
		||||
 */
 | 
			
		||||
public interface StargateTeleportEvent extends Cancellable {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the location of the players exit point
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Location of the exit point</p>
 | 
			
		||||
     */
 | 
			
		||||
    Location getExit();
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,25 @@
 | 
			
		||||
package net.knarcraft.stargate.listener;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.portal.PortalHandler;
 | 
			
		||||
import org.bukkit.event.EventHandler;
 | 
			
		||||
import org.bukkit.event.Listener;
 | 
			
		||||
import org.bukkit.event.entity.CreatureSpawnEvent;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A listener that listens for any relevant events causing entities to spawn
 | 
			
		||||
 */
 | 
			
		||||
public class EntitySpawnListener implements Listener {
 | 
			
		||||
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onCreatureSpawn(CreatureSpawnEvent event) {
 | 
			
		||||
        //Prevent Zombified Piglins and other creatures form spawning at stargates
 | 
			
		||||
        if (event.getSpawnReason() == CreatureSpawnEvent.SpawnReason.NETHER_PORTAL) {
 | 
			
		||||
            if (PortalHandler.getByEntrance(event.getLocation()) != null) {
 | 
			
		||||
                event.setCancelled(true);
 | 
			
		||||
                Stargate.debug("EntitySpawnListener", "Prevented creature from spawning at Stargate");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,16 +1,23 @@
 | 
			
		||||
package net.knarcraft.stargate.listener;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.knarlib.util.UpdateChecker;
 | 
			
		||||
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.VehicleTeleporter;
 | 
			
		||||
import net.knarcraft.stargate.utility.BungeeHelper;
 | 
			
		||||
import net.knarcraft.stargate.utility.MaterialHelper;
 | 
			
		||||
import net.knarcraft.stargate.utility.PermissionHelper;
 | 
			
		||||
import net.knarcraft.stargate.utility.TeleportHelper;
 | 
			
		||||
import net.knarcraft.stargate.utility.UUIDMigrationHelper;
 | 
			
		||||
import net.md_5.bungee.api.ChatColor;
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.GameMode;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
import org.bukkit.block.Block;
 | 
			
		||||
import org.bukkit.block.data.type.WallSign;
 | 
			
		||||
import org.bukkit.entity.AbstractHorse;
 | 
			
		||||
@@ -25,6 +32,12 @@ 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;
 | 
			
		||||
import org.bukkit.util.Vector;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This listener listens to any player-related events related to stargates
 | 
			
		||||
@@ -32,8 +45,7 @@ import org.bukkit.event.player.PlayerMoveEvent;
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class PlayerEventListener implements Listener {
 | 
			
		||||
 | 
			
		||||
    private static long eventTime;
 | 
			
		||||
    private static PlayerInteractEvent previousEvent;
 | 
			
		||||
    private static final Map<Player, Long> previousEventTimes = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This event handler handles detection of any player teleporting through a bungee gate
 | 
			
		||||
@@ -42,11 +54,22 @@ public class PlayerEventListener implements Listener {
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onPlayerJoin(PlayerJoinEvent event) {
 | 
			
		||||
        Player player = event.getPlayer();
 | 
			
		||||
        //Migrate player name to UUID if necessary
 | 
			
		||||
        UUIDMigrationHelper.migrateUUID(player);
 | 
			
		||||
 | 
			
		||||
        //Notify joining admins about the available update
 | 
			
		||||
        String availableUpdate = Stargate.getUpdateAvailable();
 | 
			
		||||
        if (availableUpdate != null && Stargate.getStargateConfig().alertAdminsAboutUpdates() &&
 | 
			
		||||
                player.hasPermission("stargate.admin")) {
 | 
			
		||||
            String updateMessage = UpdateChecker.getUpdateAvailableString(availableUpdate, Stargate.getPluginVersion());
 | 
			
		||||
            Stargate.getMessageSender().sendErrorMessage(player, updateMessage);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!Stargate.getGateConfig().enableBungee()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Player player = event.getPlayer();
 | 
			
		||||
        //Check if the player is waiting to be teleported to a stargate
 | 
			
		||||
        String destination = BungeeHelper.removeFromQueue(player.getUniqueId());
 | 
			
		||||
        if (destination == null) {
 | 
			
		||||
@@ -82,11 +105,17 @@ public class PlayerEventListener implements Listener {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        Portal entrancePortal = PortalHandler.getByEntrance(toLocation);
 | 
			
		||||
        //Check an additional block away in case the portal is a bungee portal using END_PORTAL
 | 
			
		||||
        if (entrancePortal == null) {
 | 
			
		||||
            entrancePortal = PortalHandler.getByAdjacentEntrance(toLocation);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Portal destination = entrancePortal.getPortalActivator().getDestination(player);
 | 
			
		||||
 | 
			
		||||
        Entity playerVehicle = player.getVehicle();
 | 
			
		||||
        //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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -109,12 +138,15 @@ public class PlayerEventListener implements Listener {
 | 
			
		||||
                horse.setOwner(player);
 | 
			
		||||
            }
 | 
			
		||||
            //Teleport the player's vehicle
 | 
			
		||||
            new VehicleTeleporter(destination, (Vehicle) playerVehicle).teleport(entrancePortal);
 | 
			
		||||
            player.setVelocity(new Vector());
 | 
			
		||||
            new VehicleTeleporter(destination, (Vehicle) playerVehicle).teleportEntity(entrancePortal);
 | 
			
		||||
        } else {
 | 
			
		||||
            //Just teleport the player like normal
 | 
			
		||||
            new PlayerTeleporter(destination, player).teleport(entrancePortal, event);
 | 
			
		||||
            new PlayerTeleporter(destination, player).teleportPlayer(entrancePortal, event);
 | 
			
		||||
        }
 | 
			
		||||
        if (!entrancePortal.getOptions().isSilent()) {
 | 
			
		||||
            Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
 | 
			
		||||
        }
 | 
			
		||||
        Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
 | 
			
		||||
        entrancePortal.getPortalOpener().closePortal(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -137,7 +169,12 @@ public class PlayerEventListener implements Listener {
 | 
			
		||||
        //Check if the player moved from a portal
 | 
			
		||||
        Portal entrancePortal = PortalHandler.getByEntrance(toLocation);
 | 
			
		||||
        if (entrancePortal == null) {
 | 
			
		||||
            return false;
 | 
			
		||||
            //Check an additional block away for BungeeCord portals using END_PORTAL as its material
 | 
			
		||||
            entrancePortal = PortalHandler.getByAdjacentEntrance(toLocation);
 | 
			
		||||
            if (entrancePortal == null || !entrancePortal.getOptions().isBungee() ||
 | 
			
		||||
                    entrancePortal.getGate().getPortalOpenBlock() != Material.END_PORTAL) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Portal destination = entrancePortal.getPortalActivator().getDestination(player);
 | 
			
		||||
@@ -154,12 +191,14 @@ public class PlayerEventListener implements Listener {
 | 
			
		||||
 | 
			
		||||
        //Decide if the user should be teleported to another bungee server
 | 
			
		||||
        if (entrancePortal.getOptions().isBungee()) {
 | 
			
		||||
            if (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 TeleportHelper.noLeashedCreaturesPreventTeleportation(player);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -177,7 +216,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);
 | 
			
		||||
@@ -198,6 +237,21 @@ public class PlayerEventListener implements Listener {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Allow players with permissions to apply dye to signs
 | 
			
		||||
        EquipmentSlot hand = event.getHand();
 | 
			
		||||
        if (hand != null && (PermissionHelper.hasPermission(player, "stargate.admin.dye") ||
 | 
			
		||||
                portal.isOwner(player))) {
 | 
			
		||||
            ItemStack item = player.getInventory().getItem(hand);
 | 
			
		||||
            if (item != null) {
 | 
			
		||||
                String itemName = item.getType().toString();
 | 
			
		||||
                if (itemName.endsWith("DYE") || itemName.endsWith("INK_SAC")) {
 | 
			
		||||
                    event.setUseInteractedBlock(Event.Result.ALLOW);
 | 
			
		||||
                    Bukkit.getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(), portal::drawSign, 1);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        event.setUseInteractedBlock(Event.Result.DENY);
 | 
			
		||||
        if (leftClick) {
 | 
			
		||||
            //Cancel event in creative mode to prevent breaking the sign
 | 
			
		||||
@@ -233,10 +287,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;
 | 
			
		||||
@@ -248,19 +304,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.getPlayer(), block)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (MaterialHelper.isButtonCompatible(block.getType())) {
 | 
			
		||||
            Portal portal = PortalHandler.getByBlock(block);
 | 
			
		||||
            if (portal == null) {
 | 
			
		||||
                return;
 | 
			
		||||
@@ -276,69 +333,69 @@ 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 != null && (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 event <p>The event causing the right click</p>
 | 
			
		||||
     * @param block <p>The block to check</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 player <p>The player performing 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();
 | 
			
		||||
    private boolean clickIsBug(Player player, Block block) {
 | 
			
		||||
        Long previousEventTime = previousEventTimes.get(player);
 | 
			
		||||
        if (previousEventTime != null && previousEventTime + 50 > System.currentTimeMillis()) {
 | 
			
		||||
            previousEventTimes.put(player, null);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        previousEventTimes.put(player, System.currentTimeMillis());
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleports a player to a bungee gate
 | 
			
		||||
     *
 | 
			
		||||
     * @param player         <p>The player to teleport</p>
 | 
			
		||||
     * @param entrancePortal <p>The gate the player is entering from</p>
 | 
			
		||||
     * @param event          <p>The event causing the teleportation</p>
 | 
			
		||||
     * @return <p>True if the teleportation was successful</p>
 | 
			
		||||
     */
 | 
			
		||||
    private 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"));
 | 
			
		||||
            entrancePortal.getPortalOpener().closePortal(false);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Teleport the player back to this gate, for sanity's sake
 | 
			
		||||
        new PlayerTeleporter(entrancePortal, player).teleport(entrancePortal, event);
 | 
			
		||||
 | 
			
		||||
        //Send the SGBungee packet first, it will be queued by BC if required
 | 
			
		||||
        if (!BungeeHelper.sendTeleportationMessage(player, entrancePortal)) {
 | 
			
		||||
            Stargate.debug("bungeeTeleport", "Unable to send teleportation message");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Send the connect-message to make the player change server
 | 
			
		||||
        if (!BungeeHelper.changeServer(player, entrancePortal)) {
 | 
			
		||||
            Stargate.debug("bungeeTeleport", "Unable to change server");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Stargate.debug("bungeeTeleport", "Teleported player to another server");
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -49,4 +49,5 @@ public class PluginEventListener implements Listener {
 | 
			
		||||
            Stargate.logInfo("Vault plugin lost.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,11 @@ 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.Bukkit;
 | 
			
		||||
import org.bukkit.Location;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
import org.bukkit.World;
 | 
			
		||||
@@ -67,14 +68,23 @@ public class PortalEventListener implements Listener {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Stargate.debug("PortalEventListener::onEntityPortalEnter",
 | 
			
		||||
                    "Found player " + player + " entering END_PORTAL " + portal);
 | 
			
		||||
 | 
			
		||||
            //Remove any old player teleportations in case weird things happen
 | 
			
		||||
            playersFromTheEnd.removeIf((teleportation -> teleportation.getPlayer() == player));
 | 
			
		||||
            //Decide if the anything stops the player from teleporting
 | 
			
		||||
            if (PermissionHelper.playerCannotTeleport(portal, portal.getPortalActivator().getDestination(), player, null)) {
 | 
			
		||||
            if (PermissionHelper.playerCannotTeleport(portal, portal.getPortalActivator().getDestination(), player, null) ||
 | 
			
		||||
                    portal.getOptions().isBungee()) {
 | 
			
		||||
                //Teleport the player back to the portal they came in, just in case
 | 
			
		||||
                playersFromTheEnd.add(new FromTheEndTeleportation(player, portal));
 | 
			
		||||
                Stargate.debug("PortalEventListener::onEntityPortalEnter",
 | 
			
		||||
                        "Sending player back to the entrance");
 | 
			
		||||
            } else {
 | 
			
		||||
                playersFromTheEnd.add(new FromTheEndTeleportation(player, portal.getPortalActivator().getDestination()));
 | 
			
		||||
                Stargate.debug("PortalEventListener::onEntityPortalEnter",
 | 
			
		||||
                        "Sending player to destination");
 | 
			
		||||
            }
 | 
			
		||||
            playersFromTheEnd.add(new FromTheEndTeleportation(player, portal.getPortalActivator().getDestination()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -95,10 +105,18 @@ public class PortalEventListener implements Listener {
 | 
			
		||||
 | 
			
		||||
        Portal exitPortal = teleportation.getExit();
 | 
			
		||||
        //Overwrite respawn location to respawn in front of the portal
 | 
			
		||||
        event.setRespawnLocation(new PlayerTeleporter(exitPortal, respawningPlayer).getExit(respawningPlayer,
 | 
			
		||||
                respawningPlayer.getLocation()));
 | 
			
		||||
        PlayerTeleporter teleporter = new PlayerTeleporter(exitPortal, respawningPlayer);
 | 
			
		||||
        Location respawnLocation = teleporter.getExit();
 | 
			
		||||
        event.setRespawnLocation(respawnLocation);
 | 
			
		||||
        //Try and force the player if for some reason the changing of respawn location isn't properly handled
 | 
			
		||||
        Bukkit.getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(), () ->
 | 
			
		||||
                respawningPlayer.teleport(respawnLocation), 1);
 | 
			
		||||
 | 
			
		||||
        //Properly close the portal to prevent it from staying in a locked state until it times out
 | 
			
		||||
        exitPortal.getPortalOpener().closePortal(false);
 | 
			
		||||
 | 
			
		||||
        Stargate.debug("PortalEventListener::onRespawn", "Overwriting respawn for " + respawningPlayer +
 | 
			
		||||
                " to " + respawnLocation.getWorld() + ":" + respawnLocation);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,10 +3,10 @@ package net.knarcraft.stargate.listener;
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import net.knarcraft.stargate.portal.PortalHandler;
 | 
			
		||||
import net.knarcraft.stargate.portal.VehicleTeleporter;
 | 
			
		||||
import net.knarcraft.stargate.portal.teleporter.VehicleTeleporter;
 | 
			
		||||
import net.knarcraft.stargate.utility.EconomyHelper;
 | 
			
		||||
import net.knarcraft.stargate.utility.EntityHelper;
 | 
			
		||||
import net.knarcraft.stargate.utility.PermissionHelper;
 | 
			
		||||
import net.knarcraft.stargate.utility.TeleportHelper;
 | 
			
		||||
import org.bukkit.entity.Entity;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.entity.Vehicle;
 | 
			
		||||
@@ -61,11 +61,11 @@ public class VehicleEventListener implements Listener {
 | 
			
		||||
    private static void teleportVehicle(List<Entity> passengers, Portal entrancePortal, Vehicle vehicle) {
 | 
			
		||||
        String route = "VehicleEventListener::teleportVehicle";
 | 
			
		||||
 | 
			
		||||
        if (!passengers.isEmpty() && passengers.get(0) instanceof Player) {
 | 
			
		||||
        if (!passengers.isEmpty() && TeleportHelper.containsPlayer(passengers)) {
 | 
			
		||||
            Stargate.debug(route, "Found passenger vehicle");
 | 
			
		||||
            teleportPlayerAndVehicle(entrancePortal, vehicle, passengers);
 | 
			
		||||
            teleportPlayerAndVehicle(entrancePortal, vehicle);
 | 
			
		||||
        } else {
 | 
			
		||||
            Stargate.debug(route, "Found empty vehicle");
 | 
			
		||||
            Stargate.debug(route, "Found vehicle without players");
 | 
			
		||||
            Portal destinationPortal = entrancePortal.getPortalActivator().getDestination();
 | 
			
		||||
            if (destinationPortal == null) {
 | 
			
		||||
                Stargate.debug(route, "Unable to find portal destination");
 | 
			
		||||
@@ -73,7 +73,7 @@ public class VehicleEventListener implements Listener {
 | 
			
		||||
            }
 | 
			
		||||
            Stargate.debug("vehicleTeleport", destinationPortal.getWorld() + " " +
 | 
			
		||||
                    destinationPortal.getSignLocation());
 | 
			
		||||
            new VehicleTeleporter(destinationPortal, vehicle).teleport(entrancePortal);
 | 
			
		||||
            new VehicleTeleporter(destinationPortal, vehicle).teleportEntity(entrancePortal);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -82,81 +82,66 @@ public class VehicleEventListener implements Listener {
 | 
			
		||||
     *
 | 
			
		||||
     * @param entrancePortal <p>The portal the minecart entered</p>
 | 
			
		||||
     * @param vehicle        <p>The vehicle to teleport</p>
 | 
			
		||||
     * @param passengers     <p>Any entities sitting in the minecart</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void teleportPlayerAndVehicle(Portal entrancePortal, Vehicle vehicle, List<Entity> passengers) {
 | 
			
		||||
        Player player = (Player) passengers.get(0);
 | 
			
		||||
        //On the assumption that a non-player cannot sit in the driver's seat and since some portals can only be open
 | 
			
		||||
        // to one player at a time, we only need to check if the portal is open to the driver.
 | 
			
		||||
        if (!entrancePortal.getPortalOpener().isOpenFor(player)) {
 | 
			
		||||
            Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
 | 
			
		||||
    private static void teleportPlayerAndVehicle(Portal entrancePortal, Vehicle vehicle) {
 | 
			
		||||
        Entity rootEntity = vehicle;
 | 
			
		||||
        while (rootEntity.getVehicle() != null) {
 | 
			
		||||
            rootEntity = rootEntity.getVehicle();
 | 
			
		||||
        }
 | 
			
		||||
        List<Player> players = TeleportHelper.getPlayers(rootEntity.getPassengers());
 | 
			
		||||
        Portal destinationPortal = null;
 | 
			
		||||
 | 
			
		||||
        for (Player player : players) {
 | 
			
		||||
            //The entrance portal must be open for one player for the teleportation to happen
 | 
			
		||||
            if (!entrancePortal.getPortalOpener().isOpenFor(player)) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Check if any of the players has selected the destination
 | 
			
		||||
            Portal possibleDestinationPortal = entrancePortal.getPortalActivator().getDestination(player);
 | 
			
		||||
            if (possibleDestinationPortal != null) {
 | 
			
		||||
                destinationPortal = possibleDestinationPortal;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Cancel the teleport if no players activated the portal, or if any players are denied access
 | 
			
		||||
        boolean cancelTeleport = false;
 | 
			
		||||
        for (Player player : players) {
 | 
			
		||||
            if (destinationPortal == null) {
 | 
			
		||||
                cancelTeleport = true;
 | 
			
		||||
                if (!entrancePortal.getOptions().isSilent()) {
 | 
			
		||||
                    Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("invalidMsg"));
 | 
			
		||||
                }
 | 
			
		||||
            } else if (!TeleportHelper.playerCanTeleport(player, entrancePortal, destinationPortal)) {
 | 
			
		||||
                cancelTeleport = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (cancelTeleport) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //If no destination exists, the teleportation cannot happen
 | 
			
		||||
        Portal destinationPortal = entrancePortal.getPortalActivator().getDestination(player);
 | 
			
		||||
        if (destinationPortal == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Make sure all player passengers are allowed to, and can afford to, enter the portal
 | 
			
		||||
        for (Entity entity : passengers) {
 | 
			
		||||
            if (entity instanceof Player && !playerCanTeleport((Player) entity, entrancePortal, destinationPortal)) {
 | 
			
		||||
                return;
 | 
			
		||||
        //Take payment from all players
 | 
			
		||||
        for (Player player : players) {
 | 
			
		||||
            //To prevent the case where the first passenger pays and then the second passenger is denied, this has to be
 | 
			
		||||
            // run after it has been confirmed that all passengers are able to pay
 | 
			
		||||
            int cost = EconomyHelper.getUseCost(player, entrancePortal, destinationPortal);
 | 
			
		||||
            if (cost > 0) {
 | 
			
		||||
                if (EconomyHelper.cannotPayTeleportFee(entrancePortal, player, cost)) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //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);
 | 
			
		||||
        if (cost > 0) {
 | 
			
		||||
            if (!takePlayerPayment(passengers, entrancePortal, cost)) {
 | 
			
		||||
                return;
 | 
			
		||||
        //Teleport the vehicle and inform the user if the vehicle was teleported
 | 
			
		||||
        boolean teleported = new VehicleTeleporter(destinationPortal, vehicle).teleportEntity(entrancePortal);
 | 
			
		||||
        if (teleported) {
 | 
			
		||||
            if (!entrancePortal.getOptions().isSilent()) {
 | 
			
		||||
                for (Player player : players) {
 | 
			
		||||
                    Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
 | 
			
		||||
        new VehicleTeleporter(destinationPortal, vehicle).teleport(entrancePortal);
 | 
			
		||||
        entrancePortal.getPortalOpener().closePortal(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Takes payment from all player passengers
 | 
			
		||||
     *
 | 
			
		||||
     * @param passengers     <p>All passengers in the teleporting vehicle</p>
 | 
			
		||||
     * @param entrancePortal <p>The portal the vehicle is entering from</p>
 | 
			
		||||
     * @param cost           <p>The cost each player has to pay</p>
 | 
			
		||||
     * @return <p>True if all player passengers paid successfully</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static boolean takePlayerPayment(List<Entity> passengers, Portal entrancePortal, int cost) {
 | 
			
		||||
        for (Entity entity : passengers) {
 | 
			
		||||
            //If the passenger is a player, make it pay
 | 
			
		||||
            if (entity instanceof Player && EconomyHelper.cannotPayTeleportFee(entrancePortal, (Player) entity, cost)) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the given player is allowed to and can afford to teleport
 | 
			
		||||
     *
 | 
			
		||||
     * @param player            <p>The player trying to teleport</p>
 | 
			
		||||
     * @param entrancePortal    <p>The portal the player is entering</p>
 | 
			
		||||
     * @param destinationPortal <p>The portal the player is to exit from</p>
 | 
			
		||||
     * @return <p>True if the player is allowed to teleport and is able to pay necessary fees</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static boolean playerCanTeleport(Player player, Portal entrancePortal, Portal destinationPortal) {
 | 
			
		||||
        //Make sure the user can access the portal
 | 
			
		||||
        if (PermissionHelper.cannotAccessPortal(player, entrancePortal, destinationPortal)) {
 | 
			
		||||
            Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
 | 
			
		||||
            entrancePortal.getPortalOpener().closePortal(false);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Transfer payment if necessary
 | 
			
		||||
        int cost = Stargate.getEconomyConfig().getUseCost(player, entrancePortal, destinationPortal);
 | 
			
		||||
        return cost <= 0 || Stargate.getEconomyConfig().canAffordFee(player, cost);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -46,4 +46,5 @@ public class WorldEventListener implements Listener {
 | 
			
		||||
            PortalRegistry.clearPortals(world);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,79 +0,0 @@
 | 
			
		||||
package net.knarcraft.stargate.portal;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.event.StargatePlayerPortalEvent;
 | 
			
		||||
import org.bukkit.Location;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.event.player.PlayerMoveEvent;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The portal teleporter takes care of the actual portal teleportation for any players
 | 
			
		||||
 */
 | 
			
		||||
public class PlayerTeleporter extends Teleporter {
 | 
			
		||||
 | 
			
		||||
    private final Player player;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new player teleporter
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal <p>The portal which is the target of the teleportation</p>
 | 
			
		||||
     * @param player <p>The teleporting player</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PlayerTeleporter(Portal portal, Player player) {
 | 
			
		||||
        super(portal);
 | 
			
		||||
        this.player = player;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleports a player to this teleporter's portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param origin <p>The portal the player teleports from</p>
 | 
			
		||||
     * @param event  <p>The player move event triggering the event</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void teleport(Portal origin, PlayerMoveEvent event) {
 | 
			
		||||
        Location traveller = player.getLocation();
 | 
			
		||||
        Location exit = getExit(player, traveller);
 | 
			
		||||
 | 
			
		||||
        //Rotate the player to face out from the portal
 | 
			
		||||
        adjustRotation(exit);
 | 
			
		||||
 | 
			
		||||
        //Call the StargatePlayerPortalEvent to allow plugins to change destination
 | 
			
		||||
        if (!origin.equals(portal)) {
 | 
			
		||||
            exit = triggerPlayerPortalEvent(origin, exit, event);
 | 
			
		||||
            if (exit == null) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Load chunks to make sure not to teleport to the void
 | 
			
		||||
        loadChunks();
 | 
			
		||||
 | 
			
		||||
        //If no event is passed in, assume it's a teleport, and act as such
 | 
			
		||||
        if (event == null) {
 | 
			
		||||
            player.teleport(exit);
 | 
			
		||||
        } else {
 | 
			
		||||
            //The new method to teleport in a move event is set the "to" field.
 | 
			
		||||
            event.setTo(exit);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Triggers the player portal event to allow plugins to change the exit location
 | 
			
		||||
     *
 | 
			
		||||
     * @param origin <p>The origin portal teleported from</p>
 | 
			
		||||
     * @param exit   <p>The exit location to teleport the player to</p>
 | 
			
		||||
     * @param event  <p>The player move event which triggered the teleportation</p>
 | 
			
		||||
     * @return <p>The location the player should be teleported to, or null if the event was cancelled</p>
 | 
			
		||||
     */
 | 
			
		||||
    private Location triggerPlayerPortalEvent(Portal origin, Location exit, PlayerMoveEvent event) {
 | 
			
		||||
        StargatePlayerPortalEvent stargatePlayerPortalEvent = new StargatePlayerPortalEvent(player, origin, portal, exit);
 | 
			
		||||
        Stargate.getInstance().getServer().getPluginManager().callEvent(stargatePlayerPortalEvent);
 | 
			
		||||
        //Teleport is cancelled. Teleport the player back to where it came from
 | 
			
		||||
        if (stargatePlayerPortalEvent.isCancelled()) {
 | 
			
		||||
            new PlayerTeleporter(origin, player).teleport(origin, event);
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return stargatePlayerPortalEvent.getExit();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,16 @@
 | 
			
		||||
package net.knarcraft.stargate.portal;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.SimpleVectorOperation;
 | 
			
		||||
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 net.knarcraft.stargate.utility.DirectionHelper;
 | 
			
		||||
import net.md_5.bungee.api.ChatColor;
 | 
			
		||||
import org.bukkit.World;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
 | 
			
		||||
@@ -13,8 +22,13 @@ 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 SimpleVectorOperation vectorOperation;
 | 
			
		||||
 | 
			
		||||
    private final PortalOwner portalOwner;
 | 
			
		||||
    private boolean isRegistered;
 | 
			
		||||
 | 
			
		||||
    private final PortalOptions options;
 | 
			
		||||
    private final PortalOpener portalOpener;
 | 
			
		||||
@@ -46,6 +60,27 @@ 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);
 | 
			
		||||
        this.vectorOperation = new SimpleVectorOperation(DirectionHelper.getBlockFaceFromYaw(portalLocation.getYaw()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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 +159,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 +189,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
 | 
			
		||||
     *
 | 
			
		||||
@@ -245,7 +298,17 @@ public class Portal {
 | 
			
		||||
     * @return <p>The block at the given relative position</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockLocation getBlockAt(RelativeBlockVector vector) {
 | 
			
		||||
        return getTopLeft().getRelativeLocation(vector, getYaw());
 | 
			
		||||
        return (BlockLocation) getTopLeft().clone().add(vectorOperation.performToRealSpaceOperation(vector.toVector()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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
 | 
			
		||||
@@ -258,8 +321,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 +335,19 @@ 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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
            }
 | 
			
		||||
@@ -441,4 +448,5 @@ public class PortalHandler {
 | 
			
		||||
        }
 | 
			
		||||
        return input.replaceAll("[|:#]", "").trim();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,10 @@
 | 
			
		||||
package net.knarcraft.stargate.portal;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.config.DynmapManager;
 | 
			
		||||
import net.knarcraft.stargate.container.BlockLocation;
 | 
			
		||||
import net.knarcraft.stargate.utility.PortalFileHelper;
 | 
			
		||||
import org.bukkit.World;
 | 
			
		||||
import org.bukkit.block.Sign;
 | 
			
		||||
import org.bukkit.block.data.type.WallSign;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
@@ -37,6 +36,7 @@ public class PortalRegistry {
 | 
			
		||||
        lookupControls.clear();
 | 
			
		||||
        allPortals.clear();
 | 
			
		||||
        allPortalNetworks.clear();
 | 
			
		||||
        bungeePortals.clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -64,7 +64,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 +163,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 +204,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 +220,12 @@ 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);
 | 
			
		||||
        DynmapManager.removePortalMarker(portal);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -241,8 +237,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 +246,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 +273,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 +290,8 @@ public class PortalRegistry {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        allPortals.add(portal);
 | 
			
		||||
        portal.setRegistered(true);
 | 
			
		||||
        DynmapManager.addPortalMarker(portal);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,19 @@
 | 
			
		||||
package net.knarcraft.stargate.portal;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.knarlib.property.ColorConversion;
 | 
			
		||||
import net.knarcraft.knarlib.util.ColorHelper;
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.container.SignData;
 | 
			
		||||
import net.knarcraft.stargate.portal.property.PortalLocation;
 | 
			
		||||
import net.knarcraft.stargate.utility.PermissionHelper;
 | 
			
		||||
import org.bukkit.ChatColor;
 | 
			
		||||
import net.md_5.bungee.api.ChatColor;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
import org.bukkit.block.Block;
 | 
			
		||||
import org.bukkit.block.BlockState;
 | 
			
		||||
import org.bukkit.block.Sign;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The portal sign drawer draws the sing of a given portal
 | 
			
		||||
 */
 | 
			
		||||
@@ -14,9 +21,11 @@ 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;
 | 
			
		||||
    private static Map<Material, ChatColor> perSignMainColors;
 | 
			
		||||
    private static Map<Material, ChatColor> perSignHighlightColors;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new portal sign drawer
 | 
			
		||||
@@ -28,197 +37,311 @@ 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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the per-sign main colors
 | 
			
		||||
     *
 | 
			
		||||
     * @param signMainColors <p>The per-sign main colors</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void setPerSignMainColors(Map<Material, ChatColor> signMainColors) {
 | 
			
		||||
        PortalSignDrawer.perSignMainColors = signMainColors;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the per-sign highlight colors
 | 
			
		||||
     *
 | 
			
		||||
     * @param signHighlightColors <p>The per-sign highlight colors</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void setPerSignHighlightColors(Map<Material, ChatColor> signHighlightColors) {
 | 
			
		||||
        PortalSignDrawer.perSignHighlightColors = signHighlightColors;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the currently used main sign color
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The currently used main sign color</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static ChatColor getMainColor() {
 | 
			
		||||
        return mainColor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the currently used highlighting sign color
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The currently used highlighting sign color</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static ChatColor getHighlightColor() {
 | 
			
		||||
        return highlightColor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Draws the sign of the portal this sign drawer is responsible for
 | 
			
		||||
     */
 | 
			
		||||
    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);
 | 
			
		||||
        SignData signData = new SignData(sign, getMainColor(sign.getType()), getHighlightColor(sign.getType()));
 | 
			
		||||
        drawSign(signData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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
 | 
			
		||||
     *
 | 
			
		||||
     * @param sign <p>The sign re-draw</p>
 | 
			
		||||
     * @param signData <p>All necessary sign information</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void drawSign(Sign sign) {
 | 
			
		||||
    private void drawSign(SignData signData) {
 | 
			
		||||
        Sign sign = signData.getSign();
 | 
			
		||||
        ChatColor highlightColor = signData.getHighlightSignColor();
 | 
			
		||||
        ChatColor mainColor = signData.getMainSignColor();
 | 
			
		||||
        //Clear sign
 | 
			
		||||
        for (int index = 0; index <= 3; index++) {
 | 
			
		||||
            sign.setLine(index, "");
 | 
			
		||||
        }
 | 
			
		||||
        setLine(sign, 0, highlightColor + "-" + mainColor +
 | 
			
		||||
                portal.getName() + highlightColor + "-");
 | 
			
		||||
        clearSign(sign);
 | 
			
		||||
        setLine(signData, 0, highlightColor + "-" + mainColor + translateAllColorCodes(portal.getName()) +
 | 
			
		||||
                highlightColor + "-");
 | 
			
		||||
 | 
			
		||||
        if (!portal.getPortalActivator().isActive()) {
 | 
			
		||||
            //Default sign text
 | 
			
		||||
            drawInactiveSign(sign);
 | 
			
		||||
            drawInactiveSign(signData);
 | 
			
		||||
        } else {
 | 
			
		||||
            if (portal.getOptions().isBungee()) {
 | 
			
		||||
                //Bungee sign
 | 
			
		||||
                drawBungeeSign(sign);
 | 
			
		||||
                drawBungeeSign(signData);
 | 
			
		||||
            } else if (portal.getOptions().isFixed()) {
 | 
			
		||||
                //Sign pointing at one other portal
 | 
			
		||||
                drawFixedSign(sign);
 | 
			
		||||
                drawFixedSign(signData);
 | 
			
		||||
            } else {
 | 
			
		||||
                //Networking stuff
 | 
			
		||||
                drawNetworkSign(sign);
 | 
			
		||||
                drawNetworkSign(signData);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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, translateAllColorCodes(portal.getName()));
 | 
			
		||||
        sign.update();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Draws a sign with choose-able network locations
 | 
			
		||||
     *
 | 
			
		||||
     * @param sign <p>The sign to re-draw</p>
 | 
			
		||||
     * @param signData <p>All necessary sign information</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void drawNetworkSign(Sign sign) {
 | 
			
		||||
    private void drawNetworkSign(SignData signData) {
 | 
			
		||||
        PortalActivator destinations = portal.getPortalActivator();
 | 
			
		||||
        int maxIndex = destinations.getDestinations().size() - 1;
 | 
			
		||||
        int signLineIndex = 0;
 | 
			
		||||
        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(signData, freeGatesColored, ++signLineIndex, destinationIndex - 2);
 | 
			
		||||
        }
 | 
			
		||||
        //Not first entry. Draw the previous entry
 | 
			
		||||
        if (destinationIndex > 0) {
 | 
			
		||||
            drawNetworkSignLine(freeGatesGreen, sign, ++signLineIndex, destinationIndex - 1);
 | 
			
		||||
            drawNetworkSignLine(signData, freeGatesColored, ++signLineIndex, destinationIndex - 1);
 | 
			
		||||
        }
 | 
			
		||||
        //Draw the chosen entry (line 2 or 3)
 | 
			
		||||
        drawNetworkSignChosenLine(freeGatesGreen, sign, ++signLineIndex);
 | 
			
		||||
        drawNetworkSignChosenLine(signData, freeGatesColored, ++signLineIndex);
 | 
			
		||||
        //Has another entry and space on the sign
 | 
			
		||||
        if ((maxIndex >= destinationIndex + 1)) {
 | 
			
		||||
            drawNetworkSignLine(freeGatesGreen, sign, ++signLineIndex, destinationIndex + 1);
 | 
			
		||||
            drawNetworkSignLine(signData, freeGatesColored, ++signLineIndex, destinationIndex + 1);
 | 
			
		||||
        }
 | 
			
		||||
        //Has another entry and space on the sign
 | 
			
		||||
        if ((maxIndex >= destinationIndex + 2) && (++signLineIndex <= 3)) {
 | 
			
		||||
            drawNetworkSignLine(freeGatesGreen, sign, signLineIndex, destinationIndex + 2);
 | 
			
		||||
            drawNetworkSignLine(signData, freeGatesColored, 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 signData         <p>All necessary sign information</p>
 | 
			
		||||
     * @param freeGatesColored <p>Whether to display free gates in a different color</p>
 | 
			
		||||
     * @param signLineIndex    <p>The line to draw on</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void drawNetworkSignChosenLine(boolean freeGatesGreen, Sign sign, int signLineIndex) {
 | 
			
		||||
        if (freeGatesGreen) {
 | 
			
		||||
    private void drawNetworkSignChosenLine(SignData signData, boolean freeGatesColored, int signLineIndex) {
 | 
			
		||||
        ChatColor highlightColor = signData.getHighlightSignColor();
 | 
			
		||||
        ChatColor mainColor = signData.getMainSignColor();
 | 
			
		||||
        if (freeGatesColored) {
 | 
			
		||||
            Portal destination = PortalHandler.getByName(portal.getDestinationName(), portal.getNetwork());
 | 
			
		||||
            boolean 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(signData, signLineIndex, nameColor + ">" + (free ? freeColor : mainColor) +
 | 
			
		||||
                    translateAllColorCodes(portal.getDestinationName()) + nameColor + "<");
 | 
			
		||||
        } else {
 | 
			
		||||
            setLine(sign, signLineIndex, highlightColor + ">" + mainColor + portal.getDestinationName() +
 | 
			
		||||
                    highlightColor + "<");
 | 
			
		||||
            setLine(signData, signLineIndex, highlightColor + ">" + mainColor +
 | 
			
		||||
                    translateAllColorCodes(portal.getDestinationName()) + highlightColor + "<");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets a line on a sign, adding the chosen sign color
 | 
			
		||||
     *
 | 
			
		||||
     * @param sign  <p>The sign to update</p>
 | 
			
		||||
     * @param index <p>The index of the sign line to change</p>
 | 
			
		||||
     * @param text  <p>The new text on the sign</p>
 | 
			
		||||
     * @param signData <p>All necessary sign information</p>
 | 
			
		||||
     * @param index    <p>The index of the sign line to change</p>
 | 
			
		||||
     * @param text     <p>The new text on the sign</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setLine(Sign sign, int index, String text) {
 | 
			
		||||
        sign.setLine(index, mainColor + text);
 | 
			
		||||
    public void setLine(SignData signData, int index, String text) {
 | 
			
		||||
        ChatColor mainColor = signData.getMainSignColor();
 | 
			
		||||
        signData.getSign().setLine(index, mainColor + text);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Draws one network destination on one sign line
 | 
			
		||||
     *
 | 
			
		||||
     * @param freeGatesGreen   <p>Whether to display free gates in a green color</p>
 | 
			
		||||
     * @param sign             <p>The sign to draw on</p>
 | 
			
		||||
     * @param signData         <p>All necessary sign information</p>
 | 
			
		||||
     * @param freeGatesColored <p>Whether to display free gates in a different color</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(SignData signData, boolean freeGatesColored, int signLineIndex, int destinationIndex) {
 | 
			
		||||
        ChatColor mainColor = signData.getMainSignColor();
 | 
			
		||||
        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(signData, signLineIndex, (free ? freeColor : mainColor) + translateAllColorCodes(destinationName));
 | 
			
		||||
        } else {
 | 
			
		||||
            setLine(sign, signLineIndex, mainColor + destinationName);
 | 
			
		||||
            setLine(signData, signLineIndex, mainColor + translateAllColorCodes(destinationName));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Draws a bungee sign
 | 
			
		||||
     * Draws the sign of a BungeeCord portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param sign <p>The sign to re-draw</p>
 | 
			
		||||
     * @param signData <p>All necessary sign information</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void drawBungeeSign(Sign sign) {
 | 
			
		||||
        setLine(sign, 1, Stargate.getString("bungeeSign"));
 | 
			
		||||
        setLine(sign, 2, highlightColor + ">" + mainColor + portal.getDestinationName() + highlightColor + "<");
 | 
			
		||||
        setLine(sign, 3, highlightColor + "[" + mainColor + portal.getNetwork() + highlightColor + "]");
 | 
			
		||||
    private void drawBungeeSign(SignData signData) {
 | 
			
		||||
        ChatColor highlightColor = signData.getHighlightSignColor();
 | 
			
		||||
        ChatColor mainColor = signData.getMainSignColor();
 | 
			
		||||
        setLine(signData, 1, Stargate.getString("bungeeSign"));
 | 
			
		||||
        setLine(signData, 2, highlightColor + ">" + mainColor + translateAllColorCodes(portal.getDestinationName()) +
 | 
			
		||||
                highlightColor + "<");
 | 
			
		||||
        setLine(signData, 3, highlightColor + "[" + mainColor + translateAllColorCodes(portal.getNetwork()) +
 | 
			
		||||
                highlightColor + "]");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Draws an inactive sign
 | 
			
		||||
     * Draws the sign of an in-active portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param sign <p>The sign to re-draw</p>
 | 
			
		||||
     * <p>The sign for an in-active portal should display the right-click prompt and the network.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param signData <p>All necessary sign information</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void drawInactiveSign(Sign sign) {
 | 
			
		||||
        setLine(sign, 1, Stargate.getString("signRightClick"));
 | 
			
		||||
        setLine(sign, 2, Stargate.getString("signToUse"));
 | 
			
		||||
    private void drawInactiveSign(SignData signData) {
 | 
			
		||||
        ChatColor highlightColor = signData.getHighlightSignColor();
 | 
			
		||||
        ChatColor mainColor = signData.getMainSignColor();
 | 
			
		||||
        setLine(signData, 1, Stargate.getString("signRightClick"));
 | 
			
		||||
        setLine(signData, 2, Stargate.getString("signToUse"));
 | 
			
		||||
        if (!portal.getOptions().isNoNetwork()) {
 | 
			
		||||
            setLine(sign, 3, highlightColor + "(" + mainColor + portal.getNetwork() + highlightColor + ")");
 | 
			
		||||
            setLine(signData, 3, highlightColor + "(" + mainColor + translateAllColorCodes(portal.getNetwork()) +
 | 
			
		||||
                    highlightColor + ")");
 | 
			
		||||
        } else {
 | 
			
		||||
            setLine(sign, 3, "");
 | 
			
		||||
            setLine(signData, 3, "");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Draws a sign pointing to a fixed location
 | 
			
		||||
     *
 | 
			
		||||
     * @param sign <p>The sign to re-draw</p>
 | 
			
		||||
     * @param signData <p>All necessary sign information</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void drawFixedSign(Sign sign) {
 | 
			
		||||
    private void drawFixedSign(SignData signData) {
 | 
			
		||||
        ChatColor highlightColor = signData.getHighlightSignColor();
 | 
			
		||||
        ChatColor mainColor = signData.getMainSignColor();
 | 
			
		||||
        Portal destinationPortal = PortalHandler.getByName(Portal.cleanString(portal.getDestinationName()),
 | 
			
		||||
                portal.getCleanNetwork());
 | 
			
		||||
        String destinationName = portal.getOptions().isRandom() ? Stargate.getString("signRandom") :
 | 
			
		||||
                portal.getDestinationName();
 | 
			
		||||
        setLine(sign, 1, highlightColor + ">" + mainColor + destinationName + highlightColor + "<");
 | 
			
		||||
                (destinationPortal != null ? destinationPortal.getName() : portal.getDestinationName());
 | 
			
		||||
        setLine(signData, 1, highlightColor + ">" + mainColor + translateAllColorCodes(destinationName) +
 | 
			
		||||
                highlightColor + "<");
 | 
			
		||||
 | 
			
		||||
        if (portal.getOptions().isNoNetwork()) {
 | 
			
		||||
            setLine(sign, 2, "");
 | 
			
		||||
            setLine(signData, 2, "");
 | 
			
		||||
        } else {
 | 
			
		||||
            setLine(sign, 2, highlightColor + "(" + mainColor + portal.getNetwork() + highlightColor + ")");
 | 
			
		||||
            setLine(signData, 2, highlightColor + "(" + mainColor +
 | 
			
		||||
                    translateAllColorCodes(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"));
 | 
			
		||||
            setLine(signData, 3, errorColor + Stargate.getString("signDisconnected"));
 | 
			
		||||
        } else {
 | 
			
		||||
            setLine(sign, 3, "");
 | 
			
		||||
            setLine(signData, 3, "");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -230,11 +353,54 @@ 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));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the main color to use for the given sign type
 | 
			
		||||
     *
 | 
			
		||||
     * @param signType <p>The sign type to get the main color for</p>
 | 
			
		||||
     * @return <p>The main color for the given sign type</p>
 | 
			
		||||
     */
 | 
			
		||||
    private ChatColor getMainColor(Material signType) {
 | 
			
		||||
        ChatColor signColor = perSignMainColors.get(signType);
 | 
			
		||||
        if (signColor == null) {
 | 
			
		||||
            return mainColor;
 | 
			
		||||
        } else {
 | 
			
		||||
            return signColor;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the highlight color to use for the given sign type
 | 
			
		||||
     *
 | 
			
		||||
     * @param signType <p>The sign type to get the highlight color for</p>
 | 
			
		||||
     * @return <p>The highlight color for the given sign type</p>
 | 
			
		||||
     */
 | 
			
		||||
    private ChatColor getHighlightColor(Material signType) {
 | 
			
		||||
        ChatColor signColor = perSignHighlightColors.get(signType);
 | 
			
		||||
        if (signColor == null) {
 | 
			
		||||
            return highlightColor;
 | 
			
		||||
        } else {
 | 
			
		||||
            return signColor;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Translates all normal and RGB color codes in the given input
 | 
			
		||||
     *
 | 
			
		||||
     * @param input <p>The input to translate color codes for</p>
 | 
			
		||||
     * @return <p>The input with color codes converted translated from & to §</p>
 | 
			
		||||
     */
 | 
			
		||||
    private String translateAllColorCodes(String input) {
 | 
			
		||||
        return ColorHelper.translateColorCodes(input, ColorConversion.RGB);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,189 +0,0 @@
 | 
			
		||||
package net.knarcraft.stargate.portal;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.event.StargateEntityPortalEvent;
 | 
			
		||||
import net.knarcraft.stargate.utility.DirectionHelper;
 | 
			
		||||
import org.bukkit.Location;
 | 
			
		||||
import org.bukkit.World;
 | 
			
		||||
import org.bukkit.entity.Entity;
 | 
			
		||||
import org.bukkit.entity.LivingEntity;
 | 
			
		||||
import org.bukkit.entity.Vehicle;
 | 
			
		||||
import org.bukkit.util.Vector;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The portal teleporter takes care of the actual portal teleportation for any vehicles
 | 
			
		||||
 */
 | 
			
		||||
public class VehicleTeleporter extends Teleporter {
 | 
			
		||||
 | 
			
		||||
    private final Vehicle teleportingVehicle;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new vehicle teleporter
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal             <p>The portal which is the target of the teleportation</p>
 | 
			
		||||
     * @param teleportingVehicle <p>The teleporting vehicle</p>
 | 
			
		||||
     */
 | 
			
		||||
    public VehicleTeleporter(Portal portal, Vehicle teleportingVehicle) {
 | 
			
		||||
        super(portal);
 | 
			
		||||
        this.teleportingVehicle = teleportingVehicle;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleports a vehicle to this teleporter's portal
 | 
			
		||||
     *
 | 
			
		||||
     * <p>It is assumed that if a vehicle contains any players, their permissions have already been validated before
 | 
			
		||||
     * calling this method.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param origin <p>The portal the vehicle teleports from</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void teleport(Portal origin) {
 | 
			
		||||
        Location traveller = teleportingVehicle.getLocation();
 | 
			
		||||
        Location exit = getExit(teleportingVehicle, traveller);
 | 
			
		||||
 | 
			
		||||
        double velocity = teleportingVehicle.getVelocity().length();
 | 
			
		||||
 | 
			
		||||
        //Stop and teleport
 | 
			
		||||
        teleportingVehicle.setVelocity(new Vector());
 | 
			
		||||
 | 
			
		||||
        //Get new velocity
 | 
			
		||||
        Vector newVelocityDirection = DirectionHelper.getDirectionVectorFromYaw(portal.getYaw());
 | 
			
		||||
        Vector newVelocity = newVelocityDirection.multiply(velocity);
 | 
			
		||||
 | 
			
		||||
        //Make sure the vehicle points out from the portal
 | 
			
		||||
        adjustRotation(exit);
 | 
			
		||||
 | 
			
		||||
        //Call the StargateEntityPortalEvent to allow plugins to change destination
 | 
			
		||||
        if (!origin.equals(portal)) {
 | 
			
		||||
            exit = triggerEntityPortalEvent(origin, exit);
 | 
			
		||||
            if (exit == null) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Teleport the vehicle
 | 
			
		||||
        teleportVehicle(exit, newVelocity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleports a vehicle with any passengers to the given location
 | 
			
		||||
     *
 | 
			
		||||
     * @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>
 | 
			
		||||
     */
 | 
			
		||||
    private void teleportVehicle(Location exit, Vector newVelocity) {
 | 
			
		||||
        //Load chunks to make sure not to teleport to the void
 | 
			
		||||
        loadChunks();
 | 
			
		||||
 | 
			
		||||
        List<Entity> passengers = teleportingVehicle.getPassengers();
 | 
			
		||||
        if (!passengers.isEmpty()) {
 | 
			
		||||
            if (!(teleportingVehicle instanceof LivingEntity)) {
 | 
			
		||||
                //Teleport a normal vehicle with passengers (minecart or boat)
 | 
			
		||||
                putPassengersInNewVehicle(passengers, exit, newVelocity);
 | 
			
		||||
            } else {
 | 
			
		||||
                //Teleport a living vehicle with passengers (pig, horse, donkey, strider)
 | 
			
		||||
                teleportLivingVehicle(exit, passengers);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            //Teleport an empty vehicle
 | 
			
		||||
            teleportingVehicle.teleport(exit);
 | 
			
		||||
            scheduler.scheduleSyncDelayedTask(Stargate.getInstance(),
 | 
			
		||||
                    () -> teleportingVehicle.setVelocity(newVelocity), 1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Triggers the entity portal event to allow plugins to change the exit location
 | 
			
		||||
     *
 | 
			
		||||
     * @param origin <p>The origin portal teleported from</p>
 | 
			
		||||
     * @param exit   <p>The exit location to teleport the vehicle to</p>
 | 
			
		||||
     * @return <p>The location the vehicle should be teleported to, or null if the event was cancelled</p>
 | 
			
		||||
     */
 | 
			
		||||
    private Location triggerEntityPortalEvent(Portal origin, Location exit) {
 | 
			
		||||
        StargateEntityPortalEvent stargateEntityPortalEvent = new StargateEntityPortalEvent(teleportingVehicle, origin,
 | 
			
		||||
                portal, exit);
 | 
			
		||||
        Stargate.getInstance().getServer().getPluginManager().callEvent(stargateEntityPortalEvent);
 | 
			
		||||
        //Teleport is cancelled. Teleport the entity back to where it came from just for sanity's sake
 | 
			
		||||
        if (stargateEntityPortalEvent.isCancelled()) {
 | 
			
		||||
            new VehicleTeleporter(origin, teleportingVehicle).teleport(origin);
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return stargateEntityPortalEvent.getExit();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleport a vehicle which is not a minecart or a boat
 | 
			
		||||
     *
 | 
			
		||||
     * @param exit       <p>The location the vehicle will exit</p>
 | 
			
		||||
     * @param passengers <p>The passengers of the vehicle</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void teleportLivingVehicle(Location exit, List<Entity> passengers) {
 | 
			
		||||
        teleportingVehicle.eject();
 | 
			
		||||
        teleportingVehicle.teleport(exit);
 | 
			
		||||
        handleVehiclePassengers(passengers, teleportingVehicle, 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new vehicle equal to the player's previous vehicle and puts any passengers inside
 | 
			
		||||
     *
 | 
			
		||||
     * <p>While it is possible to teleport boats and minecarts using the same methods as "teleportLivingVehicle", this
 | 
			
		||||
     * method works better with CraftBook with minecart options enabled. Using normal teleportation, CraftBook destroys
 | 
			
		||||
     * the minecart once the player is ejected, causing the minecart to disappear and the player to teleport without it.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param passengers  <p>A list of all passengers in the vehicle</p>
 | 
			
		||||
     * @param exit        <p>The exit location to spawn the new vehicle on</p>
 | 
			
		||||
     * @param newVelocity <p>The new velocity of the new vehicle</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void putPassengersInNewVehicle(List<Entity> passengers, Location exit,
 | 
			
		||||
                                           Vector newVelocity) {
 | 
			
		||||
        World vehicleWorld = exit.getWorld();
 | 
			
		||||
        if (vehicleWorld == null) {
 | 
			
		||||
            Stargate.logWarning("Unable to get the world to teleport the vehicle to");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        //Spawn a new vehicle
 | 
			
		||||
        Vehicle newVehicle = vehicleWorld.spawn(exit, teleportingVehicle.getClass());
 | 
			
		||||
        //Remove the old vehicle
 | 
			
		||||
        teleportingVehicle.eject();
 | 
			
		||||
        teleportingVehicle.remove();
 | 
			
		||||
        //Set rotation, add passengers and restore velocity
 | 
			
		||||
        newVehicle.setRotation(exit.getYaw(), exit.getPitch());
 | 
			
		||||
        handleVehiclePassengers(passengers, newVehicle, 1);
 | 
			
		||||
        scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> newVehicle.setVelocity(newVelocity), 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Ejects, teleports and adds all passengers to the target vehicle
 | 
			
		||||
     *
 | 
			
		||||
     * @param passengers <p>The passengers to handle</p>
 | 
			
		||||
     * @param vehicle    <p>The vehicle the passengers should be put into</p>
 | 
			
		||||
     * @param delay      <p>The amount of milliseconds to wait before adding the vehicle passengers</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void handleVehiclePassengers(List<Entity> passengers, Vehicle vehicle, long delay) {
 | 
			
		||||
        for (Entity passenger : passengers) {
 | 
			
		||||
            passenger.eject();
 | 
			
		||||
            scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> teleportAndAddPassenger(vehicle, passenger),
 | 
			
		||||
                    delay);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleports and adds a passenger to a vehicle
 | 
			
		||||
     *
 | 
			
		||||
     * <p>Teleportation of living vehicles is really buggy if you wait between the teleportation and passenger adding,
 | 
			
		||||
     * but there needs to be a delay between teleporting the vehicle and teleporting and adding the passenger.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param targetVehicle <p>The vehicle to add the passenger to</p>
 | 
			
		||||
     * @param passenger     <p>The passenger to teleport and add</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void teleportAndAddPassenger(Vehicle targetVehicle, Entity passenger) {
 | 
			
		||||
        if (!passenger.teleport(targetVehicle.getLocation())) {
 | 
			
		||||
            Stargate.debug("handleVehiclePassengers", "Failed to teleport passenger");
 | 
			
		||||
        }
 | 
			
		||||
        if (!targetVehicle.addPassenger(passenger)) {
 | 
			
		||||
            Stargate.debug("handleVehiclePassengers", "Failed to add passenger");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package net.knarcraft.stargate.portal;
 | 
			
		||||
package net.knarcraft.stargate.portal.property;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
@@ -43,6 +43,22 @@ public class PortalOwner {
 | 
			
		||||
        return ownerUUID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the unique id for a portal owner without one
 | 
			
		||||
     *
 | 
			
		||||
     * <p>This method is only meant to be used to set the unique id for an owner without one. If the owner already has
 | 
			
		||||
     * an unique id, an exception will be thrown.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param uniqueId <p>The new unique id for the portal owner</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setUUID(UUID uniqueId) {
 | 
			
		||||
        if (ownerUUID == null) {
 | 
			
		||||
            ownerUUID = uniqueId;
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new IllegalArgumentException("An existing UUID cannot be overwritten.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the name of this owner
 | 
			
		||||
     *
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -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
 | 
			
		||||
     *
 | 
			
		||||
@@ -226,7 +235,7 @@ public class Gate {
 | 
			
		||||
            Material type = topLeft.getRelativeLocation(entranceVector, yaw).getType();
 | 
			
		||||
 | 
			
		||||
            //Ignore entrance if it's air or water, and we're creating a new gate
 | 
			
		||||
            if (onCreate && (type == Material.AIR || type == Material.WATER)) {
 | 
			
		||||
            if (onCreate && (type.isAir() || type == Material.WATER)) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package net.knarcraft.stargate.portal;
 | 
			
		||||
package net.knarcraft.stargate.portal.property.gate;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.container.RelativeBlockVector;
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
package net.knarcraft.stargate.portal.teleporter;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.event.StargateEntityPortalEvent;
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import org.bukkit.entity.Entity;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The portal teleporter takes care of the actual portal teleportation for any entities
 | 
			
		||||
 */
 | 
			
		||||
public class EntityTeleporter extends Teleporter {
 | 
			
		||||
 | 
			
		||||
    private final Entity teleportingEntity;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new portal teleporter
 | 
			
		||||
     *
 | 
			
		||||
     * @param targetPortal <p>The portal which is the target of the teleportation</p>
 | 
			
		||||
     */
 | 
			
		||||
    public EntityTeleporter(Portal targetPortal, Entity teleportingEntity) {
 | 
			
		||||
        super(targetPortal, teleportingEntity);
 | 
			
		||||
        this.teleportingEntity = teleportingEntity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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 boolean teleportEntity(Portal origin) {
 | 
			
		||||
        return teleport(origin, new StargateEntityPortalEvent(teleportingEntity, origin, portal, exit));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,78 @@
 | 
			
		||||
package net.knarcraft.stargate.portal.teleporter;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.event.StargatePlayerPortalEvent;
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import net.knarcraft.stargate.utility.DirectionHelper;
 | 
			
		||||
import net.knarcraft.stargate.utility.TeleportHelper;
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.entity.Entity;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.event.player.PlayerMoveEvent;
 | 
			
		||||
import org.bukkit.util.Vector;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The portal teleporter takes care of the actual portal teleportation for any players
 | 
			
		||||
 */
 | 
			
		||||
public class PlayerTeleporter extends Teleporter {
 | 
			
		||||
 | 
			
		||||
    private final Player player;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new player teleporter
 | 
			
		||||
     *
 | 
			
		||||
     * @param targetPortal <p>The portal which is the target of the teleportation</p>
 | 
			
		||||
     * @param player       <p>The teleporting player</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PlayerTeleporter(Portal targetPortal, Player player) {
 | 
			
		||||
        super(targetPortal, player);
 | 
			
		||||
        this.player = player;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleports a player to this teleporter's portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param origin <p>The portal the player teleports from</p>
 | 
			
		||||
     * @param event  <p>The player move event triggering the event</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void teleportPlayer(Portal origin, PlayerMoveEvent event) {
 | 
			
		||||
        double velocity = player.getVelocity().length();
 | 
			
		||||
        List<Entity> passengers = player.getPassengers();
 | 
			
		||||
 | 
			
		||||
        //Call the StargatePlayerPortalEvent to allow plugins to change destination
 | 
			
		||||
        if (!origin.equals(portal)) {
 | 
			
		||||
            exit = triggerPortalEvent(origin, new StargatePlayerPortalEvent(player, origin, portal, exit));
 | 
			
		||||
            if (exit == null) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Calculate the exit velocity of the player
 | 
			
		||||
        Vector newVelocityDirection = DirectionHelper.getDirectionVectorFromYaw(portal.getYaw());
 | 
			
		||||
        Vector newVelocity = newVelocityDirection.multiply(velocity * Stargate.getGateConfig().getExitVelocity());
 | 
			
		||||
 | 
			
		||||
        //Load chunks to make sure not to teleport to the void
 | 
			
		||||
        loadChunks();
 | 
			
		||||
 | 
			
		||||
        //Teleport any creatures leashed by the player in a 15-block range
 | 
			
		||||
        TeleportHelper.teleportLeashedCreatures(player, origin, portal);
 | 
			
		||||
 | 
			
		||||
        if (player.eject()) {
 | 
			
		||||
            TeleportHelper.handleEntityPassengers(passengers, player, origin, portal, exit.getDirection(), newVelocity);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //If no event is passed in, assume it's a teleport, and act as such
 | 
			
		||||
        if (event == null) {
 | 
			
		||||
            player.teleport(exit);
 | 
			
		||||
        } else {
 | 
			
		||||
            //Set the exit location of the event
 | 
			
		||||
            event.setTo(exit);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Set the velocity of the teleported player after the teleportation is finished
 | 
			
		||||
        Bukkit.getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(), () -> player.setVelocity(newVelocity), 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +1,14 @@
 | 
			
		||||
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.event.StargateTeleportEvent;
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import net.knarcraft.stargate.utility.DirectionHelper;
 | 
			
		||||
import net.knarcraft.stargate.utility.EntityHelper;
 | 
			
		||||
import net.knarcraft.stargate.utility.TeleportHelper;
 | 
			
		||||
import org.bukkit.Chunk;
 | 
			
		||||
import org.bukkit.Location;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
@@ -14,7 +17,9 @@ import org.bukkit.block.data.BlockData;
 | 
			
		||||
import org.bukkit.block.data.type.Slab;
 | 
			
		||||
import org.bukkit.entity.AbstractHorse;
 | 
			
		||||
import org.bukkit.entity.Entity;
 | 
			
		||||
import org.bukkit.event.Event;
 | 
			
		||||
import org.bukkit.scheduler.BukkitScheduler;
 | 
			
		||||
import org.bukkit.util.Vector;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -28,71 +33,114 @@ public abstract class Teleporter {
 | 
			
		||||
     * The portal the entity is teleporting to
 | 
			
		||||
     */
 | 
			
		||||
    protected final Portal portal;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The scheduler to use for delaying tasks
 | 
			
		||||
     */
 | 
			
		||||
    protected final BukkitScheduler scheduler;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The exit location any entities will be teleported to
 | 
			
		||||
     */
 | 
			
		||||
    protected Location exit;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The entity being teleported by this teleporter
 | 
			
		||||
     */
 | 
			
		||||
    protected final Entity teleportedEntity;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new portal teleporter
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal <p>The portal which is the target of the teleportation</p>
 | 
			
		||||
     * @param portal           <p>The portal which is the target of the teleportation</p>
 | 
			
		||||
     * @param teleportedEntity <p>The entity teleported by this teleporter</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Teleporter(Portal portal) {
 | 
			
		||||
    public Teleporter(Portal portal, Entity teleportedEntity) {
 | 
			
		||||
        this.portal = portal;
 | 
			
		||||
        this.scheduler = Stargate.getInstance().getServer().getScheduler();
 | 
			
		||||
        this.teleportedEntity = teleportedEntity;
 | 
			
		||||
        this.exit = getExit(teleportedEntity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleports an entity
 | 
			
		||||
     *
 | 
			
		||||
     * @param origin                <p>The portal the entity teleported from</p>
 | 
			
		||||
     * @param stargateTeleportEvent <p>The event to call to make sure the teleportation is valid</p>
 | 
			
		||||
     * @return <p>True if the teleportation was successfully performed</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean teleport(Portal origin, StargateTeleportEvent stargateTeleportEvent) {
 | 
			
		||||
        List<Entity> passengers = teleportedEntity.getPassengers();
 | 
			
		||||
 | 
			
		||||
        //Call the StargateEntityPortalEvent to allow plugins to change destination
 | 
			
		||||
        if (!origin.equals(portal)) {
 | 
			
		||||
            exit = triggerPortalEvent(origin, stargateTeleportEvent);
 | 
			
		||||
            if (exit == null) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Load chunks to make sure not to teleport to the void
 | 
			
		||||
        loadChunks();
 | 
			
		||||
 | 
			
		||||
        if (teleportedEntity.eject()) {
 | 
			
		||||
            TeleportHelper.handleEntityPassengers(passengers, teleportedEntity, origin, portal, exit.getDirection(),
 | 
			
		||||
                    new Vector());
 | 
			
		||||
        }
 | 
			
		||||
        teleportedEntity.teleport(exit);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the exit location of this teleporter
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The exit location of this teleporter</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Location getExit() {
 | 
			
		||||
        return exit.clone();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Triggers the entity portal event to allow plugins to change the exit location
 | 
			
		||||
     *
 | 
			
		||||
     * @param origin                <p>The origin portal teleported from</p>
 | 
			
		||||
     * @param stargateTeleportEvent <p>The exit location to teleport the entity to</p>
 | 
			
		||||
     * @return <p>The location the entity should be teleported to, or null if the event was cancelled</p>
 | 
			
		||||
     */
 | 
			
		||||
    protected Location triggerPortalEvent(Portal origin, StargateTeleportEvent stargateTeleportEvent) {
 | 
			
		||||
        Stargate.getInstance().getServer().getPluginManager().callEvent((Event) stargateTeleportEvent);
 | 
			
		||||
        //Teleport is cancelled. Teleport the entity back to where it came from just for sanity's sake
 | 
			
		||||
        if (stargateTeleportEvent.isCancelled()) {
 | 
			
		||||
            new EntityTeleporter(origin, teleportedEntity).teleportEntity(origin);
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return stargateTeleportEvent.getExit();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adjusts the rotation of the exit to make the teleporting entity face directly out from the portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param exit <p>The location the entity will exit from</p>
 | 
			
		||||
     */
 | 
			
		||||
    protected void adjustRotation(Location exit) {
 | 
			
		||||
    protected void adjustExitLocationRotation(Location exit) {
 | 
			
		||||
        int adjust = 0;
 | 
			
		||||
        if (portal.getOptions().isBackwards()) {
 | 
			
		||||
            adjust = 180;
 | 
			
		||||
        }
 | 
			
		||||
        float newYaw = (portal.getYaw() + adjust) % 360;
 | 
			
		||||
        Stargate.debug("Portal::adjustRotation", "Setting exit yaw to " + newYaw);
 | 
			
		||||
        exit.setYaw(newYaw);
 | 
			
		||||
        exit.setDirection(DirectionHelper.getDirectionVectorFromYaw(newYaw));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the exit location for a given entity and current location
 | 
			
		||||
     *
 | 
			
		||||
     * @param entity    <p>The entity to teleport (used to determine distance from portal to avoid suffocation)</p>
 | 
			
		||||
     * @param traveller <p>The location of the entity travelling</p>
 | 
			
		||||
     * @return <p>The location the entity should be teleported to.</p>
 | 
			
		||||
     * Loads the chunks outside the portal's entrance
 | 
			
		||||
     */
 | 
			
		||||
    public Location getExit(Entity entity, Location traveller) {
 | 
			
		||||
        Location exitLocation = null;
 | 
			
		||||
        RelativeBlockVector relativeExit = portal.getGate().getLayout().getExit();
 | 
			
		||||
        if (relativeExit != null) {
 | 
			
		||||
            BlockLocation exit = portal.getBlockAt(relativeExit);
 | 
			
		||||
 | 
			
		||||
            //Move one block out to prevent exiting inside the portal
 | 
			
		||||
            float portalYaw = portal.getYaw();
 | 
			
		||||
            if (portal.getOptions().isBackwards()) {
 | 
			
		||||
                portalYaw += 180;
 | 
			
		||||
            }
 | 
			
		||||
            exitLocation = exit.getRelativeLocation(0D, 0D, 1, portalYaw);
 | 
			
		||||
 | 
			
		||||
            if (entity != null) {
 | 
			
		||||
                double entitySize = EntityHelper.getEntityMaxSize(entity);
 | 
			
		||||
                //Prevent exit suffocation for players riding horses or similar
 | 
			
		||||
                if (entitySize > 1) {
 | 
			
		||||
                    exitLocation = preventExitSuffocation(relativeExit, exitLocation, entity);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            Stargate.logWarning(String.format("Missing destination point in .gate file %s",
 | 
			
		||||
                    portal.getGate().getFilename()));
 | 
			
		||||
    protected void loadChunks() {
 | 
			
		||||
        for (Chunk chunk : getChunksToLoad()) {
 | 
			
		||||
            chunk.addPluginChunkTicket(Stargate.getInstance());
 | 
			
		||||
            //Allow the chunk to unload after 10 seconds
 | 
			
		||||
            Stargate.addChunkUnloadRequest(new ChunkUnloadRequest(chunk, 10000L));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Adjust pitch and height
 | 
			
		||||
        return adjustExitLocation(traveller, exitLocation);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -138,7 +186,7 @@ public abstract class Teleporter {
 | 
			
		||||
        if (entitySize > 1) {
 | 
			
		||||
            double entityOffset;
 | 
			
		||||
            if (portal.getOptions().isAlwaysOn()) {
 | 
			
		||||
                entityOffset = entityBoxSize / 2D;
 | 
			
		||||
                entityOffset = (entityBoxSize / 2D);
 | 
			
		||||
            } else {
 | 
			
		||||
                entityOffset = (entitySize / 2D) - 1;
 | 
			
		||||
            }
 | 
			
		||||
@@ -182,41 +230,62 @@ public abstract class Teleporter {
 | 
			
		||||
     * slab check is necessary to prevent the player from clipping through the slab and spawning beneath it. The water
 | 
			
		||||
     * check is necessary when teleporting boats to prevent it from becoming a submarine.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param traveller    <p>The location of the travelling entity</p>
 | 
			
		||||
     * @param entity       <p>The travelling entity</p>
 | 
			
		||||
     * @param exitLocation <p>The exit location generated</p>
 | 
			
		||||
     * @return <p>The location the travelling entity should be teleported to</p>
 | 
			
		||||
     */
 | 
			
		||||
    private Location adjustExitLocation(Location traveller, Location exitLocation) {
 | 
			
		||||
    private Location adjustExitLocationHeight(Entity entity, Location exitLocation) {
 | 
			
		||||
        if (exitLocation != null) {
 | 
			
		||||
            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) {
 | 
			
		||||
                //Prevent traveller from spawning inside a slab
 | 
			
		||||
                Stargate.debug("adjustExitLocation", "Added a block to get above a slab");
 | 
			
		||||
                exitLocation.add(0, 1, 0);
 | 
			
		||||
            } else if (blockData.getMaterial() == Material.WATER) {
 | 
			
		||||
                //If there's water outside, go one up to allow for boat teleportation
 | 
			
		||||
                Stargate.debug("adjustExitLocation", "Added a block to get above a block of water");
 | 
			
		||||
            BlockData blockData = exitLocation.getBlock().getBlockData();
 | 
			
		||||
            if ((blockData instanceof Bisected bisected && bisected.getHalf() == Bisected.Half.BOTTOM) ||
 | 
			
		||||
                    (blockData instanceof Slab slab && slab.getType() == Slab.Type.BOTTOM) ||
 | 
			
		||||
                    blockData.getMaterial() == Material.WATER) {
 | 
			
		||||
                //Prevent traveller from spawning inside a slab, or a boat from spawning inside water
 | 
			
		||||
                Stargate.debug("adjustExitLocation", "Added a block to get above a slab or a block of water");
 | 
			
		||||
                exitLocation.add(0, 1, 0);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            exitLocation.setPitch(traveller.getPitch());
 | 
			
		||||
            return exitLocation;
 | 
			
		||||
        } else {
 | 
			
		||||
            Stargate.logWarning("Unable to generate exit location");
 | 
			
		||||
            return traveller;
 | 
			
		||||
            return entity.getLocation();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads the chunks outside the portal's entrance
 | 
			
		||||
     * Gets the exit location for a given entity and current location
 | 
			
		||||
     *
 | 
			
		||||
     * @param entity <p>The entity to teleport (used to determine distance from portal to avoid suffocation)</p>
 | 
			
		||||
     * @return <p>The location the entity should be teleported to.</p>
 | 
			
		||||
     */
 | 
			
		||||
    protected void loadChunks() {
 | 
			
		||||
        for (Chunk chunk : getChunksToLoad()) {
 | 
			
		||||
            chunk.addPluginChunkTicket(Stargate.getInstance());
 | 
			
		||||
            //Allow the chunk to unload after 3 seconds
 | 
			
		||||
            Stargate.addChunkUnloadRequest(new ChunkUnloadRequest(chunk, 3000L));
 | 
			
		||||
    private Location getExit(Entity entity) {
 | 
			
		||||
        Location exitLocation = null;
 | 
			
		||||
        RelativeBlockVector relativeExit = portal.getGate().getLayout().getExit();
 | 
			
		||||
        if (relativeExit != null) {
 | 
			
		||||
            BlockLocation exit = portal.getBlockAt(relativeExit);
 | 
			
		||||
 | 
			
		||||
            //Move one block out to prevent exiting inside the portal
 | 
			
		||||
            float portalYaw = portal.getYaw();
 | 
			
		||||
            if (portal.getOptions().isBackwards()) {
 | 
			
		||||
                portalYaw += 180;
 | 
			
		||||
            }
 | 
			
		||||
            exitLocation = exit.getRelativeLocation(0D, 0D, 1, portalYaw);
 | 
			
		||||
 | 
			
		||||
            if (entity != null) {
 | 
			
		||||
                double entitySize = EntityHelper.getEntityMaxSize(entity);
 | 
			
		||||
                //Prevent exit suffocation for players riding horses or similar
 | 
			
		||||
                if (entitySize > 1) {
 | 
			
		||||
                    exitLocation = preventExitSuffocation(relativeExit, exitLocation, entity);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            Stargate.logWarning(String.format("Missing destination point in .gate file %s",
 | 
			
		||||
                    portal.getGate().getFilename()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Adjust height and rotation
 | 
			
		||||
        Location adjusted = adjustExitLocationHeight(entity, exitLocation);
 | 
			
		||||
        adjustExitLocationRotation(adjusted);
 | 
			
		||||
        return adjusted;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -0,0 +1,183 @@
 | 
			
		||||
package net.knarcraft.stargate.portal.teleporter;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.config.StargateGateConfig;
 | 
			
		||||
import net.knarcraft.stargate.event.StargateEntityPortalEvent;
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import net.knarcraft.stargate.utility.DirectionHelper;
 | 
			
		||||
import net.knarcraft.stargate.utility.TeleportHelper;
 | 
			
		||||
import org.bukkit.Location;
 | 
			
		||||
import org.bukkit.World;
 | 
			
		||||
import org.bukkit.entity.Boat;
 | 
			
		||||
import org.bukkit.entity.Entity;
 | 
			
		||||
import org.bukkit.entity.LivingEntity;
 | 
			
		||||
import org.bukkit.entity.Vehicle;
 | 
			
		||||
import org.bukkit.event.player.PlayerTeleportEvent;
 | 
			
		||||
import org.bukkit.util.Vector;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The portal teleporter takes care of the actual portal teleportation for any vehicles
 | 
			
		||||
 */
 | 
			
		||||
public class VehicleTeleporter extends EntityTeleporter {
 | 
			
		||||
 | 
			
		||||
    private final Vehicle teleportingVehicle;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new vehicle teleporter
 | 
			
		||||
     *
 | 
			
		||||
     * @param targetPortal       <p>The targetPortal which is the target of the teleportation</p>
 | 
			
		||||
     * @param teleportingVehicle <p>The teleporting vehicle</p>
 | 
			
		||||
     */
 | 
			
		||||
    public VehicleTeleporter(Portal targetPortal, Vehicle teleportingVehicle) {
 | 
			
		||||
        super(targetPortal, teleportingVehicle);
 | 
			
		||||
        this.teleportingVehicle = teleportingVehicle;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleports a vehicle to this teleporter's portal
 | 
			
		||||
     *
 | 
			
		||||
     * <p>It is assumed that if a vehicle contains any players, their permissions have already been validated before
 | 
			
		||||
     * 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 boolean teleportEntity(Portal origin) {
 | 
			
		||||
        Stargate.debug("VehicleTeleporter::teleport", "Preparing to teleport: " + teleportingVehicle);
 | 
			
		||||
 | 
			
		||||
        double velocity = teleportingVehicle.getVelocity().length();
 | 
			
		||||
 | 
			
		||||
        //Stop the vehicle before teleporting
 | 
			
		||||
        teleportingVehicle.setVelocity(new Vector());
 | 
			
		||||
 | 
			
		||||
        //Get new velocity
 | 
			
		||||
        Vector newVelocityDirection = DirectionHelper.getDirectionVectorFromYaw(portal.getYaw());
 | 
			
		||||
        Vector newVelocity = newVelocityDirection.multiply(velocity);
 | 
			
		||||
 | 
			
		||||
        //Call the StargateEntityPortalEvent to allow plugins to change destination
 | 
			
		||||
        exit = triggerPortalEvent(origin, new StargateEntityPortalEvent(teleportingVehicle, origin, portal, exit));
 | 
			
		||||
        if (exit == null) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Teleport the vehicle
 | 
			
		||||
        return teleportVehicle(exit, newVelocity, origin);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleports a vehicle with any passengers to the given location
 | 
			
		||||
     *
 | 
			
		||||
     * @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 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) &&
 | 
			
		||||
                    Stargate.getGateConfig().enableCraftBookRemoveOnEjectFix()) {
 | 
			
		||||
                //Teleport a normal vehicle with passengers (minecart or boat)
 | 
			
		||||
                putPassengersInNewVehicle(passengers, exit, newVelocity, origin);
 | 
			
		||||
            } else {
 | 
			
		||||
                //Teleport a living vehicle with passengers (pig, horse, donkey, strider)
 | 
			
		||||
                teleportVehicle(passengers, exit, newVelocity, 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 (TeleportHelper.containsNonPlayer(passengers) && !config.handleCreatureTransportation()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        //Don't teleport if the player does not contain a player and non-player vehicles is disabled
 | 
			
		||||
        return TeleportHelper.containsPlayer(passengers) || config.handleNonPlayerVehicles();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleport a vehicle which is not a minecart or a boat
 | 
			
		||||
     *
 | 
			
		||||
     * @param passengers  <p>The passengers of the vehicle</p>
 | 
			
		||||
     * @param exit        <p>The location the vehicle will exit</p>
 | 
			
		||||
     * @param newVelocity <p>The new velocity of the teleported vehicle</p>
 | 
			
		||||
     * @param origin      <p>The portal the vehicle teleported from</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void teleportVehicle(List<Entity> passengers, Location exit, Vector newVelocity, Portal origin) {
 | 
			
		||||
        if (teleportingVehicle.eject()) {
 | 
			
		||||
            TeleportHelper.handleEntityPassengers(passengers, teleportingVehicle, origin, portal, exit.getDirection(),
 | 
			
		||||
                    newVelocity);
 | 
			
		||||
        }
 | 
			
		||||
        Stargate.debug("VehicleTeleporter::teleportVehicle", "Teleporting " + teleportingVehicle +
 | 
			
		||||
                " to final location " + exit + " with direction " + exit.getDirection());
 | 
			
		||||
        teleportingVehicle.teleport(exit, PlayerTeleportEvent.TeleportCause.PLUGIN);
 | 
			
		||||
        scheduler.scheduleSyncDelayedTask(Stargate.getInstance(),
 | 
			
		||||
                () -> {
 | 
			
		||||
                    Stargate.debug("VehicleTeleporter::teleportVehicle", "Setting velocity " + newVelocity +
 | 
			
		||||
                            " for vehicle " + teleportingVehicle);
 | 
			
		||||
                    teleportingVehicle.setVelocity(newVelocity);
 | 
			
		||||
                }, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new vehicle equal to the player's previous vehicle and puts any passengers inside
 | 
			
		||||
     *
 | 
			
		||||
     * <p>While it is possible to teleport boats and minecarts using the same methods as "teleportLivingVehicle", this
 | 
			
		||||
     * method works better with CraftBook with minecart options enabled. Using normal teleportation, CraftBook destroys
 | 
			
		||||
     * the minecart once the player is ejected, causing the minecart to disappear and the player to teleport without it.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param passengers  <p>A list of all passengers in the vehicle</p>
 | 
			
		||||
     * @param exit        <p>The exit location to spawn the new vehicle on</p>
 | 
			
		||||
     * @param newVelocity <p>The new velocity of the new vehicle</p>
 | 
			
		||||
     * @param origin      <p>The portal the vehicle teleported from</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void putPassengersInNewVehicle(List<Entity> passengers, Location exit,
 | 
			
		||||
                                           Vector newVelocity, Portal origin) {
 | 
			
		||||
        World vehicleWorld = exit.getWorld();
 | 
			
		||||
        if (vehicleWorld == null) {
 | 
			
		||||
            Stargate.logWarning("Unable to get the world to teleport the vehicle to");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        //Spawn a new vehicle
 | 
			
		||||
        Vehicle newVehicle = vehicleWorld.spawn(exit, teleportingVehicle.getClass());
 | 
			
		||||
        if (teleportingVehicle instanceof Boat boat) {
 | 
			
		||||
            ((Boat) newVehicle).setBoatType(boat.getBoatType());
 | 
			
		||||
        }
 | 
			
		||||
        //Remove the old vehicle
 | 
			
		||||
        if (teleportingVehicle.eject()) {
 | 
			
		||||
            TeleportHelper.handleEntityPassengers(passengers, newVehicle, origin, portal, exit.getDirection(),
 | 
			
		||||
                    newVelocity);
 | 
			
		||||
        }
 | 
			
		||||
        teleportingVehicle.remove();
 | 
			
		||||
        scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> newVehicle.setVelocity(newVelocity), 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -21,32 +21,36 @@ public class BlockChangeThread implements Runnable {
 | 
			
		||||
        long sTime = System.nanoTime();
 | 
			
		||||
        //Repeat for at most 0.025 seconds
 | 
			
		||||
        while (System.nanoTime() - sTime < 25000000) {
 | 
			
		||||
            pollQueue();
 | 
			
		||||
            if (pollQueue()) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Polls the block change request queue for any waiting requests
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>True if the queue is empty and it's safe to quit</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void pollQueue() {
 | 
			
		||||
    public static boolean pollQueue() {
 | 
			
		||||
        //Abort if there's no work to be done
 | 
			
		||||
        BlockChangeRequest blockChangeRequest = Stargate.getBlockChangeRequestQueue().poll();
 | 
			
		||||
        if (blockChangeRequest == null) {
 | 
			
		||||
            return;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Change the material of the pulled block
 | 
			
		||||
        Block block = blockChangeRequest.getBlockLocation().getBlock();
 | 
			
		||||
        block.setType(blockChangeRequest.getMaterial(), false);
 | 
			
		||||
 | 
			
		||||
        if (blockChangeRequest.getMaterial() == Material.END_GATEWAY &&
 | 
			
		||||
                block.getWorld().getEnvironment() == World.Environment.THE_END) {
 | 
			
		||||
        if (blockChangeRequest.getMaterial() == Material.END_GATEWAY) {
 | 
			
		||||
            //Force a specific location to prevent exit gateway generation
 | 
			
		||||
            fixEndGatewayGate(block);
 | 
			
		||||
        } else if (blockChangeRequest.getAxis() != null) {
 | 
			
		||||
            //If orientation is relevant, adjust the block's orientation
 | 
			
		||||
            orientBlock(block, blockChangeRequest.getAxis());
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -56,8 +60,11 @@ public class BlockChangeThread implements Runnable {
 | 
			
		||||
     */
 | 
			
		||||
    private static void fixEndGatewayGate(Block block) {
 | 
			
		||||
        EndGateway gateway = (EndGateway) block.getState();
 | 
			
		||||
        gateway.setExitLocation(block.getLocation());
 | 
			
		||||
        gateway.setExactTeleport(true);
 | 
			
		||||
        gateway.setAge(Long.MIN_VALUE);
 | 
			
		||||
        if (block.getWorld().getEnvironment() == World.Environment.THE_END) {
 | 
			
		||||
            gateway.setExitLocation(block.getLocation());
 | 
			
		||||
            gateway.setExactTeleport(true);
 | 
			
		||||
        }
 | 
			
		||||
        gateway.update(false, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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()) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,12 @@
 | 
			
		||||
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 net.md_5.bungee.api.ChatColor;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.event.player.PlayerMoveEvent;
 | 
			
		||||
 | 
			
		||||
import java.io.ByteArrayInputStream;
 | 
			
		||||
import java.io.ByteArrayOutputStream;
 | 
			
		||||
@@ -70,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
 | 
			
		||||
@@ -101,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());
 | 
			
		||||
@@ -169,4 +171,51 @@ public final class BungeeHelper {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleports a player to a bungee gate
 | 
			
		||||
     *
 | 
			
		||||
     * @param player         <p>The player to teleport</p>
 | 
			
		||||
     * @param entrancePortal <p>The gate the player is entering from</p>
 | 
			
		||||
     * @param event          <p>The event causing the teleportation</p>
 | 
			
		||||
     * @return <p>True if the teleportation was successful</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean bungeeTeleport(Player player, Portal entrancePortal, PlayerMoveEvent event) {
 | 
			
		||||
        //Check if bungee is actually enabled
 | 
			
		||||
        if (!Stargate.getGateConfig().enableBungee()) {
 | 
			
		||||
            if (!entrancePortal.getOptions().isSilent()) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("bungeeDisabled"));
 | 
			
		||||
            }
 | 
			
		||||
            entrancePortal.getPortalOpener().closePortal(false);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Teleport the player back to this gate, for sanity's sake
 | 
			
		||||
        new PlayerTeleporter(entrancePortal, player).teleportPlayer(entrancePortal, event);
 | 
			
		||||
 | 
			
		||||
        //Send the SGBungee packet first, it will be queued by BC if required
 | 
			
		||||
        if (!BungeeHelper.sendTeleportationMessage(player, entrancePortal)) {
 | 
			
		||||
            Stargate.debug("bungeeTeleport", "Unable to send teleportation message");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Send the connect-message to make the player change server
 | 
			
		||||
        if (!BungeeHelper.changeServer(player, entrancePortal)) {
 | 
			
		||||
            Stargate.debug("bungeeTeleport", "Unable to change server");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Stargate.debug("bungeeTeleport", "Teleported player to another server");
 | 
			
		||||
        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));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -113,16 +113,21 @@ public final class DirectionHelper {
 | 
			
		||||
     * @return <p>A normal vector</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Vector getCoordinateVectorFromRelativeVector(double right, double down, double out, double yaw) {
 | 
			
		||||
        Vector distanceVector = DirectionHelper.getDirectionVectorFromYaw(yaw);
 | 
			
		||||
        distanceVector.multiply(out);
 | 
			
		||||
 | 
			
		||||
        Vector rightVector = DirectionHelper.getDirectionVectorFromYaw(yaw - 90);
 | 
			
		||||
        rightVector.multiply(right);
 | 
			
		||||
 | 
			
		||||
        Vector depthVector = new Vector(0, -1, 0);
 | 
			
		||||
        depthVector.multiply(down);
 | 
			
		||||
 | 
			
		||||
        return distanceVector.add(rightVector).add(depthVector);
 | 
			
		||||
        if (yaw == 0) {
 | 
			
		||||
            //South
 | 
			
		||||
            return new Vector(right, -down, out);
 | 
			
		||||
        } else if (yaw == 90) {
 | 
			
		||||
            //West
 | 
			
		||||
            return new Vector(-out, -down, right);
 | 
			
		||||
        } else if (yaw == 180) {
 | 
			
		||||
            //North
 | 
			
		||||
            return new Vector(-right, -down, -out);
 | 
			
		||||
        } else if (yaw == 270) {
 | 
			
		||||
            //East
 | 
			
		||||
            return new Vector(out, -down, -right);
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new IllegalArgumentException(String.format("Invalid yaw %f given", yaw));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,12 @@
 | 
			
		||||
package net.knarcraft.stargate.utility;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.knarlib.formatting.StringFormatter;
 | 
			
		||||
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 +38,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
 | 
			
		||||
@@ -75,7 +79,7 @@ public final class EconomyHelper {
 | 
			
		||||
     */
 | 
			
		||||
    public static void sendObtainMessage(String portalName, Player portalOwner, int earnings) {
 | 
			
		||||
        String obtainedMsg = Stargate.getString("ecoObtain");
 | 
			
		||||
        obtainedMsg = replaceVars(obtainedMsg, portalName, earnings);
 | 
			
		||||
        obtainedMsg = replacePlaceholders(obtainedMsg, portalName, earnings);
 | 
			
		||||
        Stargate.getMessageSender().sendSuccessMessage(portalOwner, obtainedMsg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -88,7 +92,7 @@ public final class EconomyHelper {
 | 
			
		||||
     */
 | 
			
		||||
    public static void sendDeductMessage(String portalName, Player player, int cost) {
 | 
			
		||||
        String deductMsg = Stargate.getString("ecoDeduct");
 | 
			
		||||
        deductMsg = replaceVars(deductMsg, portalName, cost);
 | 
			
		||||
        deductMsg = replacePlaceholders(deductMsg, portalName, cost);
 | 
			
		||||
        Stargate.getMessageSender().sendSuccessMessage(player, deductMsg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -101,7 +105,7 @@ public final class EconomyHelper {
 | 
			
		||||
     */
 | 
			
		||||
    public static void sendInsufficientFundsMessage(String portalName, Player player, int cost) {
 | 
			
		||||
        String inFundMsg = Stargate.getString("ecoInFunds");
 | 
			
		||||
        inFundMsg = replaceVars(inFundMsg, portalName, cost);
 | 
			
		||||
        inFundMsg = replacePlaceholders(inFundMsg, portalName, cost);
 | 
			
		||||
        Stargate.getMessageSender().sendErrorMessage(player, inFundMsg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -114,10 +118,120 @@ public final class EconomyHelper {
 | 
			
		||||
     */
 | 
			
		||||
    public static void sendRefundMessage(String portalName, Player player, int cost) {
 | 
			
		||||
        String refundMsg = Stargate.getString("ecoRefund");
 | 
			
		||||
        refundMsg = replaceVars(refundMsg, portalName, -cost);
 | 
			
		||||
        refundMsg = replacePlaceholders(refundMsg, portalName, -cost);
 | 
			
		||||
        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
 | 
			
		||||
     *
 | 
			
		||||
@@ -126,8 +240,8 @@ public final class EconomyHelper {
 | 
			
		||||
     * @param cost       <p>The cost for a given interaction</p>
 | 
			
		||||
     * @return <p>The same string with cost and portal variables replaced</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static String replaceVars(String message, String portalName, int cost) {
 | 
			
		||||
        return Stargate.replaceVars(message, new String[]{"%cost%", "%portal%"},
 | 
			
		||||
    private static String replacePlaceholders(String message, String portalName, int cost) {
 | 
			
		||||
        return StringFormatter.replacePlaceholders(message, new String[]{"%cost%", "%portal%"},
 | 
			
		||||
                new String[]{Stargate.getEconomyConfig().format(cost), portalName});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,127 +0,0 @@
 | 
			
		||||
package net.knarcraft.stargate.utility;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.ChatColor;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
import java.io.BufferedWriter;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
import java.io.FileNotFoundException;
 | 
			
		||||
import java.io.FileOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.InputStreamReader;
 | 
			
		||||
import java.io.OutputStreamWriter;
 | 
			
		||||
import java.nio.charset.StandardCharsets;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Helper class for reading files
 | 
			
		||||
 */
 | 
			
		||||
public final class FileHelper {
 | 
			
		||||
 | 
			
		||||
    private FileHelper() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets an input stream from a string pointing to an internal file
 | 
			
		||||
     *
 | 
			
		||||
     * <p>This is used for getting an input stream for reading a file contained within the compiled .jar file. The file
 | 
			
		||||
     * should be in the resources directory, and the file path should start with a forward slash ("/") character.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param file <p>The file to read</p>
 | 
			
		||||
     * @return <p>An input stream for the file</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static InputStream getInputStreamForInternalFile(String file) {
 | 
			
		||||
        return FileHelper.class.getResourceAsStream(file);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a buffered reader from a string pointing to a file
 | 
			
		||||
     *
 | 
			
		||||
     * @param file <p>The file to read</p>
 | 
			
		||||
     * @return <p>A buffered reader reading the file</p>
 | 
			
		||||
     * @throws FileNotFoundException <p>If the given file does not exist</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static BufferedReader getBufferedReaderFromString(String file) throws FileNotFoundException {
 | 
			
		||||
        FileInputStream fileInputStream = new FileInputStream(file);
 | 
			
		||||
        return getBufferedReaderFromInputStream(fileInputStream);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a buffered reader given an input stream
 | 
			
		||||
     *
 | 
			
		||||
     * @param inputStream <p>The input stream to read</p>
 | 
			
		||||
     * @return <p>A buffered reader reading the input stream</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static BufferedReader getBufferedReaderFromInputStream(InputStream inputStream) {
 | 
			
		||||
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
 | 
			
		||||
        return new BufferedReader(inputStreamReader);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a buffered writer from a string pointing to a file
 | 
			
		||||
     *
 | 
			
		||||
     * @param file <p>The file to write to</p>
 | 
			
		||||
     * @return <p>A buffered writer writing to the file</p>
 | 
			
		||||
     * @throws FileNotFoundException <p>If the file does not exist</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static BufferedWriter getBufferedWriterFromString(String file) throws FileNotFoundException {
 | 
			
		||||
        FileOutputStream fileOutputStream = new FileOutputStream(file);
 | 
			
		||||
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8);
 | 
			
		||||
        return new BufferedWriter(outputStreamWriter);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads key/value pairs from an input stream
 | 
			
		||||
     *
 | 
			
		||||
     * @param bufferedReader <p>The buffered reader to read</p>
 | 
			
		||||
     * @return <p>A map containing the read pairs</p>
 | 
			
		||||
     * @throws IOException <p>If unable to read from the stream</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Map<String, String> readKeyValuePairs(BufferedReader bufferedReader) throws IOException {
 | 
			
		||||
        Map<String, String> readPairs = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
        String line = bufferedReader.readLine();
 | 
			
		||||
        boolean firstLine = true;
 | 
			
		||||
        while (line != null) {
 | 
			
		||||
            //Strip UTF BOM from the first line
 | 
			
		||||
            if (firstLine) {
 | 
			
		||||
                line = removeUTF8BOM(line);
 | 
			
		||||
                firstLine = false;
 | 
			
		||||
            }
 | 
			
		||||
            //Split at first "="
 | 
			
		||||
            int equalSignIndex = line.indexOf('=');
 | 
			
		||||
            if (equalSignIndex == -1) {
 | 
			
		||||
                line = bufferedReader.readLine();
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Read the line
 | 
			
		||||
            String key = line.substring(0, equalSignIndex);
 | 
			
		||||
            String value = ChatColor.translateAlternateColorCodes('&', line.substring(equalSignIndex + 1));
 | 
			
		||||
            readPairs.put(key, value);
 | 
			
		||||
 | 
			
		||||
            line = bufferedReader.readLine();
 | 
			
		||||
        }
 | 
			
		||||
        bufferedReader.close();
 | 
			
		||||
 | 
			
		||||
        return readPairs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes the UTF-8 Byte Order Mark if present
 | 
			
		||||
     *
 | 
			
		||||
     * @param string <p>The string to remove the BOM from</p>
 | 
			
		||||
     * @return <p>A string guaranteed without a BOM</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static String removeUTF8BOM(String string) {
 | 
			
		||||
        String UTF8_BOM = "\uFEFF";
 | 
			
		||||
        if (string.startsWith(UTF8_BOM)) {
 | 
			
		||||
            string = string.substring(1);
 | 
			
		||||
        }
 | 
			
		||||
        return string;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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,8 +384,10 @@ public final class PermissionHelper {
 | 
			
		||||
 | 
			
		||||
        //Not open for this player
 | 
			
		||||
        if (!entrancePortal.getPortalOpener().isOpenFor(player)) {
 | 
			
		||||
            Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
 | 
			
		||||
            new PlayerTeleporter(entrancePortal, player).teleport(entrancePortal, event);
 | 
			
		||||
            if (!entrancePortal.getOptions().isSilent()) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
 | 
			
		||||
            }
 | 
			
		||||
            new PlayerTeleporter(entrancePortal, player).teleportPlayer(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"));
 | 
			
		||||
            new PlayerTeleporter(entrancePortal, player).teleport(entrancePortal, event);
 | 
			
		||||
            if (!entrancePortal.getOptions().isSilent()) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
 | 
			
		||||
            }
 | 
			
		||||
            new PlayerTeleporter(entrancePortal, player).teleportPlayer(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);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -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());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										247
									
								
								src/main/java/net/knarcraft/stargate/utility/TeleportHelper.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										247
									
								
								src/main/java/net/knarcraft/stargate/utility/TeleportHelper.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,247 @@
 | 
			
		||||
package net.knarcraft.stargate.utility;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import net.knarcraft.stargate.portal.teleporter.EntityTeleporter;
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.Location;
 | 
			
		||||
import org.bukkit.entity.Creature;
 | 
			
		||||
import org.bukkit.entity.Entity;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.scheduler.BukkitScheduler;
 | 
			
		||||
import org.bukkit.util.Vector;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A helper class with methods for various teleportation tasks
 | 
			
		||||
 *
 | 
			
		||||
 * <p>The teleport helper mainly helps with passengers and leashed creatures</p>
 | 
			
		||||
 */
 | 
			
		||||
public final class TeleportHelper {
 | 
			
		||||
 | 
			
		||||
    private TeleportHelper() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a player has leashed creatures that block the teleportation
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player trying to teleport</p>
 | 
			
		||||
     * @return <p>False if the player has leashed any creatures that cannot go through the portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean noLeashedCreaturesPreventTeleportation(Player player) {
 | 
			
		||||
        //Find any nearby leashed entities to teleport with the player
 | 
			
		||||
        List<Creature> nearbyCreatures = getLeashedCreatures(player);
 | 
			
		||||
 | 
			
		||||
        //Disallow creatures with passengers to prevent smuggling
 | 
			
		||||
        for (Creature creature : nearbyCreatures) {
 | 
			
		||||
            if (!creature.getPassengers().isEmpty()) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        //TODO: Improve this to account for any players sitting on any of the lead creatures
 | 
			
		||||
 | 
			
		||||
        //If it's enabled, there is no problem
 | 
			
		||||
        if (Stargate.getGateConfig().handleLeashedCreatures()) {
 | 
			
		||||
            return true;
 | 
			
		||||
        } else {
 | 
			
		||||
            return nearbyCreatures.isEmpty();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets all creatures leashed by a player within the given range
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player to check</p>
 | 
			
		||||
     * @return <p>A list of all creatures the player is holding in a leash (lead)</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static List<Creature> getLeashedCreatures(Player player) {
 | 
			
		||||
        List<Creature> leashedCreatures = new ArrayList<>();
 | 
			
		||||
        //Find any nearby leashed entities to teleport with the player
 | 
			
		||||
        List<Entity> nearbyEntities = player.getNearbyEntities(15, 15, 15);
 | 
			
		||||
        //Teleport all creatures leashed by the player to the portal the player is to exit from
 | 
			
		||||
        for (Entity entity : nearbyEntities) {
 | 
			
		||||
            if (entity instanceof Creature creature && creature.isLeashed() && creature.getLeashHolder() == player) {
 | 
			
		||||
                leashedCreatures.add(creature);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return leashedCreatures;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleports and adds a passenger to an entity
 | 
			
		||||
     *
 | 
			
		||||
     * <p>Teleportation of living vehicles is really buggy if you wait between the teleportation and passenger adding,
 | 
			
		||||
     * but there needs to be a delay between teleporting the vehicle and teleporting and adding the passenger.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param targetVehicle <p>The entity to add the passenger to</p>
 | 
			
		||||
     * @param passenger     <p>The passenger to teleport and add</p>
 | 
			
		||||
     * @param exitDirection <p>The direction of any passengers exiting the stargate</p>
 | 
			
		||||
     * @param newVelocity   <p>The new velocity of the teleported passenger</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void teleportAndAddPassenger(Entity targetVehicle, Entity passenger, Vector exitDirection,
 | 
			
		||||
                                               Vector newVelocity) {
 | 
			
		||||
        Location passengerExit = targetVehicle.getLocation().clone().setDirection(exitDirection);
 | 
			
		||||
        if (!passenger.teleport(passengerExit)) {
 | 
			
		||||
            Stargate.debug("TeleportHelper::handleVehiclePassengers", "Failed to teleport passenger" +
 | 
			
		||||
                    passenger);
 | 
			
		||||
        } else {
 | 
			
		||||
            Stargate.debug("TeleportHelper::handleVehiclePassengers", "Teleported " + passenger +
 | 
			
		||||
                    " to " + passengerExit);
 | 
			
		||||
        }
 | 
			
		||||
        if (!targetVehicle.addPassenger(passenger)) {
 | 
			
		||||
            Stargate.debug("TeleportHelper::handleVehiclePassengers", "Failed to add passenger" +
 | 
			
		||||
                    passenger);
 | 
			
		||||
        } else {
 | 
			
		||||
            Stargate.debug("TeleportHelper::handleVehiclePassengers", "Added passenger " + passenger +
 | 
			
		||||
                    " to " + targetVehicle);
 | 
			
		||||
        }
 | 
			
		||||
        Stargate.debug("VehicleTeleporter::teleportVehicle", "Setting velocity " + newVelocity +
 | 
			
		||||
                " for passenger " + passenger);
 | 
			
		||||
        passenger.setVelocity(newVelocity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Ejects, teleports and adds all passengers to the target entity
 | 
			
		||||
     *
 | 
			
		||||
     * @param passengers   <p>The passengers to handle</p>
 | 
			
		||||
     * @param entity       <p>The entity the passengers should be put into</p
 | 
			
		||||
     * @param origin       <p>The portal the entity teleported from</p>
 | 
			
		||||
     * @param target       <p>The portal the entity is teleporting to</p>
 | 
			
		||||
     * @param exitRotation <p>The rotation of any passengers exiting the stargate</p>
 | 
			
		||||
     * @param newVelocity  <p>The new velocity of the teleported passengers</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void handleEntityPassengers(List<Entity> passengers, Entity entity, Portal origin, Portal target,
 | 
			
		||||
                                              Vector exitRotation, Vector newVelocity) {
 | 
			
		||||
        for (Entity passenger : passengers) {
 | 
			
		||||
            List<Entity> passengerPassengers = passenger.getPassengers();
 | 
			
		||||
            if (!passengerPassengers.isEmpty()) {
 | 
			
		||||
                Stargate.debug("Teleporter::handleEntityPassengers", "Found the entities: " +
 | 
			
		||||
                        passengerPassengers + " as passengers of " + entity);
 | 
			
		||||
            }
 | 
			
		||||
            if (passenger.eject()) {
 | 
			
		||||
                //Teleport any passengers of the passenger
 | 
			
		||||
                handleEntityPassengers(passengerPassengers, passenger, origin, target, exitRotation, newVelocity);
 | 
			
		||||
            }
 | 
			
		||||
            Bukkit.getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(), () -> {
 | 
			
		||||
                if (passenger instanceof Player player) {
 | 
			
		||||
                    //Teleport any creatures leashed by the player in a 15-block range
 | 
			
		||||
                    teleportLeashedCreatures(player, origin, target);
 | 
			
		||||
                }
 | 
			
		||||
                teleportAndAddPassenger(entity, passenger, exitRotation, newVelocity);
 | 
			
		||||
            }, passenger instanceof Player ? Stargate.getGateConfig().waitForPlayerAfterTeleportDelay() : 0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleports any creatures leashed by the player
 | 
			
		||||
     *
 | 
			
		||||
     * <p>Will return false if the teleportation should be aborted because the player has leashed creatures that
 | 
			
		||||
     * aren't allowed to be teleported with the player.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player which is teleported</p>
 | 
			
		||||
     * @param origin <p>The portal the player is teleporting from</p>
 | 
			
		||||
     * @param target <p>The portal the player is teleporting to</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void teleportLeashedCreatures(Player player, Portal origin, Portal target) {
 | 
			
		||||
        //If this feature is disabled, just return
 | 
			
		||||
        if (!Stargate.getGateConfig().handleLeashedCreatures()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        BukkitScheduler scheduler = Bukkit.getScheduler();
 | 
			
		||||
 | 
			
		||||
        //Find any nearby leashed entities to teleport with the player
 | 
			
		||||
        List<Creature> nearbyEntities = TeleportHelper.getLeashedCreatures(player);
 | 
			
		||||
 | 
			
		||||
        //Teleport all creatures leashed by the player to the portal the player is to exit from
 | 
			
		||||
        for (Creature creature : nearbyEntities) {
 | 
			
		||||
            creature.setLeashHolder(null);
 | 
			
		||||
            scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> {
 | 
			
		||||
                new EntityTeleporter(target, creature).teleportEntity(origin);
 | 
			
		||||
                scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> creature.setLeashHolder(player),
 | 
			
		||||
                        Stargate.getGateConfig().waitForPlayerAfterTeleportDelay());
 | 
			
		||||
            }, 2);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a list of entities or any of their passengers contains any non-players
 | 
			
		||||
     *
 | 
			
		||||
     * @param entities <p>The list of entities to check</p>
 | 
			
		||||
     * @return <p>True if at least one entity is not a player</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean containsNonPlayer(List<Entity> entities) {
 | 
			
		||||
        for (Entity entity : entities) {
 | 
			
		||||
            if (!(entity instanceof Player) || containsNonPlayer(entity.getPassengers())) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a list of entities of their passengers contains at least one player
 | 
			
		||||
     *
 | 
			
		||||
     * @param entities <p>The list of entities to check</p>
 | 
			
		||||
     * @return <p>True if at least one player is present among the passengers</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean containsPlayer(List<Entity> entities) {
 | 
			
		||||
        for (Entity entity : entities) {
 | 
			
		||||
            if (entity instanceof Player || containsPlayer(entity.getPassengers())) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets all players recursively from a list of entities
 | 
			
		||||
     *
 | 
			
		||||
     * @param entities <p>The entities to check for players</p>
 | 
			
		||||
     * @return <p>The found players</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static List<Player> getPlayers(List<Entity> entities) {
 | 
			
		||||
        List<Player> players = new ArrayList<>(5);
 | 
			
		||||
        for (Entity entity : entities) {
 | 
			
		||||
            if (entity instanceof Player) {
 | 
			
		||||
                players.add((Player) entity);
 | 
			
		||||
            }
 | 
			
		||||
            players.addAll(getPlayers(entity.getPassengers()));
 | 
			
		||||
        }
 | 
			
		||||
        return players;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the given player is allowed to and can afford to teleport
 | 
			
		||||
     *
 | 
			
		||||
     * @param player            <p>The player trying to teleport</p>
 | 
			
		||||
     * @param entrancePortal    <p>The portal the player is entering</p>
 | 
			
		||||
     * @param destinationPortal <p>The portal the player is to exit from</p>
 | 
			
		||||
     * @return <p>True if the player is allowed to teleport and is able to pay necessary fees</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean playerCanTeleport(Player player, Portal entrancePortal, Portal destinationPortal) {
 | 
			
		||||
        //Make sure the user can access the portal
 | 
			
		||||
        if (PermissionHelper.cannotAccessPortal(player, entrancePortal, destinationPortal)) {
 | 
			
		||||
            if (!entrancePortal.getOptions().isSilent()) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
 | 
			
		||||
            }
 | 
			
		||||
            entrancePortal.getPortalOpener().closePortal(false);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Check if the player is able to afford the teleport fee
 | 
			
		||||
        int cost = EconomyHelper.getUseCost(player, entrancePortal, destinationPortal);
 | 
			
		||||
        boolean canAffordFee = cost <= 0 || Stargate.getEconomyConfig().canAffordFee(player, cost);
 | 
			
		||||
        if (!canAffordFee) {
 | 
			
		||||
            if (!entrancePortal.getOptions().isSilent()) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("ecoInFunds"));
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return TeleportHelper.noLeashedCreaturesPreventTeleportation(player);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,115 @@
 | 
			
		||||
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.PortalRegistry;
 | 
			
		||||
import net.knarcraft.stargate.portal.property.PortalOwner;
 | 
			
		||||
import org.bukkit.OfflinePlayer;
 | 
			
		||||
import org.bukkit.World;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Helps migrate player names to UUID where necessary
 | 
			
		||||
 */
 | 
			
		||||
public final class UUIDMigrationHelper {
 | 
			
		||||
 | 
			
		||||
    private UUIDMigrationHelper() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static Map<String, List<Portal>> playerNamesToMigrate;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Migrates the player's name to a UUID
 | 
			
		||||
     *
 | 
			
		||||
     * <p>If any portals are missing a UUID for their owner, and the given player is the owner of those portals, the
 | 
			
		||||
     * given player's UUID will be used as UUID for the portals' owner.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player to migrate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void migrateUUID(OfflinePlayer player) {
 | 
			
		||||
        Map<String, List<Portal>> playersToMigrate = getPlayersToMigrate();
 | 
			
		||||
        String playerName = player.getName();
 | 
			
		||||
 | 
			
		||||
        //Nothing to do
 | 
			
		||||
        if (!playersToMigrate.containsKey(playerName)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Stargate.debug("UUIDMigrationHelper::migrateUUID", String.format("Migrating name to UUID for player %s",
 | 
			
		||||
                playerName));
 | 
			
		||||
        List<Portal> portalsOwned = playersToMigrate.get(playerName);
 | 
			
		||||
        if (portalsOwned == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        migratePortalsToUUID(portalsOwned, player.getUniqueId());
 | 
			
		||||
 | 
			
		||||
        //Remove the player to prevent the migration to happen every time the player joins
 | 
			
		||||
        playersToMigrate.remove(playerName);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Migrates a list of portals to use UUID instead of only player name
 | 
			
		||||
     *
 | 
			
		||||
     * @param portals  <p>The portals to migrate</p>
 | 
			
		||||
     * @param uniqueId <p>The unique ID of the portals' owner</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void migratePortalsToUUID(List<Portal> portals, UUID uniqueId) {
 | 
			
		||||
        Set<World> worldsToSave = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
        //Get the real portal from the copy and set UUID
 | 
			
		||||
        for (Portal portalCopy : portals) {
 | 
			
		||||
            Portal portal = PortalHandler.getByName(portalCopy.getCleanName(), portalCopy.getCleanNetwork());
 | 
			
		||||
            if (portal != null) {
 | 
			
		||||
                portal.getOwner().setUUID(uniqueId);
 | 
			
		||||
                worldsToSave.add(portal.getWorld());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Need to make sure the changes are saved
 | 
			
		||||
        for (World world : worldsToSave) {
 | 
			
		||||
            PortalFileHelper.saveAllPortals(world);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets all player names which need to be migrated to UUIDs
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The player names to migrate</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static Map<String, List<Portal>> getPlayersToMigrate() {
 | 
			
		||||
        //Make sure to only go through portals once
 | 
			
		||||
        if (playerNamesToMigrate != null) {
 | 
			
		||||
            return playerNamesToMigrate;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        playerNamesToMigrate = new HashMap<>();
 | 
			
		||||
        for (Portal portal : PortalRegistry.getAllPortals()) {
 | 
			
		||||
            PortalOwner owner = portal.getOwner();
 | 
			
		||||
            String ownerName = owner.getName();
 | 
			
		||||
 | 
			
		||||
            //If a UUID is missing, add the portal to the list owned by the player
 | 
			
		||||
            if (owner.getUUID() == null) {
 | 
			
		||||
                List<Portal> portalList = playerNamesToMigrate.get(ownerName);
 | 
			
		||||
                if (portalList == null) {
 | 
			
		||||
                    List<Portal> newList = new ArrayList<>();
 | 
			
		||||
                    newList.add(portal);
 | 
			
		||||
                    playerNamesToMigrate.put(ownerName, newList);
 | 
			
		||||
                } else {
 | 
			
		||||
                    portalList.add(portal);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return playerNamesToMigrate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,8 @@
 | 
			
		||||
lang=language
 | 
			
		||||
defaultNetwork=defaultGateNetwork
 | 
			
		||||
use-mysql=
 | 
			
		||||
ignoreEntrance=
 | 
			
		||||
portal-save-location=folders.portalFolder
 | 
			
		||||
portal-folder=folders.portalFolder
 | 
			
		||||
gate-folder=folders.gateFolder
 | 
			
		||||
default-gate-network=gates.defaultGateNetwork
 | 
			
		||||
@@ -18,10 +22,28 @@ debug=debugging.debug
 | 
			
		||||
permdebug=debugging.permissionDebug
 | 
			
		||||
useiconomy=economy.useEconomy
 | 
			
		||||
useeconomy=economy.useEconomy
 | 
			
		||||
cost-to-use=economy.useCost
 | 
			
		||||
cost-to-create=economy.createCost
 | 
			
		||||
createcost=economy.createCost
 | 
			
		||||
destroycost=economy.destroyCost
 | 
			
		||||
usecost=economy.useCost
 | 
			
		||||
toowner=economy.toOwner
 | 
			
		||||
cost-destination=economy.chargeFreeDestination
 | 
			
		||||
chargefreedestination=economy.chargeFreeDestination
 | 
			
		||||
freegatesgreen=economy.freeGatesGreen
 | 
			
		||||
CheckUpdates=
 | 
			
		||||
CheckUpdates=
 | 
			
		||||
economy.freeGatesGreen=economy.freeGatesColored
 | 
			
		||||
teleportMessage=
 | 
			
		||||
registerMessage=
 | 
			
		||||
destroyzMessage=
 | 
			
		||||
noownersMessage=
 | 
			
		||||
unselectMessage=
 | 
			
		||||
collisinMessage=
 | 
			
		||||
cantAffordToUse=
 | 
			
		||||
cantAffordToNew=
 | 
			
		||||
portal-open=
 | 
			
		||||
portal-closed=
 | 
			
		||||
cost-type=
 | 
			
		||||
cost-to-activate=
 | 
			
		||||
taxaccount=taxAccount
 | 
			
		||||
usevault=
 | 
			
		||||
@@ -1,62 +1,107 @@
 | 
			
		||||
# stargate Configuration File
 | 
			
		||||
# Main stargate config
 | 
			
		||||
# I----------I----------I #
 | 
			
		||||
# portalFolder -  The folder for storing portals
 | 
			
		||||
# gateFolder - The folder for storing gate layouts
 | 
			
		||||
# defaultGateNetwork - The default gate network
 | 
			
		||||
# destroyedByExplosion - Whether to destroy gates with explosions (Creeper, TNT, etc.)
 | 
			
		||||
# maxGatesEachNetwork - The maximum number of gates allowed on a network - 0 for unlimited
 | 
			
		||||
# language - The language file to load for messages
 | 
			
		||||
# rememberDestination - Whether to remember the cursor location between uses
 | 
			
		||||
# handleVehicles - Whether to allow vehicles through gates
 | 
			
		||||
# sortNetworkDestinations - Whether to sort network lists alphabetically
 | 
			
		||||
# protectEntrance - Whether to protect gate entrance material (More resource intensive. Only enable if using destroyable open/closed material)
 | 
			
		||||
# mainSignColor - The color used for drawing signs (Default: BLACK).
 | 
			
		||||
# highlightSignColor - The color used for sign markings (Default: WHITE)
 | 
			
		||||
# verifyPortals - Whether all the non-sign blocks are checked to match the gate layout when a stargate is loaded.
 | 
			
		||||
# I------------I-------------I #
 | 
			
		||||
# stargate economy options #
 | 
			
		||||
# I------------I-------------I #
 | 
			
		||||
# useEconomy - Whether to use an economy plugin
 | 
			
		||||
# createCost - The cost to create a gate
 | 
			
		||||
# destroyCost - The cost to destroy a gate
 | 
			
		||||
# useCost - The cost to use a gate
 | 
			
		||||
# toOwner - Whether the charge for using a gate goes to the gate's owner
 | 
			
		||||
# chargeFreeDestination - Whether a gate whose destination is a free gate is still charged
 | 
			
		||||
# freeGatesGreen - Whether a free gate in the destination list is drawn green
 | 
			
		||||
# I-------I-------I #
 | 
			
		||||
# Debug options #
 | 
			
		||||
# I-------I-------I #
 | 
			
		||||
# debug - Debug -- Only enable if you have issues, massive console output
 | 
			
		||||
# permissionDebug - This will output any and all Permissions checks to console, used for permissions debugging (Requires debug: true)
 | 
			
		||||
 | 
			
		||||
# language - The language file to load for messages (de,en,es,fr,hu,it,ja,nb-no,nl,nn-no,pt-br,ru,zh_cn)
 | 
			
		||||
language: en
 | 
			
		||||
# adminUpdateAlert - Whether to alert admins about new plugin updates
 | 
			
		||||
adminUpdateAlert: true
 | 
			
		||||
folders:
 | 
			
		||||
  # portalFolder -  The folder for storing portals
 | 
			
		||||
  portalFolder: plugins/Stargate/portals/
 | 
			
		||||
  # gateFolder - The folder for storing gate layouts
 | 
			
		||||
  gateFolder: plugins/Stargate/gates/
 | 
			
		||||
gates:
 | 
			
		||||
  # maxGatesEachNetwork - The maximum number of gates allowed on a network - 0 for unlimited
 | 
			
		||||
  maxGatesEachNetwork: 0
 | 
			
		||||
  # defaultGateNetwork - The default gate network
 | 
			
		||||
  defaultGateNetwork: central
 | 
			
		||||
  # exitVelocity - The velocity to give players exiting stargates, relative to the entry velocity
 | 
			
		||||
  exitVelocity: 0.1
 | 
			
		||||
  cosmetic:
 | 
			
		||||
    # rememberDestination - Whether to remember the cursor location between uses
 | 
			
		||||
    rememberDestination: false
 | 
			
		||||
    # sortNetworkDestinations - Whether to sort network lists alphabetically
 | 
			
		||||
    sortNetworkDestinations: false
 | 
			
		||||
    # mainSignColor - The color used for drawing signs (Default: BLACK).
 | 
			
		||||
    mainSignColor: BLACK
 | 
			
		||||
    # highlightSignColor - The color used for sign markings (Default: WHITE)
 | 
			
		||||
    highlightSignColor: WHITE
 | 
			
		||||
    perSignColors:
 | 
			
		||||
      - 'ACACIA:default,default'
 | 
			
		||||
      - 'BIRCH:default,default'
 | 
			
		||||
      - 'CRIMSON:inverted,inverted'
 | 
			
		||||
      - 'DARK_OAK:inverted,inverted'
 | 
			
		||||
      - 'JUNGLE:default,default'
 | 
			
		||||
      - 'OAK:default,default'
 | 
			
		||||
      - 'SPRUCE:inverted,inverted'
 | 
			
		||||
      - 'WARPED:inverted,inverted'
 | 
			
		||||
  integrity:
 | 
			
		||||
    # destroyedByExplosion - Whether to destroy gates with explosions (Creeper, TNT, etc.)
 | 
			
		||||
    destroyedByExplosion: false
 | 
			
		||||
    # verifyPortals - Whether all the non-sign blocks are checked to match the gate layout when a stargate is loaded.
 | 
			
		||||
    verifyPortals: false
 | 
			
		||||
    # protectEntrance - Whether to protect gate entrance material (More resource intensive. Only enable if using 
 | 
			
		||||
    #  destroyable open/closed material)
 | 
			
		||||
    protectEntrance: false
 | 
			
		||||
  functionality:
 | 
			
		||||
    enableBungee: false
 | 
			
		||||
    # handleVehicles - Whether to allow vehicles through gates. This overrides other vehicle settings
 | 
			
		||||
    handleVehicles: true
 | 
			
		||||
    # handleEmptyVehicles - Whether to allow empty vehicles through gates (chest/hopper/tnt/furnace minecarts included)
 | 
			
		||||
    handleEmptyVehicles: true
 | 
			
		||||
    # handleCreatureTransportation - Whether to allow players to transport creatures by sending vehicles (minecarts, 
 | 
			
		||||
    #  boats) through gates
 | 
			
		||||
    handleCreatureTransportation: true
 | 
			
		||||
    # handleNonPlayerVehicles - Whether to allow vehicles with a passenger which is not a player through gates. 
 | 
			
		||||
    #  handleCreatureTransportation must be enabled
 | 
			
		||||
    handleNonPlayerVehicles: true
 | 
			
		||||
    # handleLeashedCreatures - Whether to allow creatures lead by a player to teleport with the player
 | 
			
		||||
    handleLeashedCreatures: true
 | 
			
		||||
    # enableCraftBookRemoveOnEjectFix - Whether to enable a fix that causes loss of NBT data, but allows vehicle 
 | 
			
		||||
    #  teleportation to work when CraftBook's remove minecart/boat on eject setting is enabled
 | 
			
		||||
    enableCraftBookRemoveOnEjectFix: false
 | 
			
		||||
 | 
			
		||||
# ######################## #
 | 
			
		||||
# stargate economy options #
 | 
			
		||||
# ######################## #
 | 
			
		||||
economy:
 | 
			
		||||
  # useEconomy - Whether to use an economy plugin
 | 
			
		||||
  useEconomy: false
 | 
			
		||||
  # createCost - The cost to create a gate
 | 
			
		||||
  createCost: 0
 | 
			
		||||
  # destroyCost - The cost to destroy a gate
 | 
			
		||||
  destroyCost: 0
 | 
			
		||||
  # useCost - The cost to use a gate
 | 
			
		||||
  useCost: 0
 | 
			
		||||
  # toOwner - Whether the charge for using a gate goes to the gate's owner
 | 
			
		||||
  toOwner: false
 | 
			
		||||
  # chargeFreeDestination - Whether a gate whose destination is a free gate is still charged
 | 
			
		||||
  chargeFreeDestination: true
 | 
			
		||||
  freeGatesGreen: false
 | 
			
		||||
  # freeGatesColored - Whether a free gate in the destination list is marked with a color
 | 
			
		||||
  freeGatesColored: false
 | 
			
		||||
  # freeGatesColor - The color to use for marking free gates
 | 
			
		||||
  freeGatesColor: DARK_GREEN
 | 
			
		||||
 | 
			
		||||
# ############# #
 | 
			
		||||
# Debug options #
 | 
			
		||||
# ############# #
 | 
			
		||||
debugging:
 | 
			
		||||
  # debug - Debug -- Only enable if you have issues, massive console output
 | 
			
		||||
  debug: false
 | 
			
		||||
  permissionDebug: false
 | 
			
		||||
  # permissionDebug - This will output any and all Permissions checks to console, used for permissions debugging 
 | 
			
		||||
  #  (Requires debug: true)
 | 
			
		||||
  permissionDebug: false
 | 
			
		||||
advanced:
 | 
			
		||||
  # waitForPlayerAfterTeleportDelay - The amount of ticks to wait before adding a player as passenger of a vehicle. 
 | 
			
		||||
  #  On slow servers, a value of 6 is required to avoid client glitches after teleporting on a vehicle.
 | 
			
		||||
  waitForPlayerAfterTeleportDelay: 6
 | 
			
		||||
 | 
			
		||||
# ############## #
 | 
			
		||||
# Dynmap options #
 | 
			
		||||
# ############## #
 | 
			
		||||
dynmap:
 | 
			
		||||
  # enableDynmap - Whether to display Stargates in Dynmap's map
 | 
			
		||||
  enableDynmap: true
 | 
			
		||||
  # dynmapIconsHiddenByDefault - Whether to hide the set of Stargate icons by default, requiring users to 
 | 
			
		||||
  #  manually enable them with a checkbox.
 | 
			
		||||
  dynmapIconsHiddenByDefault: true
 | 
			
		||||
							
								
								
									
										13
									
								
								src/main/resources/gates/squarenetherglowstonegate.gate
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/main/resources/gates/squarenetherglowstonegate.gate
									
									
									
									
									
										Normal 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
 | 
			
		||||
@@ -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%
 | 
			
		||||
							
								
								
									
										44
									
								
								src/main/resources/lang/ja.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/main/resources/lang/ja.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
author=furplag
 | 
			
		||||
prefix=[Stargate]
 | 
			
		||||
teleportMsg=テレポート
 | 
			
		||||
destroyMsg=ゲートが破壊されました
 | 
			
		||||
invalidMsg=無効な行き先
 | 
			
		||||
blockMsg=ブロックされた行き先
 | 
			
		||||
destEmpty=行き先リストが空です
 | 
			
		||||
denyMsg=アクセスが拒否されました
 | 
			
		||||
reloaded= Stargate をリロードしました
 | 
			
		||||
 | 
			
		||||
ecoDeduct=%cost% の値引き
 | 
			
		||||
ecoRefund=%cost% の返金
 | 
			
		||||
ecoObtain= Stargate %portal% から %cost% を得ました
 | 
			
		||||
ecoInFunds=資金の不足
 | 
			
		||||
ecoLoadError= Vault が読み込まれましたが、Economy プラグインをフックできませんでした
 | 
			
		||||
vaultLoadError=Economy は有効になっていますが、Vault をロードできないため Economy は無効化されました
 | 
			
		||||
vaultLoaded= Vault v%version% が見つかりました
 | 
			
		||||
 | 
			
		||||
createMsg=ゲートが作成されました
 | 
			
		||||
createNetDeny=対象のネットワークにアクセスできません
 | 
			
		||||
createGateDeny=対象のゲートレイアウトにアクセスできません
 | 
			
		||||
createPersonal=パーソナルネットワーク上にゲートを作成する
 | 
			
		||||
createNameLength=ゲート名が短すぎるか長すぎます
 | 
			
		||||
createExists=すでに存在するゲート名です
 | 
			
		||||
createFull=対象のネットワークはいっぱいです
 | 
			
		||||
createWorldDeny=あなたはその世界にアクセスできません
 | 
			
		||||
createConflict=ゲートが既存のゲートと競合しています
 | 
			
		||||
 | 
			
		||||
signRightClick=右クリック
 | 
			
		||||
signToUse=ゲートを使用する
 | 
			
		||||
signRandom=ランダム
 | 
			
		||||
signDisconnected=切断
 | 
			
		||||
signInvalidGate=無効なゲート
 | 
			
		||||
 | 
			
		||||
bungeeDisabled=BungeeCord サポートは無効になっています
 | 
			
		||||
bungeeDeny=BungeeCord ゲートを作成する権限がありません
 | 
			
		||||
bungeeEmpty=BungeeCord ゲートには、行き先とネットワークの両方が必要です
 | 
			
		||||
bungeeSign=テレポート先:
 | 
			
		||||
 | 
			
		||||
portalInfoTitle=[STARGATE INFO]
 | 
			
		||||
portalInfoName=ゲート名: %name%
 | 
			
		||||
portalInfoDestination=行き先: %destination%
 | 
			
		||||
portalInfoNetwork=ネットワーク: %network%
 | 
			
		||||
portalInfoServer=サーバー: %server%
 | 
			
		||||
@@ -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%
 | 
			
		||||
@@ -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%
 | 
			
		||||
							
								
								
									
										39
									
								
								src/main/resources/lang/zh_cn.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/main/resources/lang/zh_cn.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
author=YKDZ
 | 
			
		||||
signRightClick=右键
 | 
			
		||||
ecoLoadError=Vault 已加载, 但未检测到合适的经济插件
 | 
			
		||||
createConflict=星门与现有星门冲突
 | 
			
		||||
invalidMsg=无效的目的地
 | 
			
		||||
prefix=[星门] 
 | 
			
		||||
ecoObtain=从星门 %portal% 收取了 %cost%
 | 
			
		||||
vaultLoaded=检测到 Vault v%version%
 | 
			
		||||
reloaded=星门插件已重载
 | 
			
		||||
bungeeDeny=你没有创建跨服星门的权限.
 | 
			
		||||
signToUse=以使用星门
 | 
			
		||||
signInvalidGate=未知星门
 | 
			
		||||
bungeeEmpty=跨服星门需要提供目的地和网络.
 | 
			
		||||
createMsg=星门已创建
 | 
			
		||||
bungeeDisabled=跨服功能已被禁用.
 | 
			
		||||
blockMsg=目的地被阻挡
 | 
			
		||||
ecoInFunds=余额不足
 | 
			
		||||
createNameLength=名称过短或过长.
 | 
			
		||||
vaultLoadError=未检测到Vault. 经济模块已禁用
 | 
			
		||||
denyMsg=访问被拒
 | 
			
		||||
ecoDeduct=花费 %cost%
 | 
			
		||||
signDisconnected=已取消链接
 | 
			
		||||
createNetDeny=你没有这个星门网络的许可
 | 
			
		||||
bungeeSign=传送到
 | 
			
		||||
portalInfoName=名称: %name%
 | 
			
		||||
destroyMsg=星门已被破坏
 | 
			
		||||
portalInfoTitle=[星门信息]
 | 
			
		||||
createExists=与已有星门重名
 | 
			
		||||
teleportMsg=已传送
 | 
			
		||||
createGateDeny=你没有使用这个星门结构的权限
 | 
			
		||||
signRandom=随机
 | 
			
		||||
portalInfoServer=服务器: %server%
 | 
			
		||||
createWorldDeny=你没有链接这个世界的权限
 | 
			
		||||
portalInfoDestination=目的地: %destination%
 | 
			
		||||
portalInfoNetwork=星门网络: %network%
 | 
			
		||||
destEmpty=目的地列表为空
 | 
			
		||||
createPersonal=在私人网络中创建星门
 | 
			
		||||
ecoRefund=退款 %cost%
 | 
			
		||||
createFull=此星门网络已满
 | 
			
		||||
@@ -1,18 +1,18 @@
 | 
			
		||||
name: Stargate
 | 
			
		||||
main: net.knarcraft.stargate.Stargate
 | 
			
		||||
version: 0.9.0.2
 | 
			
		||||
version: '${project.version}'
 | 
			
		||||
description: Stargate mod for Bukkit Revived
 | 
			
		||||
author: EpicKnarvik97
 | 
			
		||||
authors: [ Drakia, PseudoKnight, EpicKnarvik97 ]
 | 
			
		||||
website: https://git.knarcraft.net/EpicKnarvik97/Stargate
 | 
			
		||||
api-version: 1.17
 | 
			
		||||
softdepend: [ Vault ]
 | 
			
		||||
api-version: 1.18
 | 
			
		||||
softdepend: [ Vault, dynmap ]
 | 
			
		||||
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,22 @@ 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.admin.dye:
 | 
			
		||||
    description: Allows this player to change the dye of any stargate's sign
 | 
			
		||||
    default: false
 | 
			
		||||
  stargate.server:
 | 
			
		||||
    description: Allows the creation of a BungeeCord stargate going to any server
 | 
			
		||||
    default: false
 | 
			
		||||
  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
 | 
			
		||||
      stargate.admin.dye: true
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -30,6 +32,7 @@ public class GateLayoutTest {
 | 
			
		||||
 | 
			
		||||
    @AfterAll
 | 
			
		||||
    public static void tearDown() {
 | 
			
		||||
        MockBukkit.getMock().getPluginManager().disablePlugins();
 | 
			
		||||
        MockBukkit.unmock();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user