Compare commits
	
		
			393 Commits
		
	
	
		
			0.8.0.3
			...
			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 | |||
| b98aec4a20 | |||
| 89956cf359 | |||
| 0655d85356 | |||
| 06cb99de44 | |||
| 99f8a92857 | |||
| 01df8db0bf | |||
| d754247455 | |||
| 1f1fef3054 | |||
| 40f0a99e5a | |||
| 8fa0cca5ce | |||
| a4075363ec | |||
| 260211b677 | |||
| 5d41b2114b | |||
| 50c446f9d9 | |||
| 56bf51f370 | |||
| 56ed0495b0 | |||
| 0237f45046 | |||
| 5d84e1d78a | |||
| f52ba79ae9 | |||
| 945798916b | |||
| f0e5cd45a4 | |||
| 487cb3ad9e | |||
| 544384f69b | |||
| 3fc0e6963a | |||
| 5c730eb613 | |||
| 1c906528f2 | |||
| eaf7596014 | |||
| 669767ef89 | |||
| 822f8fb2b5 | |||
| 3367d4bb76 | |||
| a100ad3fea | |||
| 2541391d3e | |||
| b7998023f5 | |||
| deba2e5c2c | |||
| 7cc8685e26 | |||
| 50084c40f9 | |||
| 2196d5b99e | |||
| 070e7250df | |||
| 9a0f16e558 | |||
| 485ca284b0 | |||
| 4e09b44c7c | |||
| 593d528bcd | |||
| 79a43b82e5 | |||
| cb2f7443f5 | |||
| 8eff9ae5e6 | |||
| 4b42d4914a | |||
| 2650e31d97 | |||
| d2e8c81a5a | |||
| 635d08b1b3 | |||
| 1d4b988ca4 | |||
| 82ed28bba0 | |||
| 0506cf1b61 | |||
| f4ec5e05d6 | |||
| 8c16ddbed5 | |||
| 27b1f0641e | |||
| ac045fa7db | |||
| 982d8abf65 | |||
| f96e8ed2da | |||
| d9ae5456cc | |||
| fabe0dda80 | |||
| 3de785d5ab | |||
| 59069d1423 | |||
| 5299efaa86 | |||
| e2c91c1feb | |||
| d45af537cd | |||
| 6e658003e0 | |||
| 382156a719 | |||
| 44325eeb6a | |||
| bf7a10636e | |||
| 0ab6cb52c0 | |||
| f16a7089f4 | |||
| 4bdc5b6bd9 | |||
| 5b6e3f81a6 | |||
| 0709c18e30 | |||
| e14007380f | |||
| 53cd55938b | |||
| 51afa1527f | |||
| 72c1b5a239 | |||
| b0c350a140 | |||
| 06757ef9ee | |||
| 9efc960696 | |||
| 1bf9914c39 | |||
| 05123d54bd | |||
| 2e4d545955 | |||
| f8fae1fbf1 | |||
| 964eb0f898 | |||
| 38ea543b80 | |||
| 69a62c921c | |||
| b847002617 | |||
| 6ad7fa4cb9 | |||
| 2abe10bcde | |||
| 7a9dbb8046 | |||
| 3a8943baef | |||
| be8de83bcc | |||
| ba3304a716 | |||
| 051a6b8f98 | |||
| f87ffc906c | |||
| 336c3c4bfb | |||
| 2fec641d9d | |||
| 0c29788a31 | |||
| fff4d8d78b | |||
| a68dc4b464 | |||
| 6d5c4802bc | |||
| e7fc1daafe | |||
| 60c543e52a | |||
| 76b2aab057 | |||
| 201f7eaf15 | |||
| d86aae87f3 | |||
| e4f71f1b71 | |||
| 7dcf050d96 | |||
| 8ada84ddb3 | |||
| 98cee192aa | |||
| 650a26402a | |||
| 461202503e | |||
| dd7176fa12 | |||
| b7c7252fad | |||
| 24af26324a | |||
| f2579c4b12 | |||
| 1e29db58b9 | |||
| d24f35375a | |||
| f681db629f | |||
| b57f988b62 | |||
| f12306426b | |||
| 8ff30ed03f | |||
| d5e6f1145c | |||
| 8835e69e3c | |||
| b191ac1de5 | |||
| 4851a0b5e2 | |||
| e253e95cec | |||
| c35378cfe0 | |||
| 319849fd96 | |||
| abd48b646d | |||
| f2332badb6 | |||
| 19018e46b8 | |||
| ec4ed1e086 | |||
| 5c601710e7 | |||
| a6fb7dcb62 | |||
| 6005c2c6d1 | |||
| 1c3dbbe81d | |||
| 87735e4935 | |||
| 93f8f715e5 | |||
| b4059dd169 | |||
| a86a5de8c3 | |||
| 7b83b2440c | |||
| 8ae4ac3fc7 | |||
| 3ac6270897 | |||
| daa3c6f868 | |||
| 75fbd44af7 | |||
| 0fe2a5b380 | |||
| b1aa53c1a9 | |||
| 44dfa2a10d | |||
| 504ef1b52f | |||
| da32cf11d1 | |||
| ba64572254 | |||
| 79703e49af | |||
| 496b5d9779 | |||
| 378a59586d | |||
| 2b52759e00 | |||
| 4acea17ba3 | |||
| 5f685b2460 | |||
| e42da6d6bd | |||
| 681014a431 | |||
| af693bddd2 | |||
| 151c242e69 | |||
| e5fef0b16a | |||
| e665a49f03 | |||
| 279ea9d8f0 | |||
| d26196b8aa | |||
| fb70b8bc75 | |||
| c422cb9ea9 | |||
| a475e8d8b1 | |||
| 1d642bfcf2 | |||
| 1da0f4eddc | |||
| 889a9d2cbc | |||
| 1721750aa1 | |||
| 2ae4fc9645 | |||
| c912624df1 | |||
| 5b7f5649b1 | |||
| df074b9ff5 | |||
| 42fa6ed8d7 | |||
| bd4586e386 | |||
| 1719e92494 | |||
| 56410a58f8 | |||
| ff8f762ea8 | |||
| c41429b6e0 | |||
| d472eab21b | |||
| 095e59c65e | |||
| 7b9f5a6de5 | |||
| e49b94cf9a | |||
| a8c0574f3b | |||
| f0a7ff8c47 | |||
| 32410a82ba | |||
| b6d18a4217 | |||
| 68f3bca04f | |||
| 2bd5bb36cf | |||
| 5a9d70f827 | |||
| a5cf1a7cd3 | |||
| af6a2537b8 | |||
| cdae2d8f35 | |||
| 9ace568047 | |||
| 5a8e8a219e | |||
| 3521257cb2 | |||
| b9cbe9ee4c | |||
| e702a0d734 | |||
| f97cb32466 | |||
| 4f5cb84d02 | |||
| 341a445d16 | |||
| df111c2750 | |||
| 6825266a92 | |||
| 6d6a7e52b2 | |||
| 6e1a69881c | |||
| 9233776b2c | |||
| 27aa0ed29d | |||
| 4e3867eae9 | |||
| ad2be87404 | |||
| a268370f52 | |||
| c8d82a8575 | |||
| 6ff998ac3b | 
							
								
								
									
										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/>.
 | 
			
		||||
							
								
								
									
										33
									
								
								Jenkinsfile
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								Jenkinsfile
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
pipeline {
 | 
			
		||||
    agent any
 | 
			
		||||
    tools {
 | 
			
		||||
        jdk 'JDK17'
 | 
			
		||||
    }
 | 
			
		||||
    stages {
 | 
			
		||||
        stage('Build') {
 | 
			
		||||
            steps {
 | 
			
		||||
                echo 'Building...'
 | 
			
		||||
                sh 'mvn clean & mvn validate & mvn compile'
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        stage('Test') {
 | 
			
		||||
            steps {
 | 
			
		||||
                echo 'Testing...'
 | 
			
		||||
                sh 'mvn test'
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        stage('Verify') {
 | 
			
		||||
            steps {
 | 
			
		||||
                echo 'Verifying...'
 | 
			
		||||
                sh 'mvn verify -Dmaven.test.skip=true'
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        stage('Deploy') {
 | 
			
		||||
             steps {
 | 
			
		||||
                echo 'Deploying...'
 | 
			
		||||
                sh 'mvn deploy -Dmaven.install.skip=true -Dmaven.test.skip=true'
 | 
			
		||||
                archiveArtifacts artifacts: '**/target/*.jar', fingerprint: true
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										212
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										212
									
								
								pom.xml
									
									
									
									
									
								
							@@ -1,60 +1,154 @@
 | 
			
		||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
			
		||||
	<modelVersion>4.0.0</modelVersion>
 | 
			
		||||
	<groupId>org.TheDgtl</groupId>
 | 
			
		||||
	<artifactId>Stargate</artifactId>
 | 
			
		||||
	<version>0.8.0.3</version>
 | 
			
		||||
	<properties>
 | 
			
		||||
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 | 
			
		||||
	</properties>
 | 
			
		||||
	<repositories>
 | 
			
		||||
		<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>
 | 
			
		||||
		</repository>
 | 
			
		||||
	</repositories>
 | 
			
		||||
	<dependencies>
 | 
			
		||||
		<dependency>
 | 
			
		||||
			<groupId>org.spigotmc</groupId>
 | 
			
		||||
			<artifactId>spigot-api</artifactId>
 | 
			
		||||
			<version>1.16.2-R0.1-SNAPSHOT</version>
 | 
			
		||||
		</dependency>
 | 
			
		||||
		<dependency>
 | 
			
		||||
			<groupId>net.milkbowl.vault</groupId>
 | 
			
		||||
			<artifactId>VaultAPI</artifactId>
 | 
			
		||||
			<version>1.7</version>
 | 
			
		||||
		</dependency>
 | 
			
		||||
	</dependencies>
 | 
			
		||||
	<build>
 | 
			
		||||
		<sourceDirectory>src</sourceDirectory>
 | 
			
		||||
		<resources>
 | 
			
		||||
			<resource>
 | 
			
		||||
				<targetPath>net/TheDgtl/Stargate/resources</targetPath>
 | 
			
		||||
				<directory>src/net/TheDgtl/Stargate/resources</directory>
 | 
			
		||||
				<includes>
 | 
			
		||||
					<include>*.txt</include>
 | 
			
		||||
				</includes>
 | 
			
		||||
			</resource>
 | 
			
		||||
			<resource>
 | 
			
		||||
				<directory>src</directory>
 | 
			
		||||
				<includes>
 | 
			
		||||
					<include>*.yml</include>
 | 
			
		||||
				</includes>
 | 
			
		||||
			</resource>
 | 
			
		||||
		</resources>
 | 
			
		||||
		<plugins>
 | 
			
		||||
			<plugin>
 | 
			
		||||
				<groupId>org.apache.maven.plugins</groupId>
 | 
			
		||||
				<artifactId>maven-compiler-plugin</artifactId>
 | 
			
		||||
				<version>3.6.1</version>
 | 
			
		||||
				<configuration>
 | 
			
		||||
					<source>1.8</source>
 | 
			
		||||
					<target>1.8</target>
 | 
			
		||||
				</configuration>
 | 
			
		||||
			</plugin>
 | 
			
		||||
		</plugins>
 | 
			
		||||
	</build>
 | 
			
		||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
			
		||||
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
			
		||||
    <modelVersion>4.0.0</modelVersion>
 | 
			
		||||
 | 
			
		||||
    <groupId>net.knarcraft</groupId>
 | 
			
		||||
    <artifactId>Stargate</artifactId>
 | 
			
		||||
    <version>0.9.4.3-SNAPSHOT</version>
 | 
			
		||||
 | 
			
		||||
    <licenses>
 | 
			
		||||
        <license>
 | 
			
		||||
            <name>GNU Lesser General Public License</name>
 | 
			
		||||
            <url>https://www.gnu.org/licenses/lgpl-3.0.en.html</url>
 | 
			
		||||
        </license>
 | 
			
		||||
    </licenses>
 | 
			
		||||
 | 
			
		||||
    <properties>
 | 
			
		||||
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 | 
			
		||||
        <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>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.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.9.0</version>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.github.seeseemelk</groupId>
 | 
			
		||||
            <artifactId>MockBukkit-v1.18</artifactId>
 | 
			
		||||
            <version>2.85.2</version>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.jetbrains</groupId>
 | 
			
		||||
            <artifactId>annotations</artifactId>
 | 
			
		||||
            <version>23.0.0</version>
 | 
			
		||||
            <scope>provided</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>junit</groupId>
 | 
			
		||||
            <artifactId>junit</artifactId>
 | 
			
		||||
            <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>
 | 
			
		||||
        <plugins>
 | 
			
		||||
            <plugin>
 | 
			
		||||
                <groupId>org.apache.maven.plugins</groupId>
 | 
			
		||||
                <artifactId>maven-compiler-plugin</artifactId>
 | 
			
		||||
                <version>3.8.1</version>
 | 
			
		||||
                <configuration>
 | 
			
		||||
                    <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>
 | 
			
		||||
@@ -1,54 +0,0 @@
 | 
			
		||||
# Stargate Configuration File
 | 
			
		||||
# Main Stargate config
 | 
			
		||||
#
 | 
			
		||||
# portal-folder -  The folder for storing portals
 | 
			
		||||
# gate-folder - The folder for storing gate layouts
 | 
			
		||||
# default-gate-network - The default gate network
 | 
			
		||||
# destroyexplosion - Whether or not to destroy gates with explosions (Creeper, TNT, etc)
 | 
			
		||||
# maxgates - The maximum number of gates allowed on a network - 0 for unlimited
 | 
			
		||||
# lang - The language file to load for messages
 | 
			
		||||
# destMemory - Whether to remember the cursor location between uses
 | 
			
		||||
# ignoreEntrance - Ignore the entrance blocks of a gate when checking. Used to work around snowmen
 | 
			
		||||
# handleVehicles - Whether to allow vehicles through gates
 | 
			
		||||
# sortLists - Whether to sort network lists alphabetically
 | 
			
		||||
# protectEntrance - Whether to protect gate entrance material (More resource intensive. Only enable if using destroyable open/closed material)
 | 
			
		||||
# signColor - The color used for drawing signs (Default: BLACK).
 | 
			
		||||
# verifyPortals - Whether or not all the non-sign blocks are checked to match the gate layout when a stargate is loaded.
 | 
			
		||||
############################
 | 
			
		||||
# Stargate economy options #
 | 
			
		||||
############################
 | 
			
		||||
# 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 gates 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
 | 
			
		||||
#################
 | 
			
		||||
# Debug options #
 | 
			
		||||
#################
 | 
			
		||||
# debug - Debug -- Only enable if you have issues, massive console output
 | 
			
		||||
# permdebug - This will output any and all Permissions checks to console, used for permissions debugging (Requires debug: true)
 | 
			
		||||
portal-folder: plugins/Stargate/portals/
 | 
			
		||||
gate-folder: plugins/Stargate/gates/
 | 
			
		||||
default-gate-network: central
 | 
			
		||||
destroyexplosion: false
 | 
			
		||||
maxgates: 0
 | 
			
		||||
lang: en
 | 
			
		||||
destMemory: false
 | 
			
		||||
ignoreEntrance: false
 | 
			
		||||
handleVehicles: true
 | 
			
		||||
sortLists: false
 | 
			
		||||
protectEntrance: false
 | 
			
		||||
signColor: BLACK
 | 
			
		||||
useeconomy: false
 | 
			
		||||
createcost: 0
 | 
			
		||||
destroycost: 0
 | 
			
		||||
usecost: 0
 | 
			
		||||
toowner: false
 | 
			
		||||
chargefreedestination: true
 | 
			
		||||
freegatesgreen: false
 | 
			
		||||
debug: false
 | 
			
		||||
permdebug: false
 | 
			
		||||
enableBungee: false
 | 
			
		||||
verifyPortals: false
 | 
			
		||||
							
								
								
									
										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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										437
									
								
								src/main/java/net/knarcraft/stargate/Stargate.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										437
									
								
								src/main/java/net/knarcraft/stargate/Stargate.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,437 @@
 | 
			
		||||
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;
 | 
			
		||||
import net.knarcraft.stargate.config.MessageSender;
 | 
			
		||||
import net.knarcraft.stargate.config.StargateConfig;
 | 
			
		||||
import net.knarcraft.stargate.config.StargateGateConfig;
 | 
			
		||||
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;
 | 
			
		||||
import net.knarcraft.stargate.listener.TeleportEventListener;
 | 
			
		||||
import net.knarcraft.stargate.listener.VehicleEventListener;
 | 
			
		||||
import net.knarcraft.stargate.listener.WorldEventListener;
 | 
			
		||||
import net.knarcraft.stargate.portal.PortalHandler;
 | 
			
		||||
import net.knarcraft.stargate.portal.PortalRegistry;
 | 
			
		||||
import net.knarcraft.stargate.thread.BlockChangeThread;
 | 
			
		||||
import net.knarcraft.stargate.thread.ChunkUnloadThread;
 | 
			
		||||
import net.knarcraft.stargate.thread.StarGateThread;
 | 
			
		||||
import org.bukkit.Server;
 | 
			
		||||
import org.bukkit.command.PluginCommand;
 | 
			
		||||
import org.bukkit.configuration.file.FileConfiguration;
 | 
			
		||||
import org.bukkit.plugin.PluginDescriptionFile;
 | 
			
		||||
import org.bukkit.plugin.PluginManager;
 | 
			
		||||
import org.bukkit.plugin.java.JavaPlugin;
 | 
			
		||||
import org.bukkit.plugin.java.JavaPluginLoader;
 | 
			
		||||
import org.bukkit.scheduler.BukkitScheduler;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.PriorityQueue;
 | 
			
		||||
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 {
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
     */
 | 
			
		||||
    public Stargate() {
 | 
			
		||||
        super();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Special constructor used for MockBukkit
 | 
			
		||||
     *
 | 
			
		||||
     * @param loader          <p>The plugin loader to be used.</p>
 | 
			
		||||
     * @param descriptionFile <p>The description file to be used.</p>
 | 
			
		||||
     * @param dataFolder      <p>The data folder to be used.</p>
 | 
			
		||||
     * @param file            <p>The file to be used</p>
 | 
			
		||||
     */
 | 
			
		||||
    protected Stargate(JavaPluginLoader loader, PluginDescriptionFile descriptionFile, File dataFolder, File file) {
 | 
			
		||||
        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
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>An instance of this plugin, or null if not instantiated</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Stargate getInstance() {
 | 
			
		||||
        return stargate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a block change request to the request queue
 | 
			
		||||
     *
 | 
			
		||||
     * @param request <p>The request to add</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void addBlockChangeRequest(BlockChangeRequest request) {
 | 
			
		||||
        if (request != null) {
 | 
			
		||||
            blockChangeRequestQueue.add(request);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the queue containing block change requests
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A block change request queue</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Queue<BlockChangeRequest> getBlockChangeRequestQueue() {
 | 
			
		||||
        return blockChangeRequestQueue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the sender for sending messages to players
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The sender for sending messages to players</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static MessageSender getMessageSender() {
 | 
			
		||||
        return stargateConfig.getMessageSender();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the object containing gate configuration values
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The object containing gate configuration values</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static StargateGateConfig getGateConfig() {
 | 
			
		||||
        return stargateConfig.getStargateGateConfig();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the version of this plugin
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>This plugin's version</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String getPluginVersion() {
 | 
			
		||||
        return pluginVersion;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the logger used for logging to the console
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The logger</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Logger getConsoleLogger() {
 | 
			
		||||
        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
 | 
			
		||||
     *
 | 
			
		||||
     * @param route   <p>The class name/route where something happened</p>
 | 
			
		||||
     * @param message <p>A message describing what happened</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void debug(String route, String message) {
 | 
			
		||||
        if (stargateConfig == null || stargateConfig.isDebuggingEnabled()) {
 | 
			
		||||
            logger.info("[Stargate::" + route + "] " + message);
 | 
			
		||||
        } else {
 | 
			
		||||
            logger.log(Level.FINEST, "[Stargate::" + route + "] " + message);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Logs an info message to the console
 | 
			
		||||
     *
 | 
			
		||||
     * @param message <p>The message to log</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void logInfo(String message) {
 | 
			
		||||
        logger.info(getBackupString("prefix") + message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Logs a severe error message to the console
 | 
			
		||||
     *
 | 
			
		||||
     * @param message <p>The message to log</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void logSevere(String message) {
 | 
			
		||||
        log(Level.SEVERE, message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Logs a warning message to the console
 | 
			
		||||
     *
 | 
			
		||||
     * @param message <p>The message to log</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void logWarning(String message) {
 | 
			
		||||
        log(Level.WARNING, message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Logs a message to the console
 | 
			
		||||
     *
 | 
			
		||||
     * @param severity <p>The severity of the event triggering the message</p>
 | 
			
		||||
     * @param message  <p>The message to log</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void log(Level severity, String message) {
 | 
			
		||||
        logger.log(severity, getBackupString("prefix") + message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the folder for saving created portals
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The returned String path is the full path to the folder</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The folder for storing the portal database</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String getPortalFolder() {
 | 
			
		||||
        return stargateConfig.getPortalFolder();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the folder storing gate files
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The returned String path is the full path to the folder</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The folder storing gate files</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String getGateFolder() {
 | 
			
		||||
        return stargateConfig.getGateFolder();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the default network for gates where a network is not specified
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The default network</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String getDefaultNetwork() {
 | 
			
		||||
        return stargateConfig.getStargateGateConfig().getDefaultPortalNetwork();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a translated string given its string key
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The name/key is the string before the equals sign in the language files</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param name <p>The name/key of the string to get</p>
 | 
			
		||||
     * @return <p>The full translated string</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String getString(String name) {
 | 
			
		||||
        return stargateConfig.getLanguageLoader().getString(name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a backup string given its string key
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The name/key is the string before the equals sign in the language files</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param name <p>The name/key of the string to get</p>
 | 
			
		||||
     * @return <p>The full string in the backup language (English)</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String getBackupString(String name) {
 | 
			
		||||
        return stargateConfig.getLanguageLoader().getBackupString(name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Replaces a variable in a string
 | 
			
		||||
     *
 | 
			
		||||
     * @param input  <p>The input containing the variables</p>
 | 
			
		||||
     * @param search <p>The variable to replace</p>
 | 
			
		||||
     * @param value  <p>The replacement value</p>
 | 
			
		||||
     * @return <p>The input string with the search replaced with value</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String replaceVars(String input, String search, String value) {
 | 
			
		||||
        return input.replace(search, value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets this plugin's plugin manager
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A plugin manager</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static PluginManager getPluginManager() {
 | 
			
		||||
        return pluginManager;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the object containing economy config values
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The object containing economy config values</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static EconomyConfig getEconomyConfig() {
 | 
			
		||||
        return stargateConfig.getEconomyConfig();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onDisable() {
 | 
			
		||||
        PortalHandler.closeAllPortals();
 | 
			
		||||
        PortalRegistry.clearPortals();
 | 
			
		||||
        stargateConfig.clearManagedWorlds();
 | 
			
		||||
        getServer().getScheduler().cancelTasks(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onEnable() {
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
        stargateConfig = new StargateConfig(logger);
 | 
			
		||||
        stargateConfig.finishSetup();
 | 
			
		||||
 | 
			
		||||
        pluginVersion = pluginDescriptionFile.getVersion();
 | 
			
		||||
 | 
			
		||||
        logger.info(pluginDescriptionFile.getName() + " v." + pluginDescriptionFile.getVersion() + " is enabled.");
 | 
			
		||||
 | 
			
		||||
        //Register events before loading gates to stop weird things from happening.
 | 
			
		||||
        registerEventListeners();
 | 
			
		||||
 | 
			
		||||
        //Run necessary threads
 | 
			
		||||
        runThreads();
 | 
			
		||||
 | 
			
		||||
        this.registerCommands();
 | 
			
		||||
 | 
			
		||||
        //Check for any available updates
 | 
			
		||||
        UpdateChecker.checkForUpdate(this, "https://api.spigotmc.org/legacy/update.php?resource=97784",
 | 
			
		||||
                Stargate::getPluginVersion, Stargate::setUpdateAvailable);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Starts threads using the bukkit scheduler
 | 
			
		||||
     */
 | 
			
		||||
    private void runThreads() {
 | 
			
		||||
        BukkitScheduler scheduler = getServer().getScheduler();
 | 
			
		||||
        scheduler.runTaskTimer(this, new StarGateThread(), 0L, 100L);
 | 
			
		||||
        scheduler.runTaskTimer(this, new BlockChangeThread(), 0L, 1L);
 | 
			
		||||
        scheduler.runTaskTimer(this, new ChunkUnloadThread(), 0L, 100L);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Registers all event listeners
 | 
			
		||||
     */
 | 
			
		||||
    private void registerEventListeners() {
 | 
			
		||||
        pluginManager.registerEvents(new PlayerEventListener(), this);
 | 
			
		||||
        pluginManager.registerEvents(new BlockEventListener(), this);
 | 
			
		||||
 | 
			
		||||
        pluginManager.registerEvents(new VehicleEventListener(), this);
 | 
			
		||||
        pluginManager.registerEvents(new EntityEventListener(), this);
 | 
			
		||||
        pluginManager.registerEvents(new PortalEventListener(), this);
 | 
			
		||||
        pluginManager.registerEvents(new WorldEventListener(), this);
 | 
			
		||||
        pluginManager.registerEvents(new PluginEventListener(this), this);
 | 
			
		||||
        pluginManager.registerEvents(new TeleportEventListener(), this);
 | 
			
		||||
        pluginManager.registerEvents(new EntitySpawnListener(), this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Registers a command for this plugin
 | 
			
		||||
     */
 | 
			
		||||
    private void registerCommands() {
 | 
			
		||||
        PluginCommand stargateCommand = this.getCommand("stargate");
 | 
			
		||||
        if (stargateCommand != null) {
 | 
			
		||||
            stargateCommand.setExecutor(new CommandStarGate());
 | 
			
		||||
            stargateCommand.setTabCompleter(new StarGateTabCompleter());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the chunk unload queue containing chunks to unload
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The chunk unload queue</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Queue<ChunkUnloadRequest> getChunkUnloadQueue() {
 | 
			
		||||
        return chunkUnloadQueue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a new chunk unload request to the chunk unload queue
 | 
			
		||||
     *
 | 
			
		||||
     * @param request <p>The new chunk unload request to add</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void addChunkUnloadRequest(ChunkUnloadRequest request) {
 | 
			
		||||
        chunkUnloadQueue.removeIf((item) -> item.getChunkToUnload().equals(request.getChunkToUnload()));
 | 
			
		||||
        chunkUnloadQueue.add(request);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the stargate configuration
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The stargate configuration</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static StargateConfig getStargateConfig() {
 | 
			
		||||
        return stargateConfig;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
package net.knarcraft.stargate.command;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This command represents the plugin's about command
 | 
			
		||||
 */
 | 
			
		||||
public class CommandAbout implements CommandExecutor {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
 | 
			
		||||
                             @NotNull String[] strings) {
 | 
			
		||||
 | 
			
		||||
        ChatColor textColor = ChatColor.GOLD;
 | 
			
		||||
        ChatColor highlightColor = ChatColor.GREEN;
 | 
			
		||||
        commandSender.sendMessage(textColor + "Stargate Plugin originally created by " + highlightColor +
 | 
			
		||||
                "Drakia" + textColor + ", and revived by " + highlightColor + "EpicKnarvik97");
 | 
			
		||||
        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()) {
 | 
			
		||||
            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 + ")";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
package net.knarcraft.stargate.command;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import org.bukkit.command.Command;
 | 
			
		||||
import org.bukkit.command.CommandExecutor;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This command represents the plugin's reload command
 | 
			
		||||
 */
 | 
			
		||||
public class CommandReload 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.reload")) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(commandSender, "Permission Denied");
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Stargate.getStargateConfig().reload(commandSender);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,40 @@
 | 
			
		||||
package net.knarcraft.stargate.command;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
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
 | 
			
		||||
 *
 | 
			
		||||
 * <p>This prefix command should only be used for commands which are certain to collide with others and which relate to
 | 
			
		||||
 * the plugin itself, not commands for functions of the plugin.</p>
 | 
			
		||||
 */
 | 
			
		||||
public class CommandStarGate implements CommandExecutor {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
 | 
			
		||||
                             @NotNull String[] args) {
 | 
			
		||||
        if (args.length > 0) {
 | 
			
		||||
            if (args[0].equalsIgnoreCase("about")) {
 | 
			
		||||
                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 {
 | 
			
		||||
            commandSender.sendMessage(ChatColor.GOLD + "Stargate version " +
 | 
			
		||||
                    ChatColor.GREEN + Stargate.getPluginVersion());
 | 
			
		||||
            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
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,57 @@
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This is the tab completer for the /stargate (/sg) command
 | 
			
		||||
 */
 | 
			
		||||
public class StarGateTabCompleter implements TabCompleter {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @Nullable List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command,
 | 
			
		||||
                                                @NotNull String s, @NotNull String[] args) {
 | 
			
		||||
        if (args.length == 1) {
 | 
			
		||||
            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();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										239
									
								
								src/main/java/net/knarcraft/stargate/config/EconomyConfig.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								src/main/java/net/knarcraft/stargate/config/EconomyConfig.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,239 @@
 | 
			
		||||
package net.knarcraft.stargate.config;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
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.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.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 Economy economy = null;
 | 
			
		||||
    private Plugin vault = null;
 | 
			
		||||
 | 
			
		||||
    private final Map<ConfigOption, Object> configOptions;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new economy config
 | 
			
		||||
     *
 | 
			
		||||
     * @param configOptions <p>The loaded config options to read</p>
 | 
			
		||||
     */
 | 
			
		||||
    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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the cost of using a gate without a specified cost
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The gate use cost</p>
 | 
			
		||||
     */
 | 
			
		||||
    public int getDefaultUseCost() {
 | 
			
		||||
        return (Integer) configOptions.get(ConfigOption.USE_COST);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether economy is enabled
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether economy is enabled</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isEconomyEnabled() {
 | 
			
		||||
        return (boolean) configOptions.get(ConfigOption.USE_ECONOMY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the economy object to use for transactions
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>An economy object, or null if economy is disabled or not initialized</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Economy getEconomy() {
 | 
			
		||||
        return economy;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets an instance of the Vault plugin
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>An instance of the Vault plugin, or null if Vault is not loaded</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Plugin getVault() {
 | 
			
		||||
        return vault;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Disables economy support by clearing relevant values
 | 
			
		||||
     */
 | 
			
		||||
    public void disableEconomy() {
 | 
			
		||||
        this.economy = null;
 | 
			
		||||
        this.vault = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether free portals should be marked with a different coloring
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether free portals should be colored</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean drawFreePortalsColored() {
 | 
			
		||||
        return (boolean) configOptions.get(ConfigOption.FREE_GATES_COLORED);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether a gate whose destination is a free gate is still charged
 | 
			
		||||
     *
 | 
			
		||||
     * <p>If teleporting from a free portal, it's free regardless of destination. If chargeFreeDestination is disabled,
 | 
			
		||||
     * it's also free to teleport back to the free portal. If chargeFreeDestination is enabled, it's only free to
 | 
			
		||||
     * teleport back if teleporting from another free portal.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether to charge for free destinations</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean freeIfFreeDestination() {
 | 
			
		||||
        return !((boolean) configOptions.get(ConfigOption.CHARGE_FREE_DESTINATION));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether payments should be sent to the owner of the used portal
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether to send payments to the portal owner</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean sendPaymentToOwner() {
 | 
			
		||||
        return (boolean) configOptions.get(ConfigOption.TO_OWNER);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the cost of creating a gate without a specified cost
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The gate creation cost</p>
 | 
			
		||||
     */
 | 
			
		||||
    public int getDefaultCreateCost() {
 | 
			
		||||
        return (Integer) configOptions.get(ConfigOption.CREATE_COST);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the cost of destroying a gate without a specified cost
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The gate destruction cost</p>
 | 
			
		||||
     */
 | 
			
		||||
    public int getDefaultDestroyCost() {
 | 
			
		||||
        return (Integer) configOptions.get(ConfigOption.DESTROY_COST);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the given player can afford the given fee
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player to check</p>
 | 
			
		||||
     * @param cost   <p>The fee to pay</p>
 | 
			
		||||
     * @return <p>True if the player can afford to pay the fee</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean canAffordFee(Player player, int cost) {
 | 
			
		||||
        return economy.getBalance(player) > cost;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a formatted string for an amount, adding the name of the currency
 | 
			
		||||
     *
 | 
			
		||||
     * @param amount <p>The amount to display</p>
 | 
			
		||||
     * @return <p>A formatted text string describing the amount</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String format(int amount) {
 | 
			
		||||
        if (isEconomyEnabled()) {
 | 
			
		||||
            return economy.format(amount);
 | 
			
		||||
        } else {
 | 
			
		||||
            return "";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets up economy by initializing vault and the vault economy provider
 | 
			
		||||
     *
 | 
			
		||||
     * @param pluginManager <p>The plugin manager to get plugins from</p>
 | 
			
		||||
     * @return <p>True if economy was enabled</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean setupEconomy(PluginManager pluginManager) {
 | 
			
		||||
        if (!isEconomyEnabled()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        //Check if vault is loaded
 | 
			
		||||
        Plugin vault = pluginManager.getPlugin("Vault");
 | 
			
		||||
        if (vault != null && vault.isEnabled()) {
 | 
			
		||||
            ServicesManager servicesManager = Stargate.getInstance().getServer().getServicesManager();
 | 
			
		||||
            RegisteredServiceProvider<Economy> economyProvider = servicesManager.getRegistration(Economy.class);
 | 
			
		||||
            if (economyProvider != null) {
 | 
			
		||||
                economy = economyProvider.getProvider();
 | 
			
		||||
                this.vault = vault;
 | 
			
		||||
                return true;
 | 
			
		||||
            } else {
 | 
			
		||||
                Stargate.logInfo(Stargate.getString("ecoLoadError"));
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            Stargate.logInfo(Stargate.getString("vaultLoadError"));
 | 
			
		||||
        }
 | 
			
		||||
        configOptions.put(ConfigOption.USE_ECONOMY, false);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether to use economy
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>True if the user has turned on economy and economy is available</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean useEconomy() {
 | 
			
		||||
        return isEconomyEnabled() && economy != null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the cost of creating the given gate
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player creating the gate</p>
 | 
			
		||||
     * @param gate   <p>The gate type used</p>
 | 
			
		||||
     * @return <p>The cost of creating the gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public int getCreateCost(Player player, Gate gate) {
 | 
			
		||||
        if (isFree(player, "create")) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            return gate.getCreateCost();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the cost of destroying the given gate
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player creating the gate</p>
 | 
			
		||||
     * @param gate   <p>The gate type used</p>
 | 
			
		||||
     * @return <p>The cost of destroying the gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public int getDestroyCost(Player player, Gate gate) {
 | 
			
		||||
        if (isFree(player, "destroy")) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            return gate.getDestroyCost();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Determines if a player can do a gate action for free
 | 
			
		||||
     *
 | 
			
		||||
     * @param player         <p>The player to check</p>
 | 
			
		||||
     * @param permissionNode <p>The free.permissionNode necessary to allow free gate {action}</p>
 | 
			
		||||
     * @return <p></p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isFree(Player player, String permissionNode) {
 | 
			
		||||
        return !useEconomy() || PermissionHelper.hasPermission(player, "stargate.free." + permissionNode);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										257
									
								
								src/main/java/net/knarcraft/stargate/config/LanguageLoader.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								src/main/java/net/knarcraft/stargate/config/LanguageLoader.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,257 @@
 | 
			
		||||
package net.knarcraft.stargate.config;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.knarlib.property.ColorConversion;
 | 
			
		||||
import net.knarcraft.knarlib.util.FileHelper;
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
import java.io.BufferedWriter;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class is responsible for loading all strings which are translated into several languages
 | 
			
		||||
 */
 | 
			
		||||
public final class LanguageLoader {
 | 
			
		||||
 | 
			
		||||
    private final String languageFolder;
 | 
			
		||||
    private final Map<String, String> loadedBackupStrings;
 | 
			
		||||
    private String chosenLanguage;
 | 
			
		||||
    private Map<String, String> loadedStringTranslations;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new language loader
 | 
			
		||||
     *
 | 
			
		||||
     * <p>This will only load the backup language. Set the chosen language and reload afterwards.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param languageFolder <p>The folder containing the language files</p>
 | 
			
		||||
     */
 | 
			
		||||
    public LanguageLoader(String languageFolder) {
 | 
			
		||||
        this.languageFolder = languageFolder;
 | 
			
		||||
        File testFile = new File(languageFolder, "en.txt");
 | 
			
		||||
        if (!testFile.exists()) {
 | 
			
		||||
            if (testFile.getParentFile().mkdirs()) {
 | 
			
		||||
                Stargate.debug("LanguageLoader", "Created language folder");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Load english as backup language in case the chosen language is missing newly added text strings
 | 
			
		||||
        InputStream inputStream = FileHelper.getInputStreamForInternalFile("/lang/en.txt");
 | 
			
		||||
        if (inputStream != null) {
 | 
			
		||||
            loadedBackupStrings = load("en", inputStream);
 | 
			
		||||
        } else {
 | 
			
		||||
            loadedBackupStrings = null;
 | 
			
		||||
            Stargate.getConsoleLogger().severe("[stargate] Error loading backup language. " +
 | 
			
		||||
                    "There may be missing text in-game");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reloads languages from the files on disk
 | 
			
		||||
     */
 | 
			
		||||
    public void reload() {
 | 
			
		||||
        //Extracts/Updates the language as needed
 | 
			
		||||
        updateLanguage(chosenLanguage);
 | 
			
		||||
        loadedStringTranslations = load(chosenLanguage);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the string to display given its name/key
 | 
			
		||||
     *
 | 
			
		||||
     * @param name <p>The name/key of the string to display</p>
 | 
			
		||||
     * @return <p>The string in the user's preferred language</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getString(String name) {
 | 
			
		||||
        String value = null;
 | 
			
		||||
        if (loadedStringTranslations != null) {
 | 
			
		||||
            value = loadedStringTranslations.get(name);
 | 
			
		||||
        }
 | 
			
		||||
        if (value == null) {
 | 
			
		||||
            value = getBackupString(name);
 | 
			
		||||
        }
 | 
			
		||||
        return value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the string to display given its name/key
 | 
			
		||||
     *
 | 
			
		||||
     * @param name <p>The name/key of the string to display</p>
 | 
			
		||||
     * @return <p>The string in the backup language (English)</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getBackupString(String name) {
 | 
			
		||||
        String value = null;
 | 
			
		||||
        if (loadedBackupStrings != null) {
 | 
			
		||||
            value = loadedBackupStrings.get(name);
 | 
			
		||||
        }
 | 
			
		||||
        if (value == null) {
 | 
			
		||||
            return "";
 | 
			
		||||
        }
 | 
			
		||||
        return value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the chosen plugin language
 | 
			
		||||
     *
 | 
			
		||||
     * @param chosenLanguage <p>The new plugin language</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setChosenLanguage(String chosenLanguage) {
 | 
			
		||||
        this.chosenLanguage = chosenLanguage;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates files in the plugin directory with contents from the compiled .jar
 | 
			
		||||
     *
 | 
			
		||||
     * @param language <p>The language to update</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void updateLanguage(String language) {
 | 
			
		||||
        Map<String, String> currentLanguageValues = load(language);
 | 
			
		||||
 | 
			
		||||
        InputStream inputStream = getClass().getResourceAsStream("/lang/" + language + ".txt");
 | 
			
		||||
        if (inputStream == null) {
 | 
			
		||||
            Stargate.logInfo(String.format("The language %s is not available. Falling back to english, You can add a " +
 | 
			
		||||
                    "custom language by creating a new text file in the lang directory.", language));
 | 
			
		||||
            Stargate.debug("LanguageLoader::updateLanguage", String.format("Unable to load /lang/%s.txt", language));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            readChangedLanguageStrings(inputStream, language, currentLanguageValues);
 | 
			
		||||
        } catch (IOException ex) {
 | 
			
		||||
            ex.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads language strings
 | 
			
		||||
     *
 | 
			
		||||
     * @param inputStream           <p>The input stream to read from</p>
 | 
			
		||||
     * @param language              <p>The selected language</p>
 | 
			
		||||
     * @param currentLanguageValues <p>The current values of the loaded/processed language</p>
 | 
			
		||||
     * @throws IOException <p>if unable to read a language file</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void readChangedLanguageStrings(InputStream inputStream, String language, Map<String,
 | 
			
		||||
            String> currentLanguageValues) throws IOException {
 | 
			
		||||
        //Get language values
 | 
			
		||||
        BufferedReader bufferedReader = FileHelper.getBufferedReaderFromInputStream(inputStream);
 | 
			
		||||
        Map<String, String> internalLanguageValues = FileHelper.readKeyValuePairs(bufferedReader, "=",
 | 
			
		||||
                ColorConversion.NORMAL);
 | 
			
		||||
 | 
			
		||||
        //If currentLanguageValues is null; the chosen language has not been used before
 | 
			
		||||
        if (currentLanguageValues == null) {
 | 
			
		||||
            updateLanguageFile(language, internalLanguageValues, null);
 | 
			
		||||
            Stargate.logInfo(String.format("Language (%s) has been loaded", language));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //If a key is not found in the language file, add the one in the internal file. Must update the external file
 | 
			
		||||
        if (!internalLanguageValues.keySet().equals(currentLanguageValues.keySet())) {
 | 
			
		||||
            Map<String, String> newLanguageValues = new HashMap<>();
 | 
			
		||||
            boolean updateNecessary = false;
 | 
			
		||||
            for (String key : internalLanguageValues.keySet()) {
 | 
			
		||||
                if (currentLanguageValues.get(key) == null) {
 | 
			
		||||
                    newLanguageValues.put(key, internalLanguageValues.get(key));
 | 
			
		||||
                    //Found at least one value in the internal file not in the external file. Need to update
 | 
			
		||||
                    updateNecessary = true;
 | 
			
		||||
                } else {
 | 
			
		||||
                    newLanguageValues.put(key, currentLanguageValues.get(key));
 | 
			
		||||
                    currentLanguageValues.remove(key);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            //Update the file itself
 | 
			
		||||
            if (updateNecessary) {
 | 
			
		||||
                updateLanguageFile(language, newLanguageValues, currentLanguageValues);
 | 
			
		||||
                Stargate.logInfo(String.format("Your language file (%s.txt) has been updated", language));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the language file for a given language
 | 
			
		||||
     *
 | 
			
		||||
     * @param language              <p>The language to update</p>
 | 
			
		||||
     * @param languageStrings       <p>The updated language strings</p>
 | 
			
		||||
     * @param customLanguageStrings <p>Any custom language strings not recognized</p>
 | 
			
		||||
     * @throws IOException <p>If unable to write to the language file</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void updateLanguageFile(String language, Map<String, String> languageStrings,
 | 
			
		||||
                                    Map<String, String> customLanguageStrings) throws IOException {
 | 
			
		||||
        BufferedWriter bufferedWriter = FileHelper.getBufferedWriterFromString(languageFolder + language + ".txt");
 | 
			
		||||
 | 
			
		||||
        //Output normal Language data
 | 
			
		||||
        for (String key : languageStrings.keySet()) {
 | 
			
		||||
            bufferedWriter.write(key + "=" + languageStrings.get(key));
 | 
			
		||||
            bufferedWriter.newLine();
 | 
			
		||||
        }
 | 
			
		||||
        bufferedWriter.newLine();
 | 
			
		||||
        //Output any custom language strings the user had
 | 
			
		||||
        if (customLanguageStrings != null) {
 | 
			
		||||
            for (String key : customLanguageStrings.keySet()) {
 | 
			
		||||
                bufferedWriter.write(key + "=" + customLanguageStrings.get(key));
 | 
			
		||||
                bufferedWriter.newLine();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        bufferedWriter.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads the given language
 | 
			
		||||
     *
 | 
			
		||||
     * @param lang <p>The language to load</p>
 | 
			
		||||
     * @return <p>A mapping between loaded string indexes and the strings to display</p>
 | 
			
		||||
     */
 | 
			
		||||
    private Map<String, String> load(String lang) {
 | 
			
		||||
        return load(lang, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads the given language
 | 
			
		||||
     *
 | 
			
		||||
     * @param lang        <p>The language to load</p>
 | 
			
		||||
     * @param inputStream <p>An optional input stream to use. Defaults to using a file input stream</p>
 | 
			
		||||
     * @return <p>A mapping between loaded string indexes and the strings to display</p>
 | 
			
		||||
     */
 | 
			
		||||
    private Map<String, String> load(String lang, InputStream inputStream) {
 | 
			
		||||
        Map<String, String> strings;
 | 
			
		||||
        BufferedReader bufferedReader;
 | 
			
		||||
        try {
 | 
			
		||||
            if (inputStream == null) {
 | 
			
		||||
                bufferedReader = FileHelper.getBufferedReaderFromString(languageFolder + lang + ".txt");
 | 
			
		||||
            } else {
 | 
			
		||||
                bufferedReader = FileHelper.getBufferedReaderFromInputStream(inputStream);
 | 
			
		||||
            }
 | 
			
		||||
            strings = FileHelper.readKeyValuePairs(bufferedReader, "=", ColorConversion.NORMAL);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            if (Stargate.getStargateConfig().isDebuggingEnabled()) {
 | 
			
		||||
                Stargate.getConsoleLogger().info("[Stargate] Unable to load language " + lang);
 | 
			
		||||
            }
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return strings;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Prints debug output to the console for checking loaded language strings/translations
 | 
			
		||||
     */
 | 
			
		||||
    public void debug() {
 | 
			
		||||
        if (loadedStringTranslations != null) {
 | 
			
		||||
            Set<String> keys = loadedStringTranslations.keySet();
 | 
			
		||||
            for (String key : keys) {
 | 
			
		||||
                Stargate.debug("LanguageLoader::Debug::loadedStringTranslations", key + " => " +
 | 
			
		||||
                        loadedStringTranslations.get(key));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (loadedBackupStrings == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        Set<String> keys = loadedBackupStrings.keySet();
 | 
			
		||||
        for (String key : keys) {
 | 
			
		||||
            Stargate.debug("LanguageLoader::Debug::loadedBackupStrings", key + " => " +
 | 
			
		||||
                    loadedBackupStrings.get(key));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,61 @@
 | 
			
		||||
package net.knarcraft.stargate.config;
 | 
			
		||||
 | 
			
		||||
import net.md_5.bungee.api.ChatColor;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The message sender is responsible sending messages to players with correct coloring and formatting
 | 
			
		||||
 */
 | 
			
		||||
public final class MessageSender {
 | 
			
		||||
 | 
			
		||||
    private final LanguageLoader languageLoader;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new message sender
 | 
			
		||||
     *
 | 
			
		||||
     * @param languageLoader <p>The language loader to get translated strings from</p>
 | 
			
		||||
     */
 | 
			
		||||
    public MessageSender(LanguageLoader languageLoader) {
 | 
			
		||||
        this.languageLoader = languageLoader;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends an error message to a player
 | 
			
		||||
     *
 | 
			
		||||
     * @param player  <p>The player to send the message to</p>
 | 
			
		||||
     * @param message <p>The message to send</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void sendErrorMessage(CommandSender player, String message) {
 | 
			
		||||
        sendMessage(player, message, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a success message to a player
 | 
			
		||||
     *
 | 
			
		||||
     * @param player  <p>The player to send the message to</p>
 | 
			
		||||
     * @param message <p>The message to send</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void sendSuccessMessage(CommandSender player, String message) {
 | 
			
		||||
        sendMessage(player, message, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a message to a player
 | 
			
		||||
     *
 | 
			
		||||
     * @param sender  <p>The player to send the message to</p>
 | 
			
		||||
     * @param message <p>The message to send</p>
 | 
			
		||||
     * @param error   <p>Whether the message sent is an error</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void sendMessage(CommandSender sender, String message, boolean error) {
 | 
			
		||||
        if (message.isEmpty()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        message = ChatColor.translateAlternateColorCodes('&', message);
 | 
			
		||||
        if (error) {
 | 
			
		||||
            sender.sendMessage(ChatColor.RED + languageLoader.getString("prefix") + ChatColor.WHITE + message);
 | 
			
		||||
        } else {
 | 
			
		||||
            sender.sendMessage(ChatColor.GREEN + languageLoader.getString("prefix") + ChatColor.WHITE + message);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										553
									
								
								src/main/java/net/knarcraft/stargate/config/StargateConfig.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										553
									
								
								src/main/java/net/knarcraft/stargate/config/StargateConfig.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,553 @@
 | 
			
		||||
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.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.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;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.concurrent.ConcurrentLinkedQueue;
 | 
			
		||||
import java.util.logging.Logger;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The stargate config is responsible for keeping track of all configuration values
 | 
			
		||||
 */
 | 
			
		||||
public final class StargateConfig {
 | 
			
		||||
 | 
			
		||||
    private final Queue<Portal> activePortalsQueue = new ConcurrentLinkedQueue<>();
 | 
			
		||||
    private final Queue<Portal> openPortalsQueue = new ConcurrentLinkedQueue<>();
 | 
			
		||||
    private final HashSet<String> managedWorlds = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
    private StargateGateConfig stargateGateConfig;
 | 
			
		||||
    private MessageSender messageSender;
 | 
			
		||||
    private final LanguageLoader languageLoader;
 | 
			
		||||
    private EconomyConfig economyConfig;
 | 
			
		||||
    private final Logger logger;
 | 
			
		||||
 | 
			
		||||
    private final String dataFolderPath;
 | 
			
		||||
    private String gateFolder;
 | 
			
		||||
    private String portalFolder;
 | 
			
		||||
    private String languageName = "en";
 | 
			
		||||
 | 
			
		||||
    private final Map<ConfigOption, Object> configOptions;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new stargate config
 | 
			
		||||
     *
 | 
			
		||||
     * @param logger <p>The logger to use for logging errors</p>
 | 
			
		||||
     */
 | 
			
		||||
    public StargateConfig(Logger logger) {
 | 
			
		||||
        this.logger = logger;
 | 
			
		||||
        configOptions = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
        dataFolderPath = Stargate.getInstance().getDataFolder().getPath().replaceAll("\\\\", "/");
 | 
			
		||||
        portalFolder = dataFolderPath + "/portals/";
 | 
			
		||||
        gateFolder = dataFolderPath + "/gates/";
 | 
			
		||||
        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
 | 
			
		||||
     */
 | 
			
		||||
    public void finishSetup() {
 | 
			
		||||
        this.loadConfig();
 | 
			
		||||
 | 
			
		||||
        //Enable the required channels for Bungee support
 | 
			
		||||
        if (stargateGateConfig.enableBungee()) {
 | 
			
		||||
            startStopBungeeListener(true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Set the chosen language and reload the language loader
 | 
			
		||||
        languageLoader.setChosenLanguage(languageName);
 | 
			
		||||
        languageLoader.reload();
 | 
			
		||||
 | 
			
		||||
        messageSender = new MessageSender(languageLoader);
 | 
			
		||||
        if (isDebuggingEnabled()) {
 | 
			
		||||
            languageLoader.debug();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.createMissingFolders();
 | 
			
		||||
        this.loadGates();
 | 
			
		||||
        this.loadAllPortals();
 | 
			
		||||
 | 
			
		||||
        //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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the queue of open portals
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The open portals queue is used to close open portals after some time has passed</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The open portals queue</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Queue<Portal> getOpenPortalsQueue() {
 | 
			
		||||
        return openPortalsQueue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the queue of active portals
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The active portals queue is used to de-activate portals after some time has passed</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The active portals queue</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Queue<Portal> getActivePortalsQueue() {
 | 
			
		||||
        return activePortalsQueue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether debugging is enabled
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether debugging is enabled</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isDebuggingEnabled() {
 | 
			
		||||
        return (boolean) configOptions.get(ConfigOption.DEBUG);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether permission debugging is enabled
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether permission debugging is enabled</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isPermissionDebuggingEnabled() {
 | 
			
		||||
        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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the object containing economy config values
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The object containing economy config values</p>
 | 
			
		||||
     */
 | 
			
		||||
    public EconomyConfig getEconomyConfig() {
 | 
			
		||||
        return this.economyConfig;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reloads all portals and files
 | 
			
		||||
     *
 | 
			
		||||
     * @param sender <p>The sender of the reload request</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void reload(CommandSender sender) {
 | 
			
		||||
        //Unload all saved data
 | 
			
		||||
        unload();
 | 
			
		||||
 | 
			
		||||
        //Perform all block change requests to prevent mismatch if a gate's open-material changes. Changing the 
 | 
			
		||||
        // closed-material still requires a restart.
 | 
			
		||||
        BlockChangeRequest firstElement = Stargate.getBlockChangeRequestQueue().peek();
 | 
			
		||||
        while (firstElement != null) {
 | 
			
		||||
            BlockChangeThread.pollQueue();
 | 
			
		||||
            firstElement = Stargate.getBlockChangeRequestQueue().peek();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Store the old enable bungee state in case it changes
 | 
			
		||||
        boolean oldEnableBungee = stargateGateConfig.enableBungee();
 | 
			
		||||
 | 
			
		||||
        //Load all data
 | 
			
		||||
        load();
 | 
			
		||||
 | 
			
		||||
        //Enable or disable the required channels for Bungee support
 | 
			
		||||
        if (oldEnableBungee != stargateGateConfig.enableBungee()) {
 | 
			
		||||
            startStopBungeeListener(stargateGateConfig.enableBungee());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Reload portal markers
 | 
			
		||||
        DynmapManager.addAllPortalMarkers();
 | 
			
		||||
 | 
			
		||||
        messageSender.sendErrorMessage(sender, languageLoader.getString("reloaded"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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();
 | 
			
		||||
        }
 | 
			
		||||
        //Force all portals to close
 | 
			
		||||
        closeAllOpenPortals();
 | 
			
		||||
        PortalHandler.closeAllPortals();
 | 
			
		||||
 | 
			
		||||
        //Clear queues and lists
 | 
			
		||||
        activePortalsQueue.clear();
 | 
			
		||||
        openPortalsQueue.clear();
 | 
			
		||||
        managedWorlds.clear();
 | 
			
		||||
 | 
			
		||||
        //Clear all loaded portals
 | 
			
		||||
        PortalRegistry.clearPortals();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clears the set of managed worlds
 | 
			
		||||
     */
 | 
			
		||||
    public void clearManagedWorlds() {
 | 
			
		||||
        managedWorlds.clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a copy of the set of managed worlds
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The managed worlds</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Set<String> getManagedWorlds() {
 | 
			
		||||
        return new HashSet<>(managedWorlds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a world to the managed worlds
 | 
			
		||||
     *
 | 
			
		||||
     * @param worldName <p>The name of the world to manage</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void addManagedWorld(String worldName) {
 | 
			
		||||
        managedWorlds.add(worldName);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes a world from the managed worlds
 | 
			
		||||
     *
 | 
			
		||||
     * @param worldName <p>The name of the world to stop managing</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void removeManagedWorld(String worldName) {
 | 
			
		||||
        managedWorlds.remove(worldName);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads all necessary data
 | 
			
		||||
     */
 | 
			
		||||
    private void load() {
 | 
			
		||||
        //Load the config from disk
 | 
			
		||||
        loadConfig();
 | 
			
		||||
 | 
			
		||||
        //Load all gates
 | 
			
		||||
        loadGates();
 | 
			
		||||
 | 
			
		||||
        //Load all portals
 | 
			
		||||
        loadAllPortals();
 | 
			
		||||
 | 
			
		||||
        //Update the language loader in case the loaded language changed
 | 
			
		||||
        languageLoader.setChosenLanguage(languageName);
 | 
			
		||||
        languageLoader.reload();
 | 
			
		||||
        if (isDebuggingEnabled()) {
 | 
			
		||||
            languageLoader.debug();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Load Economy support if enabled/clear if disabled
 | 
			
		||||
        reloadEconomy();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Starts the listener for listening to BungeeCord messages
 | 
			
		||||
     */
 | 
			
		||||
    public void startStopBungeeListener(boolean start) {
 | 
			
		||||
        Messenger messenger = Bukkit.getMessenger();
 | 
			
		||||
        String bungeeChannel = "BungeeCord";
 | 
			
		||||
 | 
			
		||||
        if (start) {
 | 
			
		||||
            messenger.registerOutgoingPluginChannel(Stargate.getInstance(), bungeeChannel);
 | 
			
		||||
            messenger.registerIncomingPluginChannel(Stargate.getInstance(), bungeeChannel, new BungeeCordListener());
 | 
			
		||||
        } else {
 | 
			
		||||
            messenger.unregisterIncomingPluginChannel(Stargate.getInstance(), bungeeChannel);
 | 
			
		||||
            messenger.unregisterOutgoingPluginChannel(Stargate.getInstance(), bungeeChannel);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reloads economy by enabling or disabling it as necessary
 | 
			
		||||
     */
 | 
			
		||||
    public void reloadEconomy() {
 | 
			
		||||
        EconomyConfig economyConfig = getEconomyConfig();
 | 
			
		||||
        if (economyConfig.isEconomyEnabled() && economyConfig.getEconomy() == null) {
 | 
			
		||||
            setupVaultEconomy();
 | 
			
		||||
        } else if (!economyConfig.isEconomyEnabled()) {
 | 
			
		||||
            economyConfig.disableEconomy();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Forces all open portals to close
 | 
			
		||||
     */
 | 
			
		||||
    public void closeAllOpenPortals() {
 | 
			
		||||
        for (Portal openPortal : openPortalsQueue) {
 | 
			
		||||
            openPortal.getPortalOpener().closePortal(false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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
 | 
			
		||||
     */
 | 
			
		||||
    public void loadConfig() {
 | 
			
		||||
        Stargate.getInstance().reloadConfig();
 | 
			
		||||
        FileConfiguration newConfig = Stargate.getInstance().getConfig();
 | 
			
		||||
 | 
			
		||||
        boolean isMigrating = false;
 | 
			
		||||
        if (newConfig.getString("lang") != null || newConfig.getString("economy.freeGatesGreen") != null) {
 | 
			
		||||
            migrateConfig(newConfig);
 | 
			
		||||
            isMigrating = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //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 = (String) configOptions.get(ConfigOption.LANGUAGE);
 | 
			
		||||
 | 
			
		||||
        //Get important folders from the config
 | 
			
		||||
        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) {
 | 
			
		||||
            GateHandler.writeDefaultGatesToFolder(gateFolder);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Load all gate config values
 | 
			
		||||
        stargateGateConfig = new StargateGateConfig(configOptions);
 | 
			
		||||
 | 
			
		||||
        //Load all economy config values
 | 
			
		||||
        economyConfig = new EconomyConfig(configOptions);
 | 
			
		||||
 | 
			
		||||
        Stargate.getInstance().saveConfig();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the object containing configuration values regarding gates
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Gets the gate config</p>
 | 
			
		||||
     */
 | 
			
		||||
    public StargateGateConfig getStargateGateConfig() {
 | 
			
		||||
        return stargateGateConfig;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads all available gates
 | 
			
		||||
     */
 | 
			
		||||
    public void loadGates() {
 | 
			
		||||
        GateHandler.loadGates(gateFolder);
 | 
			
		||||
        Stargate.logInfo(String.format("Loaded %s gate layouts", GateHandler.getGateCount()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Changes all configuration values from the old name to the new name
 | 
			
		||||
     *
 | 
			
		||||
     * @param newConfig <p>The config to read from and write to</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void migrateConfig(FileConfiguration newConfig) {
 | 
			
		||||
        //Save the old config just in case something goes wrong
 | 
			
		||||
        try {
 | 
			
		||||
            newConfig.save(dataFolderPath + "/config.yml.old");
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            Stargate.debug("Stargate::migrateConfig", "Unable to save old backup and do migration");
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Read all available config migrations
 | 
			
		||||
        Map<String, String> migrationFields;
 | 
			
		||||
        try {
 | 
			
		||||
            migrationFields = FileHelper.readKeyValuePairs(FileHelper.getBufferedReaderFromInputStream(
 | 
			
		||||
                            FileHelper.getInputStreamForInternalFile("/config-migrations.txt")), "=",
 | 
			
		||||
                    ColorConversion.NORMAL);
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            Stargate.debug("Stargate::migrateConfig", "Unable to load config migration file");
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Replace old config names with the new ones
 | 
			
		||||
        for (String key : migrationFields.keySet()) {
 | 
			
		||||
            if (newConfig.contains(key)) {
 | 
			
		||||
                String newPath = migrationFields.get(key);
 | 
			
		||||
                Object oldValue = newConfig.get(key);
 | 
			
		||||
                if (!newPath.trim().isEmpty()) {
 | 
			
		||||
                    newConfig.set(newPath, oldValue);
 | 
			
		||||
                }
 | 
			
		||||
                newConfig.set(key, null);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads economy from Vault
 | 
			
		||||
     */
 | 
			
		||||
    private void setupVaultEconomy() {
 | 
			
		||||
        EconomyConfig economyConfig = getEconomyConfig();
 | 
			
		||||
        if (economyConfig.setupEconomy(Stargate.getPluginManager()) && economyConfig.getEconomy() != null) {
 | 
			
		||||
            String vaultVersion = economyConfig.getVault().getDescription().getVersion();
 | 
			
		||||
            Stargate.logInfo(Stargate.replaceVars(Stargate.getString("vaultLoaded"), "%version%", vaultVersion));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads all portals in all un-managed worlds
 | 
			
		||||
     */
 | 
			
		||||
    public void loadAllPortals() {
 | 
			
		||||
        for (World world : Stargate.getInstance().getServer().getWorlds()) {
 | 
			
		||||
            if (!managedWorlds.contains(world.getName())) {
 | 
			
		||||
                PortalFileHelper.loadAllPortals(world);
 | 
			
		||||
                managedWorlds.add(world.getName());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates missing folders
 | 
			
		||||
     */
 | 
			
		||||
    private void createMissingFolders() {
 | 
			
		||||
        File newPortalDir = new File(portalFolder);
 | 
			
		||||
        if (!newPortalDir.exists()) {
 | 
			
		||||
            if (!newPortalDir.mkdirs()) {
 | 
			
		||||
                logger.severe("Unable to create portal directory");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        File newFile = new File(portalFolder, Stargate.getInstance().getServer().getWorlds().get(0).getName() +
 | 
			
		||||
                ".db");
 | 
			
		||||
        if (!newFile.exists() && !newFile.getParentFile().exists()) {
 | 
			
		||||
            if (!newFile.getParentFile().mkdirs()) {
 | 
			
		||||
                logger.severe("Unable to create portal database folder: " + newFile.getParentFile().getPath());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the folder all portals are stored in
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The portal folder</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getPortalFolder() {
 | 
			
		||||
        return portalFolder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the folder storing gate files
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The returned String path is the full path to the folder</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The folder storing gate files</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getGateFolder() {
 | 
			
		||||
        return gateFolder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the sender for sending messages to players
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The sender for sending messages to players</p>
 | 
			
		||||
     */
 | 
			
		||||
    public MessageSender getMessageSender() {
 | 
			
		||||
        return messageSender;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the language loader containing translated strings
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The language loader</p>
 | 
			
		||||
     */
 | 
			
		||||
    public LanguageLoader getLanguageLoader() {
 | 
			
		||||
        return languageLoader;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,328 @@
 | 
			
		||||
package net.knarcraft.stargate.config;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.knarlib.util.ColorHelper;
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.portal.PortalSignDrawer;
 | 
			
		||||
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 static final int activeTime = 10;
 | 
			
		||||
    private static final int openTime = 10;
 | 
			
		||||
    private final Map<ConfigOption, Object> configOptions;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new stargate config
 | 
			
		||||
     *
 | 
			
		||||
     * @param configOptions <p>The loaded config options to use</p>
 | 
			
		||||
     */
 | 
			
		||||
    public StargateGateConfig(Map<ConfigOption, Object> configOptions) {
 | 
			
		||||
        this.configOptions = configOptions;
 | 
			
		||||
        loadGateConfig();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the amount of seconds a portal should be open before automatically closing
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The open time of a gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public int getOpenTime() {
 | 
			
		||||
        return openTime;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the amount of seconds a portal should be active before automatically deactivating
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The active time of a gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public int getActiveTime() {
 | 
			
		||||
        return activeTime;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the maximum number of gates allowed on each network
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Maximum number of gates for each network</p>
 | 
			
		||||
     */
 | 
			
		||||
    public int maxGatesEachNetwork() {
 | 
			
		||||
        return (int) configOptions.get(ConfigOption.MAX_GATES_EACH_NETWORK);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether a portal's lastly used destination should be remembered
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether a portal's lastly used destination should be remembered</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean rememberDestination() {
 | 
			
		||||
        return (boolean) configOptions.get(ConfigOption.REMEMBER_DESTINATION);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether vehicle teleportation should be handled in addition to player teleportation
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether vehicle teleportation should be handled</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean 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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether the list of destinations within a network should be sorted
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether network destinations should be sorted</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean sortNetworkDestinations() {
 | 
			
		||||
        return (boolean) configOptions.get(ConfigOption.SORT_NETWORK_DESTINATIONS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether portal entrances should be protected from block breaking
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether portal entrances should be protected</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean protectEntrance() {
 | 
			
		||||
        return (boolean) configOptions.get(ConfigOption.PROTECT_ENTRANCE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether BungeeCord support is enabled
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether bungee support is enabled</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean enableBungee() {
 | 
			
		||||
        return (boolean) configOptions.get(ConfigOption.ENABLE_BUNGEE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether all portals' integrity has to be verified on startup and reload
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether portals need to be verified</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean verifyPortals() {
 | 
			
		||||
        return (boolean) configOptions.get(ConfigOption.VERIFY_PORTALS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether portals should be destroyed by nearby explosions
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether portals should be destroyed by explosions</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean destroyedByExplosion() {
 | 
			
		||||
        return (boolean) configOptions.get(ConfigOption.DESTROYED_BY_EXPLOSION);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the default portal network to use if no other network is given
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The default portal network</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getDefaultPortalNetwork() {
 | 
			
		||||
        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
 | 
			
		||||
     */
 | 
			
		||||
    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();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads the per-sign colors specified in the config file
 | 
			
		||||
     */
 | 
			
		||||
    public void loadPerSignColors() {
 | 
			
		||||
        List<?> perSignColors = (List<?>) configOptions.get(ConfigOption.PER_SIGN_COLORS);
 | 
			
		||||
        ChatColor[] defaultColors = new ChatColor[]{PortalSignDrawer.getMainColor(), PortalSignDrawer.getHighlightColor()};
 | 
			
		||||
        List<Map<Material, ChatColor>> colorMaps = new ArrayList<>();
 | 
			
		||||
        colorMaps.add(new HashMap<>());
 | 
			
		||||
        colorMaps.add(new HashMap<>());
 | 
			
		||||
 | 
			
		||||
        for (Object signColorSpecification : perSignColors) {
 | 
			
		||||
            parsePerSignColors(signColorSpecification, defaultColors, colorMaps);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        PortalSignDrawer.setPerSignMainColors(colorMaps.get(0));
 | 
			
		||||
        PortalSignDrawer.setPerSignHighlightColors(colorMaps.get(1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses a per-sign color specification object and stores the result
 | 
			
		||||
     *
 | 
			
		||||
     * @param signColorSpecification <p>The sign color specification to parse</p>
 | 
			
		||||
     * @param defaultColors          <p>The specified default colors</p>
 | 
			
		||||
     * @param colorMaps              <p>The list of color maps to save the resulting colors to</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void parsePerSignColors(Object signColorSpecification, ChatColor[] defaultColors,
 | 
			
		||||
                                    List<Map<Material, ChatColor>> colorMaps) {
 | 
			
		||||
        String[] specificationData = String.valueOf(signColorSpecification).split(":");
 | 
			
		||||
        Material[] signMaterials = new Material[]{Material.matchMaterial(specificationData[0] + "_SIGN"),
 | 
			
		||||
                Material.matchMaterial(specificationData[0] + "_WALL_SIGN")};
 | 
			
		||||
 | 
			
		||||
        if (specificationData.length != 2) {
 | 
			
		||||
            Stargate.logWarning("You have an invalid per-sign line in your config.yml file. Please fix it!");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        String[] colors = specificationData[1].split(",");
 | 
			
		||||
        if (colors.length != 2) {
 | 
			
		||||
            Stargate.logWarning("You have an invalid per-sign line in your config.yml file. Please fix it!");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        for (int colorIndex = 0; colorIndex < 2; colorIndex++) {
 | 
			
		||||
            if (colors[colorIndex].equalsIgnoreCase("default")) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            loadPerSignColor(colors, colorIndex, defaultColors, signMaterials, colorMaps);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads a per-sign color
 | 
			
		||||
     *
 | 
			
		||||
     * @param colors        <p>The colors specified in the config file</p>
 | 
			
		||||
     * @param colorIndex    <p>The index of the color to load</p>
 | 
			
		||||
     * @param defaultColors <p>The specified default colors</p>
 | 
			
		||||
     * @param signMaterials <p>The materials to load this color for</p>
 | 
			
		||||
     * @param colorMaps     <p>The list of color maps to save the resulting color to</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void loadPerSignColor(String[] colors, int colorIndex, ChatColor[] defaultColors, Material[] signMaterials,
 | 
			
		||||
                                  List<Map<Material, ChatColor>> colorMaps) {
 | 
			
		||||
        ChatColor parsedColor;
 | 
			
		||||
        if (colors[colorIndex].equalsIgnoreCase("inverted")) {
 | 
			
		||||
            //Convert from ChatColor to awt.Color to Bukkit.Color then invert and convert to ChatColor
 | 
			
		||||
            java.awt.Color color = defaultColors[colorIndex].getColor();
 | 
			
		||||
            parsedColor = ColorHelper.fromColor(ColorHelper.invert(Color.fromRGB(color.getRed(), color.getGreen(),
 | 
			
		||||
                    color.getBlue())));
 | 
			
		||||
        } else {
 | 
			
		||||
            try {
 | 
			
		||||
                parsedColor = ChatColor.of(colors[colorIndex]);
 | 
			
		||||
            } catch (IllegalArgumentException | NullPointerException exception) {
 | 
			
		||||
                Stargate.logWarning("You have specified an invalid per-sign color in your config.yml. Custom color for \"" +
 | 
			
		||||
                        signMaterials[0] + "\" disabled");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (parsedColor != null) {
 | 
			
		||||
            for (Material signMaterial : signMaterials) {
 | 
			
		||||
                colorMaps.get(colorIndex).put(signMaterial, parsedColor);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads the correct sign color given a sign color string
 | 
			
		||||
     *
 | 
			
		||||
     * @param mainSignColor <p>A string representing the main sign color</p>
 | 
			
		||||
     */
 | 
			
		||||
    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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
package net.knarcraft.stargate.container;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.Axis;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a request for changing a block into another material
 | 
			
		||||
 */
 | 
			
		||||
public class BlockChangeRequest {
 | 
			
		||||
 | 
			
		||||
    private final BlockLocation blockLocation;
 | 
			
		||||
    private final Material newMaterial;
 | 
			
		||||
    private final Axis newAxis;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new block change request
 | 
			
		||||
     *
 | 
			
		||||
     * @param blockLocation <p>The location of the block to change</p>
 | 
			
		||||
     * @param material      <p>The new material to change the block to</p>
 | 
			
		||||
     * @param axis          <p>The new axis to orient the block along</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockChangeRequest(BlockLocation blockLocation, Material material, Axis axis) {
 | 
			
		||||
        this.blockLocation = blockLocation;
 | 
			
		||||
        newMaterial = material;
 | 
			
		||||
        newAxis = axis;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the location of the block to change
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The location of the block</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockLocation getBlockLocation() {
 | 
			
		||||
        return blockLocation;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the material to change the block into
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The material to change the block into</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Material getMaterial() {
 | 
			
		||||
        return newMaterial;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the axis to orient the block along
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The axis to orient the block along</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Axis getAxis() {
 | 
			
		||||
        return newAxis;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,227 @@
 | 
			
		||||
package net.knarcraft.stargate.container;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.utility.DirectionHelper;
 | 
			
		||||
import org.bukkit.Location;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
import org.bukkit.World;
 | 
			
		||||
import org.bukkit.block.Block;
 | 
			
		||||
import org.bukkit.block.BlockFace;
 | 
			
		||||
import org.bukkit.block.data.BlockData;
 | 
			
		||||
import org.bukkit.block.data.Directional;
 | 
			
		||||
import org.bukkit.block.data.type.Sign;
 | 
			
		||||
import org.bukkit.util.Vector;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class represents a block location
 | 
			
		||||
 *
 | 
			
		||||
 * <p>The BlockLocation class is basically a Location with some extra functionality.
 | 
			
		||||
 * Warning: Because of differences in the equals methods between Location and BlockLocation, a BlockLocation which
 | 
			
		||||
 * equals another BlockLocation does not necessarily equal the same BlockLocation if treated as a Location.</p>
 | 
			
		||||
 */
 | 
			
		||||
public class BlockLocation extends Location {
 | 
			
		||||
 | 
			
		||||
    private BlockLocation parent = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new block location
 | 
			
		||||
     *
 | 
			
		||||
     * @param world <p>The world the block exists in</p>
 | 
			
		||||
     * @param x     <p>The x coordinate of the block</p>
 | 
			
		||||
     * @param y     <p>The y coordinate of the block</p>
 | 
			
		||||
     * @param z     <p>The z coordinate of the block</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockLocation(World world, int x, int y, int z) {
 | 
			
		||||
        super(world, x, y, z);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a block location from a block
 | 
			
		||||
     *
 | 
			
		||||
     * @param block <p>The block to get the location of</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockLocation(Block block) {
 | 
			
		||||
        super(block.getWorld(), block.getX(), block.getY(), block.getZ());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a block location from a string
 | 
			
		||||
     *
 | 
			
		||||
     * @param world  <p>The world the block exists in</p>
 | 
			
		||||
     * @param string <p>A comma separated list of x, y and z coordinates as integers</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockLocation(World world, String string) {
 | 
			
		||||
        super(world, Integer.parseInt(string.split(",")[0]), Integer.parseInt(string.split(",")[1]),
 | 
			
		||||
                Integer.parseInt(string.split(",")[2]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new block location in a relative position to this block location
 | 
			
		||||
     *
 | 
			
		||||
     * @param x <p>The number of blocks to move in the x-direction</p>
 | 
			
		||||
     * @param y <p>The number of blocks to move in the y-direction</p>
 | 
			
		||||
     * @param z <p>The number of blocks to move in the z-direction</p>
 | 
			
		||||
     * @return <p>A new block location</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockLocation makeRelativeBlockLocation(int x, int y, int z) {
 | 
			
		||||
        return (BlockLocation) this.clone().add(x, y, z);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a location in a relative position to this block location
 | 
			
		||||
     *
 | 
			
		||||
     * @param x   <p>The number of blocks to move in the x-direction</p>
 | 
			
		||||
     * @param y   <p>The number of blocks to move in the y-direction</p>
 | 
			
		||||
     * @param z   <p>The z position relative to this block's position</p>
 | 
			
		||||
     * @param yaw <p>The number of blocks to move in the z-direction</p>
 | 
			
		||||
     * @return <p>A new location</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Location makeRelativeLocation(double x, double y, double z, float yaw) {
 | 
			
		||||
        Location newLocation = this.clone();
 | 
			
		||||
        newLocation.setYaw(yaw);
 | 
			
		||||
        newLocation.setPitch(0);
 | 
			
		||||
        return newLocation.add(x, y, z);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a location relative to this block location
 | 
			
		||||
     *
 | 
			
		||||
     * @param relativeVector <p>The relative block vector describing the relative location</p>
 | 
			
		||||
     * @param yaw            <p>The yaw pointing outwards from a portal (in the relative vector's out direction)</p>
 | 
			
		||||
     * @return <p>A location relative to this location</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockLocation getRelativeLocation(RelativeBlockVector relativeVector, double yaw) {
 | 
			
		||||
        Vector realVector = DirectionHelper.getCoordinateVectorFromRelativeVector(relativeVector.getRight(),
 | 
			
		||||
                relativeVector.getDown(), relativeVector.getOut(), yaw);
 | 
			
		||||
        return makeRelativeBlockLocation(realVector.getBlockX(), realVector.getBlockY(), realVector.getBlockZ());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Makes a location relative to the current location according to given parameters
 | 
			
		||||
     *
 | 
			
		||||
     * <p>Out goes in the direction of the yaw. Right goes in the direction of (yaw - 90) degrees.
 | 
			
		||||
     * Depth goes downwards following the -y direction.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param right     <p>The amount of blocks to go right when looking towards a portal</p>
 | 
			
		||||
     * @param down      <p>The amount of blocks to go downwards when looking towards a portal</p>
 | 
			
		||||
     * @param out       <p>The amount of blocks to go outwards when looking towards a portal</p>
 | 
			
		||||
     * @param portalYaw <p>The yaw when looking out from the portal</p>
 | 
			
		||||
     * @return A new location relative to this block location
 | 
			
		||||
     */
 | 
			
		||||
    public Location getRelativeLocation(double right, double down, double out, float portalYaw) {
 | 
			
		||||
        Vector realVector = DirectionHelper.getCoordinateVectorFromRelativeVector(right, down, out, portalYaw);
 | 
			
		||||
        return makeRelativeLocation(0.5 + realVector.getBlockX(), realVector.getBlockY(),
 | 
			
		||||
                0.5 + realVector.getBlockZ(), portalYaw);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the type of block at this block location
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The block's material type</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Material getType() {
 | 
			
		||||
        return this.getBlock().getType();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the type of block at this location
 | 
			
		||||
     *
 | 
			
		||||
     * @param type <p>The block's new material type</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setType(Material type) {
 | 
			
		||||
        this.getBlock().setType(type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the location representing this block location
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The location representing this block location</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Location getLocation() {
 | 
			
		||||
        return this.clone();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets this block location's parent block
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The parent block is the block the item at this block location is attached to. Usually this is the block a
 | 
			
		||||
     * sign or wall sign is attached to.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>This block location's parent block</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Block getParent() {
 | 
			
		||||
        if (parent == null) {
 | 
			
		||||
            findParent();
 | 
			
		||||
        }
 | 
			
		||||
        if (parent == null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return parent.getBlock();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Tries to find the parent block location
 | 
			
		||||
     *
 | 
			
		||||
     * <p>If this block location is a sign, the parent is the block location of the block the sign is connected to.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void findParent() {
 | 
			
		||||
        int offsetX = 0;
 | 
			
		||||
        int offsetY = 0;
 | 
			
		||||
        int offsetZ = 0;
 | 
			
		||||
 | 
			
		||||
        BlockData blockData = getBlock().getBlockData();
 | 
			
		||||
        if (blockData instanceof Directional) {
 | 
			
		||||
            //Get the offset of the block "behind" this block
 | 
			
		||||
            BlockFace facing = ((Directional) blockData).getFacing().getOppositeFace();
 | 
			
		||||
            offsetX = facing.getModX();
 | 
			
		||||
            offsetZ = facing.getModZ();
 | 
			
		||||
        } else if (blockData instanceof Sign) {
 | 
			
		||||
            //Get offset the block beneath the sign
 | 
			
		||||
            offsetY = -1;
 | 
			
		||||
        } else {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        parent = this.makeRelativeBlockLocation(offsetX, offsetY, offsetZ);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return String.valueOf(this.getBlockX()) + ',' + this.getBlockY() + ',' + this.getBlockZ();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int hashCode() {
 | 
			
		||||
        int result = 18;
 | 
			
		||||
 | 
			
		||||
        result = result * 27 + this.getBlockX();
 | 
			
		||||
        result = result * 27 + this.getBlockY();
 | 
			
		||||
        result = result * 27 + this.getBlockZ();
 | 
			
		||||
        if (this.getWorld() != null) {
 | 
			
		||||
            result = result * 27 + this.getWorld().getName().hashCode();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object object) {
 | 
			
		||||
        if (this == object) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        if (object == null || getClass() != object.getClass()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        BlockLocation blockLocation = (BlockLocation) object;
 | 
			
		||||
 | 
			
		||||
        World thisWorld = this.getWorld();
 | 
			
		||||
        World otherWorld = blockLocation.getWorld();
 | 
			
		||||
        //Check if the worlds of the two locations match
 | 
			
		||||
        boolean worldsEqual = (thisWorld == null && otherWorld == null) || ((thisWorld != null && otherWorld != null)
 | 
			
		||||
                && thisWorld == otherWorld);
 | 
			
		||||
 | 
			
		||||
        //As this is a block location, only the block coordinates are compared
 | 
			
		||||
        return blockLocation.getBlockX() == this.getBlockX() && blockLocation.getBlockY() == this.getBlockY() &&
 | 
			
		||||
                blockLocation.getBlockZ() == this.getBlockZ() && worldsEqual;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
package net.knarcraft.stargate.container;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.Chunk;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a requests for the unloading of a chunk which has been previously loaded by the Stargate plugin
 | 
			
		||||
 */
 | 
			
		||||
public class ChunkUnloadRequest implements Comparable<ChunkUnloadRequest> {
 | 
			
		||||
 | 
			
		||||
    private final Long unloadNanoTime;
 | 
			
		||||
    private final Chunk chunkToUnload;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new chunk unloading request
 | 
			
		||||
     *
 | 
			
		||||
     * @param chunkToUnload   <p>The chunk to request the unloading of</p>
 | 
			
		||||
     * @param timeUntilUnload <p>The time in milliseconds to wait before unloading the chunk</p>
 | 
			
		||||
     */
 | 
			
		||||
    public ChunkUnloadRequest(Chunk chunkToUnload, Long timeUntilUnload) {
 | 
			
		||||
        this.chunkToUnload = chunkToUnload;
 | 
			
		||||
        long systemNanoTime = System.nanoTime();
 | 
			
		||||
        this.unloadNanoTime = systemNanoTime + (timeUntilUnload * 1000000);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the chunk to unload
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The chunk to unload</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Chunk getChunkToUnload() {
 | 
			
		||||
        return this.chunkToUnload;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the system nano time denoting at which time the unload request should be executed
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The system nano time denoting when the chunk is to be unloaded</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Long getUnloadNanoTime() {
 | 
			
		||||
        return this.unloadNanoTime;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return "{" + chunkToUnload + ", " + unloadNanoTime + "}";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int compareTo(@NotNull ChunkUnloadRequest otherRequest) {
 | 
			
		||||
        //Prioritize requests based on time until unload
 | 
			
		||||
        return unloadNanoTime.compareTo(otherRequest.unloadNanoTime);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,60 @@
 | 
			
		||||
package net.knarcraft.stargate.container;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class represents a player teleporting from the end to the over-world using an artificial end portal
 | 
			
		||||
 *
 | 
			
		||||
 * <p>This is necessary because a player entering an end portal in the end is a special case. Instead of being
 | 
			
		||||
 * teleported, the player is respawned. Because of this, the teleportation needs to be saved and later used to hijack
 | 
			
		||||
 * the position of where the player is to respawn.</p>
 | 
			
		||||
 */
 | 
			
		||||
public class FromTheEndTeleportation {
 | 
			
		||||
 | 
			
		||||
    private final Player teleportingPlayer;
 | 
			
		||||
    private final Portal exitPortal;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new teleportation from the end
 | 
			
		||||
     *
 | 
			
		||||
     * @param teleportingPlayer <p>The teleporting player</p>
 | 
			
		||||
     * @param exitPortal        <p>The portal to exit from</p>
 | 
			
		||||
     */
 | 
			
		||||
    public FromTheEndTeleportation(Player teleportingPlayer, Portal exitPortal) {
 | 
			
		||||
        this.teleportingPlayer = teleportingPlayer;
 | 
			
		||||
        this.exitPortal = exitPortal;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the teleporting player
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The teleporting player</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Player getPlayer() {
 | 
			
		||||
        return this.teleportingPlayer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the portal to exit from
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The portal to exit from</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Portal getExit() {
 | 
			
		||||
        return this.exitPortal;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int hashCode() {
 | 
			
		||||
        return teleportingPlayer.hashCode();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object other) {
 | 
			
		||||
        if (!(other instanceof FromTheEndTeleportation otherTeleportation)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return teleportingPlayer.equals(otherTeleportation.teleportingPlayer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,133 @@
 | 
			
		||||
package net.knarcraft.stargate.container;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.util.Vector;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This stores a block location as a vector relative to a position
 | 
			
		||||
 *
 | 
			
		||||
 * <p>A relative block vector stores a vector relative to some origin. The origin in this plugin is usually the
 | 
			
		||||
 * top-left block of a gate (top-left when looking at the side with the sign). The right is therefore the distance
 | 
			
		||||
 * from the top-left corner towards the top-right corner. Down is the distance from the top-left corner towards the
 | 
			
		||||
 * bottom-left corner. Out is the distance outward from the gate.</p>
 | 
			
		||||
 */
 | 
			
		||||
public class RelativeBlockVector {
 | 
			
		||||
 | 
			
		||||
    private final int right;
 | 
			
		||||
    private final int down;
 | 
			
		||||
    private final int out;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A specifier for one of the relative block vector's three properties
 | 
			
		||||
     */
 | 
			
		||||
    public enum Property {
 | 
			
		||||
        /**
 | 
			
		||||
         * Specifies the relative block vector's right property
 | 
			
		||||
         */
 | 
			
		||||
        RIGHT,
 | 
			
		||||
        /**
 | 
			
		||||
         * Specifies the relative block vector's down property
 | 
			
		||||
         */
 | 
			
		||||
        DOWN,
 | 
			
		||||
        /**
 | 
			
		||||
         * Specifies the relative block vector's out property
 | 
			
		||||
         */
 | 
			
		||||
        OUT
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new relative block vector
 | 
			
		||||
     *
 | 
			
		||||
     * <p>Relative block vectors start from a top-left corner. A yaw is used to orient a relative block vector in the
 | 
			
		||||
     * "real world".
 | 
			
		||||
     * In terms of a gate layout, the origin is 0,0. Right is towards the end of the line. Down is to the
 | 
			
		||||
     * next line. Out is towards the observer.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param right <p>The distance rightward relative to the origin</p>
 | 
			
		||||
     * @param down  <p>The distance downward relative to the origin</p>
 | 
			
		||||
     * @param out   <p>The distance outward relative to the origin</p>
 | 
			
		||||
     */
 | 
			
		||||
    public RelativeBlockVector(int right, int down, int out) {
 | 
			
		||||
        this.right = right;
 | 
			
		||||
        this.down = down;
 | 
			
		||||
        this.out = out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a value to one of the properties of this relative block vector
 | 
			
		||||
     *
 | 
			
		||||
     * @param propertyToAddTo <p>The property to add to</p>
 | 
			
		||||
     * @param valueToAdd      <p>The value to add to the property (negative to move in the opposite direction)</p>
 | 
			
		||||
     * @return <p>A new relative block vector with the property altered</p>
 | 
			
		||||
     */
 | 
			
		||||
    public RelativeBlockVector addToVector(Property propertyToAddTo, int valueToAdd) {
 | 
			
		||||
        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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a relative block vector which is this inverted (pointing in the opposite direction)
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>This vector, but inverted</p>
 | 
			
		||||
     */
 | 
			
		||||
    public RelativeBlockVector invert() {
 | 
			
		||||
        return new RelativeBlockVector(-this.right, -this.down, -this.out);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the distance to the right relative to the origin
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The distance to the right relative to the origin</p>
 | 
			
		||||
     */
 | 
			
		||||
    public int getRight() {
 | 
			
		||||
        return right;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the distance downward relative to the origin
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The distance downward relative to the origin</p>
 | 
			
		||||
     */
 | 
			
		||||
    public int getDown() {
 | 
			
		||||
        return down;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the distance outward relative to the origin
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The distance outward relative to the origin</p>
 | 
			
		||||
     */
 | 
			
		||||
    public int getOut() {
 | 
			
		||||
        return out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return String.format("(right = %d, down = %d, out = %d)", right, down, out);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object other) {
 | 
			
		||||
        if (other == this) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        if (other == null || this.getClass() != other.getClass()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        RelativeBlockVector otherVector = (RelativeBlockVector) other;
 | 
			
		||||
        return this.right == otherVector.right && this.down == otherVector.down &&
 | 
			
		||||
                this.out == otherVector.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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,66 @@
 | 
			
		||||
package net.knarcraft.stargate.event;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.event.HandlerList;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This event should be called whenever a player attempts to access a stargate
 | 
			
		||||
 *
 | 
			
		||||
 * <p>This event is triggered whenever a player enters or activates a stargate. This event can be used to override
 | 
			
		||||
 * whether the player should be allowed to access the stargate.</p>
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class StargateAccessEvent extends StargatePlayerEvent {
 | 
			
		||||
 | 
			
		||||
    private static final HandlerList handlers = new HandlerList();
 | 
			
		||||
    private boolean deny;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new stargate access event
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player involved in the event</p>
 | 
			
		||||
     * @param portal <p>The portal involved in the event</p>
 | 
			
		||||
     * @param deny   <p>Whether the stargate access should be denied</p>
 | 
			
		||||
     */
 | 
			
		||||
    public StargateAccessEvent(Player player, Portal portal, boolean deny) {
 | 
			
		||||
        super(portal, player);
 | 
			
		||||
 | 
			
		||||
        this.deny = deny;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether the player should be denied access
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether the player should be denied access</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean getDeny() {
 | 
			
		||||
        return this.deny;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets whether to deny access to the player
 | 
			
		||||
     *
 | 
			
		||||
     * @param deny <p>Whether to deny access to the player</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setDeny(boolean deny) {
 | 
			
		||||
        this.deny = deny;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a handler-list containing all event handlers
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A handler-list with all event handlers</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static HandlerList getHandlerList() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public HandlerList getHandlers() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,89 @@
 | 
			
		||||
package net.knarcraft.stargate.event;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.event.HandlerList;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This event should be called whenever a player activates a stargate
 | 
			
		||||
 *
 | 
			
		||||
 * <p>Activation of a stargate happens when a player right-clicks the sign of a stargate.
 | 
			
		||||
 * This event can be used to overwrite the selected destination, and all destinations the player can see.</p>
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class StargateActivateEvent extends StargatePlayerEvent {
 | 
			
		||||
 | 
			
		||||
    private static final HandlerList handlers = new HandlerList();
 | 
			
		||||
    private List<String> destinations;
 | 
			
		||||
    private String destination;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new stargate activate event
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal       <p>The activated portal</p>
 | 
			
		||||
     * @param player       <p>The player activating the portal</p>
 | 
			
		||||
     * @param destinations <p>The destinations available to the player using the portal</p>
 | 
			
		||||
     * @param destination  <p>The currently selected destination</p>
 | 
			
		||||
     */
 | 
			
		||||
    public StargateActivateEvent(Portal portal, Player player, List<String> destinations, String destination) {
 | 
			
		||||
        super(portal, player);
 | 
			
		||||
 | 
			
		||||
        this.destinations = destinations;
 | 
			
		||||
        this.destination = destination;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the destinations available for the portal
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The destinations available for the portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public List<String> getDestinations() {
 | 
			
		||||
        return destinations;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the destinations available to the player using the portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param destinations <p>The new list of available destinations</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setDestinations(List<String> destinations) {
 | 
			
		||||
        this.destinations = destinations;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the selected destination
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The selected destination</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getDestination() {
 | 
			
		||||
        return destination;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets (changes) the selected destination
 | 
			
		||||
     *
 | 
			
		||||
     * @param destination <p>The new selected destination</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setDestination(String destination) {
 | 
			
		||||
        this.destination = destination;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a handler-list containing all event handlers
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A handler-list with all event handlers</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static HandlerList getHandlerList() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public HandlerList getHandlers() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,64 @@
 | 
			
		||||
package net.knarcraft.stargate.event;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import org.bukkit.event.HandlerList;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This event should be called whenever a stargate is closed
 | 
			
		||||
 *
 | 
			
		||||
 * <p>This event can be used to overwrite whether the stargate should be forced to close, even if it's set as
 | 
			
		||||
 * always-on.</p>
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class StargateCloseEvent extends StargateEvent {
 | 
			
		||||
 | 
			
		||||
    private static final HandlerList handlers = new HandlerList();
 | 
			
		||||
    private boolean force;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new stargate closing event
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal <p>The portal to close</p>
 | 
			
		||||
     * @param force  <p>Whether to force the gate to close, even if set as always-on</p>
 | 
			
		||||
     */
 | 
			
		||||
    public StargateCloseEvent(Portal portal, boolean force) {
 | 
			
		||||
        super(portal);
 | 
			
		||||
 | 
			
		||||
        this.force = force;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether to force the stargate to close
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether to force the stargate to close</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean getForce() {
 | 
			
		||||
        return force;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets whether the stargate should be forced to close
 | 
			
		||||
     *
 | 
			
		||||
     * @param force <p>Whether the stargate should be forced to close</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setForce(boolean force) {
 | 
			
		||||
        this.force = force;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a handler-list containing all event handlers
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A handler-list with all event handlers</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static HandlerList getHandlerList() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public HandlerList getHandlers() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,120 @@
 | 
			
		||||
package net.knarcraft.stargate.event;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.event.HandlerList;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This event should be called whenever a stargate is created
 | 
			
		||||
 *
 | 
			
		||||
 * <p>This event can be used to deny or change the cost of a stargate creation.</p>
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class StargateCreateEvent extends StargatePlayerEvent {
 | 
			
		||||
 | 
			
		||||
    private static final HandlerList handlers = new HandlerList();
 | 
			
		||||
    private final String[] lines;
 | 
			
		||||
    private boolean deny;
 | 
			
		||||
    private String denyReason;
 | 
			
		||||
    private int cost;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new stargate creation event
 | 
			
		||||
     *
 | 
			
		||||
     * @param player     <p>Thg player creating the stargate</p>
 | 
			
		||||
     * @param portal     <p>The created portal</p>
 | 
			
		||||
     * @param lines      <p>The lines of the sign creating the star gate</p>
 | 
			
		||||
     * @param deny       <p>Whether to deny the creation of the new gate</p>
 | 
			
		||||
     * @param denyReason <p>The reason stargate creation was denied</p>
 | 
			
		||||
     * @param cost       <p>The cost of creating the new star gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public StargateCreateEvent(Player player, Portal portal, String[] lines, boolean deny, String denyReason, int cost) {
 | 
			
		||||
        super(portal, player);
 | 
			
		||||
        this.lines = lines;
 | 
			
		||||
        this.deny = deny;
 | 
			
		||||
        this.denyReason = denyReason;
 | 
			
		||||
        this.cost = cost;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a given line from the sign creating the star gate
 | 
			
		||||
     *
 | 
			
		||||
     * @param index <p>The line number to get</p>
 | 
			
		||||
     * @return <p>The text on the given line</p>
 | 
			
		||||
     * @throws IndexOutOfBoundsException <p>If given a line index less than zero or above three</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getLine(int index) throws IndexOutOfBoundsException {
 | 
			
		||||
        return lines[index];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether the stargate creation should be denied
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether the stargate creation should be denied</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean getDeny() {
 | 
			
		||||
        return deny;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets whether the stargate creation should be denied
 | 
			
		||||
     *
 | 
			
		||||
     * @param deny <p>Whether the stargate creation should be denied</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setDeny(boolean deny) {
 | 
			
		||||
        this.deny = deny;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the reason the stargate creation was denied
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The reason the stargate creation was denied</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getDenyReason() {
 | 
			
		||||
        return denyReason;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the reason the stargate creation was denied
 | 
			
		||||
     *
 | 
			
		||||
     * @param denyReason <p>The new reason why the stargate creation was denied</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setDenyReason(String denyReason) {
 | 
			
		||||
        this.denyReason = denyReason;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the cost of creating the stargate
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The cost of creating the stargate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public int getCost() {
 | 
			
		||||
        return cost;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the cost of creating the stargate
 | 
			
		||||
     *
 | 
			
		||||
     * @param cost <p>The new cost of creating the stargate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setCost(int cost) {
 | 
			
		||||
        this.cost = cost;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a handler-list containing all event handlers
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A handler-list with all event handlers</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static HandlerList getHandlerList() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public HandlerList getHandlers() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,42 @@
 | 
			
		||||
package net.knarcraft.stargate.event;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import org.bukkit.event.HandlerList;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This event should be called whenever a stargate is deactivated
 | 
			
		||||
 *
 | 
			
		||||
 * <p>A deactivation is usually caused by no activity for a set amount of time.
 | 
			
		||||
 * This event can only be used to listen for de-activation events.</p>
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class StargateDeactivateEvent extends StargateEvent {
 | 
			
		||||
 | 
			
		||||
    private static final HandlerList handlers = new HandlerList();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new stargate deactivation event
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal <p>The portal which was deactivated</p>
 | 
			
		||||
     */
 | 
			
		||||
    public StargateDeactivateEvent(Portal portal) {
 | 
			
		||||
        super(portal);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a handler-list containing all event handlers
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A handler-list with all event handlers</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static HandlerList getHandlerList() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public HandlerList getHandlers() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,106 @@
 | 
			
		||||
package net.knarcraft.stargate.event;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.event.HandlerList;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This event should be called whenever a stargate is destroyed
 | 
			
		||||
 *
 | 
			
		||||
 * <p>This event can be used to deny or change the cost of a stargate destruction.</p>
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class StargateDestroyEvent extends StargatePlayerEvent {
 | 
			
		||||
 | 
			
		||||
    private static final HandlerList handlers = new HandlerList();
 | 
			
		||||
    private boolean deny;
 | 
			
		||||
    private String denyReason;
 | 
			
		||||
    private int cost;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new Stargate Destroy Event
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal  <p>The destroyed portal</p>
 | 
			
		||||
     * @param player  <p>The player destroying the portal</p>
 | 
			
		||||
     * @param deny    <p>Whether the event should be denied (cancelled)</p>
 | 
			
		||||
     * @param denyMsg <p>The message to display if the event is denied</p>
 | 
			
		||||
     * @param cost    <p>The cost of destroying the portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public StargateDestroyEvent(Portal portal, Player player, boolean deny, String denyMsg, int cost) {
 | 
			
		||||
        super(portal, player);
 | 
			
		||||
        this.deny = deny;
 | 
			
		||||
        this.denyReason = denyMsg;
 | 
			
		||||
        this.cost = cost;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this event should be denied
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether this event should be denied</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean getDeny() {
 | 
			
		||||
        return deny;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets whether this event should be denied
 | 
			
		||||
     *
 | 
			
		||||
     * @param deny <p>Whether this event should be denied</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setDeny(boolean deny) {
 | 
			
		||||
        this.deny = deny;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the reason the event was denied
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The reason the event was denied</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getDenyReason() {
 | 
			
		||||
        return denyReason;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the reason the event was denied
 | 
			
		||||
     *
 | 
			
		||||
     * @param denyReason <p>The reason the event was denied</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setDenyReason(String denyReason) {
 | 
			
		||||
        this.denyReason = denyReason;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the cost of destroying the portal
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The cost of destroying the portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public int getCost() {
 | 
			
		||||
        return cost;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the cost of destroying the portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param cost <p>The cost of destroying the portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setCost(int cost) {
 | 
			
		||||
        this.cost = cost;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a handler-list containing all event handlers
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A handler-list with all event handlers</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static HandlerList getHandlerList() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public HandlerList getHandlers() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,90 @@
 | 
			
		||||
package net.knarcraft.stargate.event;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import org.bukkit.Location;
 | 
			
		||||
import org.bukkit.entity.Entity;
 | 
			
		||||
import org.bukkit.event.HandlerList;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This event should be called whenever a non-player teleports through a stargate
 | 
			
		||||
 *
 | 
			
		||||
 * <p>This event can be used to overwrite the location the entity is teleported to.</p>
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class StargateEntityPortalEvent extends StargateEvent implements StargateTeleportEvent {
 | 
			
		||||
 | 
			
		||||
    private static final HandlerList handlers = new HandlerList();
 | 
			
		||||
    final Entity travellingEntity;
 | 
			
		||||
    private final Portal destination;
 | 
			
		||||
    private Location exit;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new stargate portal event
 | 
			
		||||
     *
 | 
			
		||||
     * @param travellingEntity <p>The entity travelling through this portal</p>
 | 
			
		||||
     * @param portal           <p>The portal the entity entered from</p>
 | 
			
		||||
     * @param destination      <p>The destination the entity should exit from</p>
 | 
			
		||||
     * @param exit             <p>The exit location of the destination portal the entity will be teleported to</p>
 | 
			
		||||
     */
 | 
			
		||||
    public StargateEntityPortalEvent(Entity travellingEntity, Portal portal, Portal destination, Location exit) {
 | 
			
		||||
        super(portal);
 | 
			
		||||
 | 
			
		||||
        this.travellingEntity = travellingEntity;
 | 
			
		||||
        this.destination = destination;
 | 
			
		||||
        this.exit = exit;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the non-player entity teleporting
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The non-player teleporting</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Entity getEntity() {
 | 
			
		||||
        return travellingEntity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the destination portal
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The destination portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Portal getDestination() {
 | 
			
		||||
        return destination;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the location of the players exit point
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Location of the exit point</p>
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public Location getExit() {
 | 
			
		||||
        return exit;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the location of the entity's exit point
 | 
			
		||||
     *
 | 
			
		||||
     * @param location <p>The new location of the entity's exit point</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setExit(Location location) {
 | 
			
		||||
        this.exit = location;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a handler-list containing all event handlers
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A handler-list with all event handlers</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static HandlerList getHandlerList() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public HandlerList getHandlers() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,45 @@
 | 
			
		||||
package net.knarcraft.stargate.event;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import org.bukkit.event.Cancellable;
 | 
			
		||||
import org.bukkit.event.Event;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An abstract event describing any stargate event
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public abstract class StargateEvent extends Event implements Cancellable {
 | 
			
		||||
 | 
			
		||||
    private final Portal portal;
 | 
			
		||||
    private boolean cancelled;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new stargate event
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal <p>The portal involved in this stargate event</p>
 | 
			
		||||
     */
 | 
			
		||||
    StargateEvent(Portal portal) {
 | 
			
		||||
        this.portal = portal;
 | 
			
		||||
        this.cancelled = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the portal involved in this stargate event
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The portal involved in this stargate event</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Portal getPortal() {
 | 
			
		||||
        return portal;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean isCancelled() {
 | 
			
		||||
        return this.cancelled;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void setCancelled(boolean cancelled) {
 | 
			
		||||
        this.cancelled = cancelled;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,65 @@
 | 
			
		||||
package net.knarcraft.stargate.event;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.event.HandlerList;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This event should be called whenever a player opens a stargate
 | 
			
		||||
 *
 | 
			
		||||
 * <p>This event can be used to overwrite whether the stargate should be forced to open, even if it's already open.</p>
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings({"unused"})
 | 
			
		||||
public class StargateOpenEvent extends StargatePlayerEvent {
 | 
			
		||||
 | 
			
		||||
    private static final HandlerList handlers = new HandlerList();
 | 
			
		||||
    private boolean force;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new stargate open event
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player opening the stargate</p>
 | 
			
		||||
     * @param portal <p>The opened portal</p>
 | 
			
		||||
     * @param force  <p>Whether to force the portal open</p>
 | 
			
		||||
     */
 | 
			
		||||
    public StargateOpenEvent(Player player, Portal portal, boolean force) {
 | 
			
		||||
        super(portal, player);
 | 
			
		||||
 | 
			
		||||
        this.force = force;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether the portal should be forced open
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether the portal should be forced open</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean getForce() {
 | 
			
		||||
        return force;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets whether the portal should be forced open
 | 
			
		||||
     *
 | 
			
		||||
     * @param force <p>Whether the portal should be forced open</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setForce(boolean force) {
 | 
			
		||||
        this.force = force;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a handler-list containing all event handlers
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A handler-list with all event handlers</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static HandlerList getHandlerList() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public HandlerList getHandlers() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,33 @@
 | 
			
		||||
package net.knarcraft.stargate.event;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An abstract event describing any stargate event where a player is involved
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public abstract class StargatePlayerEvent extends StargateEvent {
 | 
			
		||||
 | 
			
		||||
    private final Player player;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new stargate player event
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal <p>The portal involved in this stargate event</p>
 | 
			
		||||
     */
 | 
			
		||||
    StargatePlayerEvent(Portal portal, Player player) {
 | 
			
		||||
        super(portal);
 | 
			
		||||
        this.player = player;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the player creating the star gate
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The player creating the star gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Player getPlayer() {
 | 
			
		||||
        return player;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,79 @@
 | 
			
		||||
package net.knarcraft.stargate.event;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import org.bukkit.Location;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.event.HandlerList;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This event should be called whenever a player teleports through a stargate
 | 
			
		||||
 *
 | 
			
		||||
 * <p>This event can be used to overwrite the location the player is teleported to.</p>
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class StargatePlayerPortalEvent extends StargatePlayerEvent implements StargateTeleportEvent {
 | 
			
		||||
 | 
			
		||||
    private static final HandlerList handlers = new HandlerList();
 | 
			
		||||
    private final Portal destination;
 | 
			
		||||
    private Location exit;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new stargate player portal event
 | 
			
		||||
     *
 | 
			
		||||
     * @param player      <p>The player teleporting</p>
 | 
			
		||||
     * @param portal      <p>The portal the player entered from</p>
 | 
			
		||||
     * @param destination <p>The destination the player should exit from</p>
 | 
			
		||||
     * @param exit        <p>The exit location of the destination portal the user will be teleported to</p>
 | 
			
		||||
     */
 | 
			
		||||
    public StargatePlayerPortalEvent(Player player, Portal portal, Portal destination, Location exit) {
 | 
			
		||||
        super(portal, player);
 | 
			
		||||
 | 
			
		||||
        this.destination = destination;
 | 
			
		||||
        this.exit = exit;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the destination portal
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The destination portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Portal getDestination() {
 | 
			
		||||
        return destination;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the location of the players exit point
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Location of the exit point</p>
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public Location getExit() {
 | 
			
		||||
        return exit;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the location of the player's exit point
 | 
			
		||||
     *
 | 
			
		||||
     * @param location <p>The new location of the player's exit point</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setExit(Location location) {
 | 
			
		||||
        this.exit = location;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a handler-list containing all event handlers
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A handler-list with all event handlers</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static HandlerList getHandlerList() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public HandlerList getHandlers() {
 | 
			
		||||
        return handlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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();
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								src/main/java/net/knarcraft/stargate/event/package-info.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/main/java/net/knarcraft/stargate/event/package-info.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Events for any plugins wanting to interact with the Stargate plugin
 | 
			
		||||
 *
 | 
			
		||||
 * <p>This package contains several events used for interactions with Stargate. All events can be cancelled. For
 | 
			
		||||
 * several of the events, it is possible to overrule permissions. A general overview of the events' usage:</p>
 | 
			
		||||
 *
 | 
			
		||||
 * <ul>
 | 
			
		||||
 *     <li>The StargateAccessEvent is called whenever a player clicks a stargate's sign, and when a player enters a
 | 
			
		||||
 *     Stargate. It can be used to override whether the access should be allowed or denied.</li>
 | 
			
		||||
 *     <li>The StargateActivateEvent is called whenever a player activates a stargate (uses the stargate's sign). It
 | 
			
		||||
 *     can be used to override which destinations are available to the player.</li>
 | 
			
		||||
 *     <li>The StargateCloseEvent is called whenever a stargate is closed. Forcing the stargate closed can be toggled.</li>
 | 
			
		||||
 *     <li>The StargateCreateEvent is called whenever a new stargate is created. Its deny value can be overridden, the
 | 
			
		||||
 *     cost can be changed</li>
 | 
			
		||||
 *     <li>The StargateDeactivateEvent is called whenever a stargate is deactivated.</li>
 | 
			
		||||
 *     <li>The StargateDestroyEvent is called whenever a stargate is destroyed. Its deny value can be overridden or the
 | 
			
		||||
 *     cost can be changed.</li>
 | 
			
		||||
 *     <li>The StargateEntityPortalEvent is called whenever an entity teleports through a stargate. The exit location
 | 
			
		||||
 *     can be changed.</li>
 | 
			
		||||
 *     <li>The StargateOpenEvent is called whenever a stargate is opened. Forcing the stargate open can be toggled.</li>
 | 
			
		||||
 *     <li>The StargatePlayerPortalEvent is called whenever a player teleports through a stargate. The exit location can
 | 
			
		||||
 *     be changed.</li>
 | 
			
		||||
 * </ul>
 | 
			
		||||
 */
 | 
			
		||||
package net.knarcraft.stargate.event;
 | 
			
		||||
@@ -0,0 +1,280 @@
 | 
			
		||||
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;
 | 
			
		||||
import net.knarcraft.stargate.portal.PortalHandler;
 | 
			
		||||
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;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.entity.Snowman;
 | 
			
		||||
import org.bukkit.event.EventHandler;
 | 
			
		||||
import org.bukkit.event.EventPriority;
 | 
			
		||||
import org.bukkit.event.Listener;
 | 
			
		||||
import org.bukkit.event.block.BlockBreakEvent;
 | 
			
		||||
import org.bukkit.event.block.BlockFromToEvent;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class is responsible for listening to relevant block events related to creating and breaking portals
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class BlockEventListener implements Listener {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Detects snowmen ruining portals
 | 
			
		||||
     *
 | 
			
		||||
     * <p>If entrance protection or portal verification is enabled, the snowman will be prevented from placing snow in
 | 
			
		||||
     * the portal entrance.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The triggered event</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onBlockFormedByEntity(EntityBlockFormEvent event) {
 | 
			
		||||
        if (event.isCancelled() || (!Stargate.getGateConfig().protectEntrance() &&
 | 
			
		||||
                !Stargate.getGateConfig().verifyPortals())) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        //We are only interested in snowman events
 | 
			
		||||
        if (!(event.getEntity() instanceof Snowman)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        //Cancel the event if a snowman is trying to place snow in the portal's entrance
 | 
			
		||||
        if (PortalHandler.getByEntrance(event.getBlock()) != null) {
 | 
			
		||||
            event.setCancelled(true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Detects sign changes to detect if the user is creating a new gate
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The triggered event</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onSignChange(SignChangeEvent event) {
 | 
			
		||||
        if (event.isCancelled()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        Player player = event.getPlayer();
 | 
			
		||||
        Block block = event.getBlock();
 | 
			
		||||
        //Ignore normal signs
 | 
			
		||||
        if (!(block.getBlockData() instanceof WallSign)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        final Portal portal = new PortalCreator(event, player).createPortal();
 | 
			
		||||
        //Not creating a gate, just placing a sign
 | 
			
		||||
        if (portal == null) {
 | 
			
		||||
            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
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The triggered event</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler(priority = EventPriority.HIGHEST)
 | 
			
		||||
    public void onBlockBreak(BlockBreakEvent event) {
 | 
			
		||||
        if (event.isCancelled()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        Block block = event.getBlock();
 | 
			
		||||
        Player player = event.getPlayer();
 | 
			
		||||
 | 
			
		||||
        //Decide if a portal is broken
 | 
			
		||||
        Portal portal = PortalHandler.getByBlock(block);
 | 
			
		||||
        if (portal == null && Stargate.getGateConfig().protectEntrance()) {
 | 
			
		||||
            portal = PortalHandler.getByEntrance(block);
 | 
			
		||||
        }
 | 
			
		||||
        if (portal == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        boolean deny = false;
 | 
			
		||||
        String denyMessage = "";
 | 
			
		||||
 | 
			
		||||
        //Decide if the user can destroy the portal
 | 
			
		||||
        if (!PermissionHelper.canDestroyPortal(player, portal)) {
 | 
			
		||||
            denyMessage = Stargate.getString("denyMsg");
 | 
			
		||||
            deny = true;
 | 
			
		||||
            Stargate.logInfo(String.format("%s tried to destroy gate", player.getName()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int cost = Stargate.getEconomyConfig().getDestroyCost(player, portal.getGate());
 | 
			
		||||
 | 
			
		||||
        //Create and call a StarGateDestroyEvent
 | 
			
		||||
        StargateDestroyEvent destroyEvent = new StargateDestroyEvent(portal, player, deny, denyMessage, cost);
 | 
			
		||||
        Stargate.getInstance().getServer().getPluginManager().callEvent(destroyEvent);
 | 
			
		||||
        if (destroyEvent.isCancelled()) {
 | 
			
		||||
            event.setCancelled(true);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Destroy denied
 | 
			
		||||
        if (destroyEvent.getDeny()) {
 | 
			
		||||
            if (!destroyEvent.getDenyReason().trim().isEmpty()) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, destroyEvent.getDenyReason());
 | 
			
		||||
            }
 | 
			
		||||
            event.setCancelled(true);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Take care of payment transactions
 | 
			
		||||
        if (!handleEconomyPayment(destroyEvent, player, portal, event)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        PortalRegistry.unregisterPortal(portal, true);
 | 
			
		||||
        Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("destroyMsg"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles economy payment for breaking the portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param destroyEvent <p>The destroy event</p>
 | 
			
		||||
     * @param player       <p>The player which triggered the event</p>
 | 
			
		||||
     * @param portal       <p>The broken portal</p>
 | 
			
		||||
     * @param event        <p>The break event</p>
 | 
			
		||||
     * @return <p>True if the payment was successful. False if the event was cancelled</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean handleEconomyPayment(StargateDestroyEvent destroyEvent, Player player, Portal portal,
 | 
			
		||||
                                         BlockBreakEvent event) {
 | 
			
		||||
        int cost = destroyEvent.getCost();
 | 
			
		||||
        if (cost != 0) {
 | 
			
		||||
            String portalName = portal.getName();
 | 
			
		||||
            //Cannot pay
 | 
			
		||||
            if (!EconomyHelper.chargePlayerIfNecessary(player, cost)) {
 | 
			
		||||
                Stargate.debug("onBlockBreak", "Insufficient Funds");
 | 
			
		||||
                EconomyHelper.sendInsufficientFundsMessage(portalName, player, cost);
 | 
			
		||||
                event.setCancelled(true);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            //Tell the player they've paid or deceived money
 | 
			
		||||
            if (cost > 0) {
 | 
			
		||||
                EconomyHelper.sendDeductMessage(portalName, player, cost);
 | 
			
		||||
            } else {
 | 
			
		||||
                EconomyHelper.sendRefundMessage(portalName, player, cost);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Prevents any block physics events which may damage parts of the portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The event to check and possibly cancel</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onBlockPhysics(BlockPhysicsEvent event) {
 | 
			
		||||
        Block block = event.getBlock();
 | 
			
		||||
        Portal portal = null;
 | 
			
		||||
 | 
			
		||||
        if (block.getType() == Material.NETHER_PORTAL) {
 | 
			
		||||
            portal = PortalHandler.getByEntrance(block);
 | 
			
		||||
        } else if (MaterialHelper.isButtonCompatible(block.getType())) {
 | 
			
		||||
            portal = PortalHandler.getByControl(block);
 | 
			
		||||
        }
 | 
			
		||||
        if (portal != null) {
 | 
			
		||||
            event.setCancelled(true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Cancels any block move events which may cause a block to enter the opening of a portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The event to check and possibly cancel</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onBlockFromTo(BlockFromToEvent event) {
 | 
			
		||||
        Portal portal = PortalHandler.getByEntrance(event.getBlock());
 | 
			
		||||
 | 
			
		||||
        if (portal != null) {
 | 
			
		||||
            event.setCancelled((event.getBlock().getY() == event.getToBlock().getY()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Cancels any piston extend events if the target block is part of a portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The event to check and possibly cancel</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onPistonExtend(BlockPistonExtendEvent event) {
 | 
			
		||||
        cancelPistonEvent(event, event.getBlocks());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Cancels any piston retract events if the target block is part of a portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The event to check and possibly cancel</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onPistonRetract(BlockPistonRetractEvent event) {
 | 
			
		||||
        if (!event.isSticky()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        cancelPistonEvent(event, event.getBlocks());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Cancels a piston event if it would destroy a portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param event  <p>The event to cancel</p>
 | 
			
		||||
     * @param blocks <p>The blocks included in the event</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void cancelPistonEvent(BlockPistonEvent event, List<Block> blocks) {
 | 
			
		||||
        for (Block block : blocks) {
 | 
			
		||||
            Portal portal = PortalHandler.getByBlock(block);
 | 
			
		||||
            if (portal != null) {
 | 
			
		||||
                event.setCancelled(true);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,42 @@
 | 
			
		||||
package net.knarcraft.stargate.listener;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.utility.BungeeHelper;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.plugin.messaging.PluginMessageListener;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This listener teleports a user if a valid message is received from BungeeCord
 | 
			
		||||
 *
 | 
			
		||||
 * <p>Specifically, if a string starts with SGBungee encoded to be readable by readUTF followed by
 | 
			
		||||
 * [PlayerUUID]delimiter[DestinationPortal] is received on the BungeeCord channel, this listener will teleport the
 | 
			
		||||
 * player to the destination portal.</p>
 | 
			
		||||
 */
 | 
			
		||||
public class BungeeCordListener implements PluginMessageListener {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Receives plugin messages
 | 
			
		||||
     *
 | 
			
		||||
     * @param channel <p>The channel the message was received on</p>
 | 
			
		||||
     * @param unused  <p>Unused.</p>
 | 
			
		||||
     * @param message <p>The message received from the plugin</p>
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onPluginMessageReceived(@NotNull String channel, @NotNull Player unused, byte[] message) {
 | 
			
		||||
        //Ignore plugin messages if some other plugin message is received
 | 
			
		||||
        if (!channel.equals(BungeeHelper.getBungeeChannel())) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Try to read the plugin message
 | 
			
		||||
        String receivedMessage = BungeeHelper.readPluginMessage(message);
 | 
			
		||||
        if (receivedMessage == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Use the message to initiate teleportation
 | 
			
		||||
        BungeeHelper.handleTeleportMessage(receivedMessage);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,67 @@
 | 
			
		||||
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.PortalRegistry;
 | 
			
		||||
import net.knarcraft.stargate.utility.EntityHelper;
 | 
			
		||||
import org.bukkit.block.Block;
 | 
			
		||||
import org.bukkit.entity.Entity;
 | 
			
		||||
import org.bukkit.event.EventHandler;
 | 
			
		||||
import org.bukkit.event.EventPriority;
 | 
			
		||||
import org.bukkit.event.Listener;
 | 
			
		||||
import org.bukkit.event.entity.EntityExplodeEvent;
 | 
			
		||||
import org.bukkit.event.entity.EntityPortalEvent;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This listener listens for any relevant events on portal entities
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class EntityEventListener implements Listener {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This event handler prevents sending entities to the normal nether instead of the stargate target
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The event to check and possibly cancel</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler(priority = EventPriority.LOWEST)
 | 
			
		||||
    public void onPortalEvent(EntityPortalEvent event) {
 | 
			
		||||
        if (event.isCancelled()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Entity entity = event.getEntity();
 | 
			
		||||
        //Cancel normal portal event is near a stargate
 | 
			
		||||
        if (PortalHandler.getByAdjacentEntrance(event.getFrom(), EntityHelper.getEntityMaxSizeInt(entity)) != null) {
 | 
			
		||||
            event.setCancelled(true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This method catches any explosion events
 | 
			
		||||
     *
 | 
			
		||||
     * <p>If destroyed by explosions is enabled, any portals destroyed by the explosion will be unregistered. If not,
 | 
			
		||||
     * the explosion will be cancelled.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The triggered explosion event</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onEntityExplode(EntityExplodeEvent event) {
 | 
			
		||||
        if (event.isCancelled()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        for (Block block : event.blockList()) {
 | 
			
		||||
            Portal portal = PortalHandler.getByBlock(block);
 | 
			
		||||
            if (portal == null) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            if (Stargate.getGateConfig().destroyedByExplosion()) {
 | 
			
		||||
                PortalRegistry.unregisterPortal(portal, true);
 | 
			
		||||
            } else {
 | 
			
		||||
                event.setCancelled(true);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,401 @@
 | 
			
		||||
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.Portal;
 | 
			
		||||
import net.knarcraft.stargate.portal.PortalActivator;
 | 
			
		||||
import net.knarcraft.stargate.portal.PortalHandler;
 | 
			
		||||
import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter;
 | 
			
		||||
import net.knarcraft.stargate.portal.teleporter.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;
 | 
			
		||||
import org.bukkit.entity.Entity;
 | 
			
		||||
import org.bukkit.entity.LivingEntity;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.entity.Vehicle;
 | 
			
		||||
import org.bukkit.event.Event;
 | 
			
		||||
import org.bukkit.event.EventHandler;
 | 
			
		||||
import org.bukkit.event.Listener;
 | 
			
		||||
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
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class PlayerEventListener implements Listener {
 | 
			
		||||
 | 
			
		||||
    private static final Map<Player, Long> previousEventTimes = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This event handler handles detection of any player teleporting through a bungee gate
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The event to check for a teleporting player</p>
 | 
			
		||||
     */
 | 
			
		||||
    @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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Check if the player is waiting to be teleported to a stargate
 | 
			
		||||
        String destination = BungeeHelper.removeFromQueue(player.getUniqueId());
 | 
			
		||||
        if (destination == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Portal portal = PortalHandler.getBungeePortal(destination);
 | 
			
		||||
        if (portal == null) {
 | 
			
		||||
            Stargate.debug("PlayerJoin", "Error fetching destination portal: " + destination);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        //Teleport the player to the stargate
 | 
			
		||||
        new PlayerTeleporter(portal, player).teleport(portal, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This event handler detects if a player moves into a portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The player move event which was triggered</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onPlayerMove(PlayerMoveEvent event) {
 | 
			
		||||
        if (event.isCancelled() || event.getTo() == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        BlockLocation fromLocation = new BlockLocation(event.getFrom().getBlock());
 | 
			
		||||
        BlockLocation toLocation = new BlockLocation(event.getTo().getBlock());
 | 
			
		||||
        Player player = event.getPlayer();
 | 
			
		||||
 | 
			
		||||
        //Check whether the event needs to be considered
 | 
			
		||||
        if (!isRelevantMoveEvent(event, player, fromLocation, toLocation)) {
 | 
			
		||||
            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 || (playerVehicle instanceof LivingEntity &&
 | 
			
		||||
                Stargate.getGateConfig().handleVehicles())) {
 | 
			
		||||
            teleportPlayer(playerVehicle, player, entrancePortal, destination, event);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleports a player, also teleports the player's vehicle if it's a living entity
 | 
			
		||||
     *
 | 
			
		||||
     * @param playerVehicle  <p>The vehicle the player is currently sitting in</p>
 | 
			
		||||
     * @param player         <p>The player which moved</p>
 | 
			
		||||
     * @param entrancePortal <p>The entrance the player entered</p>
 | 
			
		||||
     * @param destination    <p>The destination of the entrance portal</p>
 | 
			
		||||
     * @param event          <p>The move event causing the teleportation to trigger</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void teleportPlayer(Entity playerVehicle, Player player, Portal entrancePortal, Portal destination,
 | 
			
		||||
                                PlayerMoveEvent event) {
 | 
			
		||||
        if (playerVehicle instanceof LivingEntity) {
 | 
			
		||||
            //Make sure any horses are properly tamed
 | 
			
		||||
            if (playerVehicle instanceof AbstractHorse horse && !horse.isTamed()) {
 | 
			
		||||
                horse.setTamed(true);
 | 
			
		||||
                horse.setOwner(player);
 | 
			
		||||
            }
 | 
			
		||||
            //Teleport the player's vehicle
 | 
			
		||||
            player.setVelocity(new Vector());
 | 
			
		||||
            new VehicleTeleporter(destination, (Vehicle) playerVehicle).teleportEntity(entrancePortal);
 | 
			
		||||
        } else {
 | 
			
		||||
            //Just teleport the player like normal
 | 
			
		||||
            new PlayerTeleporter(destination, player).teleportPlayer(entrancePortal, event);
 | 
			
		||||
        }
 | 
			
		||||
        if (!entrancePortal.getOptions().isSilent()) {
 | 
			
		||||
            Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
 | 
			
		||||
        }
 | 
			
		||||
        entrancePortal.getPortalOpener().closePortal(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a player move event is relevant for this plugin
 | 
			
		||||
     *
 | 
			
		||||
     * @param event        <p>The player move event to check</p>
 | 
			
		||||
     * @param player       <p>The player which moved</p>
 | 
			
		||||
     * @param fromLocation <p>The location the player is moving from</p>
 | 
			
		||||
     * @param toLocation   <p>The location the player is moving to</p>
 | 
			
		||||
     * @return <p>True if the event is relevant</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isRelevantMoveEvent(PlayerMoveEvent event, Player player, BlockLocation fromLocation,
 | 
			
		||||
                                        BlockLocation toLocation) {
 | 
			
		||||
        //Check to see if the player moved to another block
 | 
			
		||||
        if (fromLocation.equals(toLocation)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Check if the player moved from a portal
 | 
			
		||||
        Portal entrancePortal = PortalHandler.getByEntrance(toLocation);
 | 
			
		||||
        if (entrancePortal == null) {
 | 
			
		||||
            //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);
 | 
			
		||||
 | 
			
		||||
        //Catch always open portals without a valid destination to prevent the user for being teleported and denied
 | 
			
		||||
        if (!entrancePortal.getOptions().isBungee() && destination == null) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Decide if the anything stops the player from teleport
 | 
			
		||||
        if (PermissionHelper.playerCannotTeleport(entrancePortal, destination, player, event)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Decide if the user should be teleported to another bungee server
 | 
			
		||||
        if (entrancePortal.getOptions().isBungee()) {
 | 
			
		||||
            if (BungeeHelper.bungeeTeleport(player, entrancePortal, event) && !entrancePortal.getOptions().isSilent()) {
 | 
			
		||||
                Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Make sure to check if the player has any leashed creatures, even though leashed teleportation is disabled
 | 
			
		||||
        return TeleportHelper.noLeashedCreaturesPreventTeleportation(player);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This event handler detects if a player clicks a button or a sign
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The player interact event which was triggered</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onPlayerInteract(PlayerInteractEvent event) {
 | 
			
		||||
        Player player = event.getPlayer();
 | 
			
		||||
        Block block = event.getClickedBlock();
 | 
			
		||||
 | 
			
		||||
        if (block == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (event.getAction() == Action.RIGHT_CLICK_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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This method handles left- or right-clicking of a sign
 | 
			
		||||
     *
 | 
			
		||||
     * @param event     <p>The event causing the click</p>
 | 
			
		||||
     * @param player    <p>The player clicking the sign</p>
 | 
			
		||||
     * @param block     <p>The block that was clicked</p>
 | 
			
		||||
     * @param leftClick <p>Whether the player performed a left click as opposed to a right click</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void handleSignClick(PlayerInteractEvent event, Player player, Block block, boolean leftClick) {
 | 
			
		||||
        Portal portal = PortalHandler.getByBlock(block);
 | 
			
		||||
        if (portal == null) {
 | 
			
		||||
            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
 | 
			
		||||
            if (player.getGameMode().equals(GameMode.CREATIVE)) {
 | 
			
		||||
                event.setCancelled(true);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            //Prevent usage of item in the player's hand (placing block and such)
 | 
			
		||||
            event.setUseItemInHand(Event.Result.DENY);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Check if the user can use the portal
 | 
			
		||||
        if (cannotAccessPortal(player, portal)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Cycle portal destination
 | 
			
		||||
        if ((!portal.isOpen()) && (!portal.getOptions().isFixed())) {
 | 
			
		||||
            PortalActivator destinations = portal.getPortalActivator();
 | 
			
		||||
            if (leftClick) {
 | 
			
		||||
                destinations.cycleDestination(player, -1);
 | 
			
		||||
            } else {
 | 
			
		||||
                destinations.cycleDestination(player);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if a player should be denied from accessing (using) a portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player trying to access the portal</p>
 | 
			
		||||
     * @param portal <p>The portal the player is trying to use</p>
 | 
			
		||||
     * @return <p>True if the player should be denied</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean cannotAccessPortal(Player player, Portal portal) {
 | 
			
		||||
        boolean deny = PermissionHelper.cannotAccessNetwork(player, portal.getCleanNetwork());
 | 
			
		||||
 | 
			
		||||
        if (PermissionHelper.portalAccessDenied(player, portal, deny)) {
 | 
			
		||||
            if (!portal.getOptions().isSilent()) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This method handles right-clicking of a sign or button belonging to a stargate
 | 
			
		||||
     *
 | 
			
		||||
     * @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, EquipmentSlot hand) {
 | 
			
		||||
        if (block.getBlockData() instanceof WallSign) {
 | 
			
		||||
            handleSignClick(event, player, block, false);
 | 
			
		||||
            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;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Prevent the held item from being placed
 | 
			
		||||
            event.setUseItemInHand(Event.Result.DENY);
 | 
			
		||||
            event.setUseInteractedBlock(Event.Result.DENY);
 | 
			
		||||
 | 
			
		||||
            //Check if the user can use the portal
 | 
			
		||||
            if (cannotAccessPortal(player, portal)) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            PermissionHelper.openPortal(player, portal);
 | 
			
		||||
            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);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Displays information about a clicked portal
 | 
			
		||||
     *
 | 
			
		||||
     * <p>This will only display portal info if the portal has no sign and is not silent.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param block  <p>The clicked block</p>
 | 
			
		||||
     * @param player <p>The player that clicked the block</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void displayPortalInfo(Block block, Player player) {
 | 
			
		||||
        Portal portal = PortalHandler.getByBlock(block);
 | 
			
		||||
        if (portal == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Display portal information as a portal without a sign does not display any
 | 
			
		||||
        if (portal.getOptions().hasNoSign() && (!portal.getOptions().isSilent() || player.isSneaking())) {
 | 
			
		||||
            MessageSender sender = Stargate.getMessageSender();
 | 
			
		||||
            sender.sendSuccessMessage(player, ChatColor.GOLD + Stargate.getString("portalInfoTitle"));
 | 
			
		||||
            sender.sendSuccessMessage(player, Stargate.replaceVars(Stargate.getString("portalInfoName"),
 | 
			
		||||
                    "%name%", portal.getName()));
 | 
			
		||||
            sender.sendSuccessMessage(player, Stargate.replaceVars(Stargate.getString("portalInfoDestination"),
 | 
			
		||||
                    "%destination%", portal.getDestinationName()));
 | 
			
		||||
            if (portal.getOptions().isBungee()) {
 | 
			
		||||
                sender.sendSuccessMessage(player, Stargate.replaceVars(Stargate.getString("portalInfoServer"),
 | 
			
		||||
                        "%server%", portal.getNetwork()));
 | 
			
		||||
            } else {
 | 
			
		||||
                sender.sendSuccessMessage(player, Stargate.replaceVars(Stargate.getString("portalInfoNetwork"),
 | 
			
		||||
                        "%network%", portal.getNetwork()));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This function decides if a right click of a block is caused by a Spigot bug
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The Spigot bug currently makes every right click of some blocks trigger twice, causing the portal to close
 | 
			
		||||
     * immediately, or causing portal information printing twice. This fix should detect the bug without breaking
 | 
			
		||||
     * clicking once the bug is fixed.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param 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(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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,53 @@
 | 
			
		||||
package net.knarcraft.stargate.listener;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import org.bukkit.event.EventHandler;
 | 
			
		||||
import org.bukkit.event.Listener;
 | 
			
		||||
import org.bukkit.event.server.PluginDisableEvent;
 | 
			
		||||
import org.bukkit.event.server.PluginEnableEvent;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This listener listens for any plugins being enabled or disabled to catch the loading of vault
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class PluginEventListener implements Listener {
 | 
			
		||||
 | 
			
		||||
    private final Stargate stargate;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new plugin event listener
 | 
			
		||||
     *
 | 
			
		||||
     * @param stargate <p>A reference to the stargate plugin to </p>
 | 
			
		||||
     */
 | 
			
		||||
    public PluginEventListener(Stargate stargate) {
 | 
			
		||||
        this.stargate = stargate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This event listens for and announces that the vault plugin was detected and enabled
 | 
			
		||||
     *
 | 
			
		||||
     * <p>Each time this event is called, the economy handler will try to enable vault</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param ignored <p>The actual event called. This is currently not used</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onPluginEnable(PluginEnableEvent ignored) {
 | 
			
		||||
        if (Stargate.getEconomyConfig().setupEconomy(stargate.getServer().getPluginManager())) {
 | 
			
		||||
            String vaultVersion = Stargate.getEconomyConfig().getVault().getDescription().getVersion();
 | 
			
		||||
            Stargate.logInfo(Stargate.replaceVars(Stargate.getString("vaultLoaded"), "%version%", vaultVersion));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This event listens for the vault plugin being disabled and notifies the console
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The event caused by disabling a plugin</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onPluginDisable(PluginDisableEvent event) {
 | 
			
		||||
        if (event.getPlugin().equals(Stargate.getEconomyConfig().getVault())) {
 | 
			
		||||
            Stargate.logInfo("Vault plugin lost.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,122 @@
 | 
			
		||||
package net.knarcraft.stargate.listener;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.container.FromTheEndTeleportation;
 | 
			
		||||
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;
 | 
			
		||||
import org.bukkit.entity.Entity;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.event.EventHandler;
 | 
			
		||||
import org.bukkit.event.Listener;
 | 
			
		||||
import org.bukkit.event.entity.EntityPortalEnterEvent;
 | 
			
		||||
import org.bukkit.event.player.PlayerRespawnEvent;
 | 
			
		||||
import org.bukkit.event.world.PortalCreateEvent;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Listens for and cancels relevant portal events
 | 
			
		||||
 */
 | 
			
		||||
public class PortalEventListener implements Listener {
 | 
			
		||||
 | 
			
		||||
    private static final List<FromTheEndTeleportation> playersFromTheEnd = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Listens for and aborts vanilla portal creation caused by stargate creation
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The triggered event</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onPortalCreation(PortalCreateEvent event) {
 | 
			
		||||
        if (event.isCancelled()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        //Unnecessary nether portal creation is only triggered by nether pairing
 | 
			
		||||
        if (event.getReason() == PortalCreateEvent.CreateReason.NETHER_PAIR) {
 | 
			
		||||
            //If an entity is standing in a Stargate entrance, it can be assumed that the creation is a mistake
 | 
			
		||||
            Entity entity = event.getEntity();
 | 
			
		||||
            if (entity != null && PortalHandler.getByAdjacentEntrance(entity.getLocation()) != null) {
 | 
			
		||||
                Stargate.debug("PortalEventListener::onPortalCreation",
 | 
			
		||||
                        "Cancelled nether portal create event");
 | 
			
		||||
                event.setCancelled(true);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Listen for entities entering an artificial end portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The triggered event</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onEntityPortalEnter(EntityPortalEnterEvent event) {
 | 
			
		||||
        Location location = event.getLocation();
 | 
			
		||||
        World world = location.getWorld();
 | 
			
		||||
        Entity entity = event.getEntity();
 | 
			
		||||
        //Hijack normal portal teleportation if teleporting from a stargate
 | 
			
		||||
        if (entity instanceof Player player && location.getBlock().getType() == Material.END_PORTAL && world != null &&
 | 
			
		||||
                world.getEnvironment() == World.Environment.THE_END) {
 | 
			
		||||
            Portal portal = PortalHandler.getByAdjacentEntrance(location);
 | 
			
		||||
            if (portal == null) {
 | 
			
		||||
                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) ||
 | 
			
		||||
                    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");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Listen for the respawn event to catch players teleporting from the end in an artificial end portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The triggered event</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onRespawn(PlayerRespawnEvent event) {
 | 
			
		||||
        Player respawningPlayer = event.getPlayer();
 | 
			
		||||
        int playerIndex = playersFromTheEnd.indexOf(new FromTheEndTeleportation(respawningPlayer, null));
 | 
			
		||||
        if (playerIndex == -1) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        FromTheEndTeleportation teleportation = playersFromTheEnd.get(playerIndex);
 | 
			
		||||
        playersFromTheEnd.remove(playerIndex);
 | 
			
		||||
 | 
			
		||||
        Portal exitPortal = teleportation.getExit();
 | 
			
		||||
        //Overwrite respawn location to respawn in front of the portal
 | 
			
		||||
        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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
package net.knarcraft.stargate.listener;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.portal.PortalHandler;
 | 
			
		||||
import org.bukkit.event.EventHandler;
 | 
			
		||||
import org.bukkit.event.Listener;
 | 
			
		||||
import org.bukkit.event.player.PlayerTeleportEvent;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This listener listens to teleportation-related events
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class TeleportEventListener implements Listener {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This event handler handles some special teleportation events
 | 
			
		||||
     *
 | 
			
		||||
     * <p>This event cancels nether portal, end gateway and end portal teleportation if the user teleported from a
 | 
			
		||||
     * stargate entrance. This prevents the user from just teleporting to the nether or the end with portals using
 | 
			
		||||
     * the special teleportation blocks.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The event to check and possibly cancel</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onPlayerTeleport(PlayerTeleportEvent event) {
 | 
			
		||||
        PlayerTeleportEvent.TeleportCause cause = event.getCause();
 | 
			
		||||
 | 
			
		||||
        //Block normal portal teleportation if teleporting from a stargate
 | 
			
		||||
        if (!event.isCancelled() && (cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL ||
 | 
			
		||||
                cause == PlayerTeleportEvent.TeleportCause.END_GATEWAY ||
 | 
			
		||||
                cause == PlayerTeleportEvent.TeleportCause.END_PORTAL)
 | 
			
		||||
                && PortalHandler.getByAdjacentEntrance(event.getFrom()) != null) {
 | 
			
		||||
            event.setCancelled(true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,147 @@
 | 
			
		||||
package net.knarcraft.stargate.listener;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import net.knarcraft.stargate.portal.PortalHandler;
 | 
			
		||||
import net.knarcraft.stargate.portal.teleporter.VehicleTeleporter;
 | 
			
		||||
import net.knarcraft.stargate.utility.EconomyHelper;
 | 
			
		||||
import net.knarcraft.stargate.utility.EntityHelper;
 | 
			
		||||
import net.knarcraft.stargate.utility.TeleportHelper;
 | 
			
		||||
import org.bukkit.entity.Entity;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.entity.Vehicle;
 | 
			
		||||
import org.bukkit.event.EventHandler;
 | 
			
		||||
import org.bukkit.event.Listener;
 | 
			
		||||
import org.bukkit.event.vehicle.VehicleMoveEvent;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This listener listens for the vehicle move event to teleport vehicles through portals
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class VehicleEventListener implements Listener {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check for a vehicle moving through a portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The triggered move event</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onVehicleMove(VehicleMoveEvent event) {
 | 
			
		||||
        if (!Stargate.getGateConfig().handleVehicles()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        List<Entity> passengers = event.getVehicle().getPassengers();
 | 
			
		||||
        Vehicle vehicle = event.getVehicle();
 | 
			
		||||
 | 
			
		||||
        Portal entrancePortal;
 | 
			
		||||
        int entitySize = EntityHelper.getEntityMaxSizeInt(vehicle);
 | 
			
		||||
        if (EntityHelper.getEntityMaxSize(vehicle) > 1) {
 | 
			
		||||
            entrancePortal = PortalHandler.getByAdjacentEntrance(event.getTo(), entitySize - 1);
 | 
			
		||||
        } else {
 | 
			
		||||
            entrancePortal = PortalHandler.getByEntrance(event.getTo());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Return if the portal cannot be teleported through
 | 
			
		||||
        if (entrancePortal == null || !entrancePortal.isOpen() || entrancePortal.getOptions().isBungee()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        teleportVehicle(passengers, entrancePortal, vehicle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleports a vehicle through a stargate
 | 
			
		||||
     *
 | 
			
		||||
     * @param passengers     <p>The passengers inside the vehicle</p>
 | 
			
		||||
     * @param entrancePortal <p>The portal the vehicle is entering</p>
 | 
			
		||||
     * @param vehicle        <p>The vehicle passing through</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void teleportVehicle(List<Entity> passengers, Portal entrancePortal, Vehicle vehicle) {
 | 
			
		||||
        String route = "VehicleEventListener::teleportVehicle";
 | 
			
		||||
 | 
			
		||||
        if (!passengers.isEmpty() && TeleportHelper.containsPlayer(passengers)) {
 | 
			
		||||
            Stargate.debug(route, "Found passenger vehicle");
 | 
			
		||||
            teleportPlayerAndVehicle(entrancePortal, vehicle);
 | 
			
		||||
        } else {
 | 
			
		||||
            Stargate.debug(route, "Found vehicle without players");
 | 
			
		||||
            Portal destinationPortal = entrancePortal.getPortalActivator().getDestination();
 | 
			
		||||
            if (destinationPortal == null) {
 | 
			
		||||
                Stargate.debug(route, "Unable to find portal destination");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            Stargate.debug("vehicleTeleport", destinationPortal.getWorld() + " " +
 | 
			
		||||
                    destinationPortal.getSignLocation());
 | 
			
		||||
            new VehicleTeleporter(destinationPortal, vehicle).teleportEntity(entrancePortal);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Teleports a player and the vehicle the player sits in
 | 
			
		||||
     *
 | 
			
		||||
     * @param entrancePortal <p>The portal the minecart entered</p>
 | 
			
		||||
     * @param vehicle        <p>The vehicle to teleport</p>
 | 
			
		||||
     */
 | 
			
		||||
    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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Take payment from all players
 | 
			
		||||
        for (Player player : players) {
 | 
			
		||||
            //To prevent the case where the first passenger pays and then the second passenger is denied, this has to be
 | 
			
		||||
            // run after it has been confirmed that all passengers are able to pay
 | 
			
		||||
            int cost = EconomyHelper.getUseCost(player, entrancePortal, destinationPortal);
 | 
			
		||||
            if (cost > 0) {
 | 
			
		||||
                if (EconomyHelper.cannotPayTeleportFee(entrancePortal, player, cost)) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Teleport the vehicle and inform the user if the vehicle was teleported
 | 
			
		||||
        boolean teleported = new VehicleTeleporter(destinationPortal, vehicle).teleportEntity(entrancePortal);
 | 
			
		||||
        if (teleported) {
 | 
			
		||||
            if (!entrancePortal.getOptions().isSilent()) {
 | 
			
		||||
                for (Player player : players) {
 | 
			
		||||
                    Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            entrancePortal.getPortalOpener().closePortal(false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,50 @@
 | 
			
		||||
package net.knarcraft.stargate.listener;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.config.StargateConfig;
 | 
			
		||||
import net.knarcraft.stargate.portal.PortalRegistry;
 | 
			
		||||
import net.knarcraft.stargate.utility.PortalFileHelper;
 | 
			
		||||
import org.bukkit.World;
 | 
			
		||||
import org.bukkit.event.EventHandler;
 | 
			
		||||
import org.bukkit.event.Listener;
 | 
			
		||||
import org.bukkit.event.world.WorldLoadEvent;
 | 
			
		||||
import org.bukkit.event.world.WorldUnloadEvent;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This listener listens for the loading and unloading of worlds to load and unload stargates
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public class WorldEventListener implements Listener {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This listener listens for the loading of a world and loads all gates from the world if not already loaded
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The triggered world load event</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onWorldLoad(WorldLoadEvent event) {
 | 
			
		||||
        StargateConfig config = Stargate.getStargateConfig();
 | 
			
		||||
        if (!config.getManagedWorlds().contains(event.getWorld().getName()) &&
 | 
			
		||||
                PortalFileHelper.loadAllPortals(event.getWorld())) {
 | 
			
		||||
            config.addManagedWorld(event.getWorld().getName());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This listener listens for the unloading of a world
 | 
			
		||||
     *
 | 
			
		||||
     * @param event <p>The triggered world unload event</p>
 | 
			
		||||
     */
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onWorldUnload(WorldUnloadEvent event) {
 | 
			
		||||
        Stargate.debug("onWorldUnload", "Reloading all Stargates");
 | 
			
		||||
        World world = event.getWorld();
 | 
			
		||||
        String worldName = world.getName();
 | 
			
		||||
        StargateConfig config = Stargate.getStargateConfig();
 | 
			
		||||
        if (config.getManagedWorlds().contains(worldName)) {
 | 
			
		||||
            config.removeManagedWorld(worldName);
 | 
			
		||||
            PortalRegistry.clearPortals(world);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										4
									
								
								src/main/java/net/knarcraft/stargate/package-info.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/main/java/net/knarcraft/stargate/package-info.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
/**
 | 
			
		||||
 * The root package of the Stargate plugin. Contains the main Stargate.java file
 | 
			
		||||
 */
 | 
			
		||||
package net.knarcraft.stargate;
 | 
			
		||||
							
								
								
									
										353
									
								
								src/main/java/net/knarcraft/stargate/portal/Portal.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										353
									
								
								src/main/java/net/knarcraft/stargate/portal/Portal.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,353 @@
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class represents a portal in space which points to one or several portals
 | 
			
		||||
 */
 | 
			
		||||
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;
 | 
			
		||||
    private final PortalLocation location;
 | 
			
		||||
    private final PortalSignDrawer signDrawer;
 | 
			
		||||
    private final PortalStructure structure;
 | 
			
		||||
    private final PortalActivator portalActivator;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param portalLocation <p>Object containing locations of all relevant blocks</p>
 | 
			
		||||
     * @param button         <p>The location of the portal's open button</p>
 | 
			
		||||
     * @param destination    <p>The destination defined on the sign's destination line. "" for non-fixed gates</p>
 | 
			
		||||
     * @param name           <p>The name of the portal defined on the sign's first line</p>
 | 
			
		||||
     * @param network        <p>The network the portal belongs to, defined on the sign's third</p>
 | 
			
		||||
     * @param gate           <p>The gate type to use for this portal</p>
 | 
			
		||||
     * @param portalOwner    <p>The portal's owner</p>
 | 
			
		||||
     * @param options        <p>A map containing all possible portal options, with true for the ones enabled</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Portal(PortalLocation portalLocation, BlockLocation button, String destination, String name, String network,
 | 
			
		||||
                  Gate gate, PortalOwner portalOwner, Map<PortalOption, Boolean> options) {
 | 
			
		||||
        this.location = portalLocation;
 | 
			
		||||
        this.network = network;
 | 
			
		||||
        this.name = name;
 | 
			
		||||
        this.portalOwner = portalOwner;
 | 
			
		||||
        this.options = new PortalOptions(options, destination.length() > 0);
 | 
			
		||||
        this.signDrawer = new PortalSignDrawer(this);
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the location data for this portal
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>This portal's location data</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalLocation getLocation() {
 | 
			
		||||
        return this.location;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the structure of this portal
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The structure contains information about the portal's gate, button and real locations of frames and
 | 
			
		||||
     * entrances. The structure is also responsible for verifying built StarGates to make sure they match the gate.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>This portal's structure</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalStructure getStructure() {
 | 
			
		||||
        return this.structure;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets this portal's activator
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The activator is responsible for activating/de-activating the portal and contains information about
 | 
			
		||||
     * available destinations and which player activated the portal.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>This portal's activator</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalActivator getPortalActivator() {
 | 
			
		||||
        return this.portalActivator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Re-draws the sign on this portal
 | 
			
		||||
     */
 | 
			
		||||
    public void drawSign() {
 | 
			
		||||
        this.signDrawer.drawSign();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the portal options for this portal
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>This portal's portal options</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalOptions getOptions() {
 | 
			
		||||
        return this.options;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this portal is currently open
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether this portal is open</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isOpen() {
 | 
			
		||||
        return portalOpener.isOpen();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the player currently using this portal
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The player currently using this portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Player getActivePlayer() {
 | 
			
		||||
        return portalActivator.getActivePlayer();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the network this portal belongs to
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The network this portal belongs to</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getNetwork() {
 | 
			
		||||
        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)
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The time is given in the equivalent of a Unix timestamp. It's used to decide when a portal times out and
 | 
			
		||||
     * automatically closes/deactivates.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The time this portal was triggered (activated/opened)</p>
 | 
			
		||||
     */
 | 
			
		||||
    public long getTriggeredTime() {
 | 
			
		||||
        return portalOpener.getTriggeredTime();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the name of this portal
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The name of this portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getName() {
 | 
			
		||||
        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
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The portal opener is responsible for opening and closing this portal.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>This portal's portal opener</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalOpener getPortalOpener() {
 | 
			
		||||
        return portalOpener;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the name of this portal's destination portal
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The name of this portal's destination portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getDestinationName() {
 | 
			
		||||
        return portalOpener.getPortalActivator().getDestinationName();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the gate type used by this portal
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The gate type used by this portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Gate getGate() {
 | 
			
		||||
        return structure.getGate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets this portal's owner
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The owner is the player which created the portal.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>This portal's owner</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalOwner getOwner() {
 | 
			
		||||
        return portalOwner;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a given player is the owner of this portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player to check</p>
 | 
			
		||||
     * @return <p>True if the player is the owner of this portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isOwner(Player player) {
 | 
			
		||||
        if (this.portalOwner.getUUID() != null) {
 | 
			
		||||
            return player.getUniqueId().compareTo(this.portalOwner.getUUID()) == 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            return player.getName().equalsIgnoreCase(this.portalOwner.getName());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the world this portal belongs to
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The world this portal belongs to</p>
 | 
			
		||||
     */
 | 
			
		||||
    public World getWorld() {
 | 
			
		||||
        return location.getWorld();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the location of this portal's sign
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The location of this portal's sign</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockLocation getSignLocation() {
 | 
			
		||||
        return this.location.getSignLocation();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the rotation (yaw) of this portal
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The yaw is used to calculate all kinds of directions. See DirectionHelper to see how the yaw is used to
 | 
			
		||||
     * calculate to/from other direction types.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The rotation (yaw) of this portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public float getYaw() {
 | 
			
		||||
        return this.location.getYaw();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the location of the top-left block of the portal
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The location of the top-left portal block</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockLocation getTopLeft() {
 | 
			
		||||
        return this.location.getTopLeft();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the block at the given location relative to this portal's top-left block
 | 
			
		||||
     *
 | 
			
		||||
     * @param vector <p>The relative block vector explaining the position of the block</p>
 | 
			
		||||
     * @return <p>The block at the given relative position</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockLocation getBlockAt(RelativeBlockVector vector) {
 | 
			
		||||
        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
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return String.format("Portal [id=%s, network=%s name=%s, type=%s]", getSignLocation(), network, name,
 | 
			
		||||
                structure.getGate().getFilename());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int hashCode() {
 | 
			
		||||
        final int prime = 31;
 | 
			
		||||
        int result = 1;
 | 
			
		||||
        result = prime * result + ((cleanName == null) ? 0 : cleanName.hashCode());
 | 
			
		||||
        result = prime * result + ((cleanNetwork == null) ? 0 : cleanNetwork.hashCode());
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object object) {
 | 
			
		||||
        if (this == object) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        if (object == null || getClass() != object.getClass()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        Portal other = (Portal) object;
 | 
			
		||||
        if (cleanName == null) {
 | 
			
		||||
            if (other.cleanName != null) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (!cleanName.equalsIgnoreCase(other.cleanName)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        //If none of the portals have a name, check if the network is the same
 | 
			
		||||
        if (cleanNetwork == null) {
 | 
			
		||||
            return other.cleanNetwork == null;
 | 
			
		||||
        } else {
 | 
			
		||||
            return cleanNetwork.equalsIgnoreCase(other.cleanNetwork);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										288
									
								
								src/main/java/net/knarcraft/stargate/portal/PortalActivator.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										288
									
								
								src/main/java/net/knarcraft/stargate/portal/PortalActivator.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,288 @@
 | 
			
		||||
package net.knarcraft.stargate.portal;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.event.StargateActivateEvent;
 | 
			
		||||
import net.knarcraft.stargate.event.StargateDeactivateEvent;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Comparator;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Random;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The portal activator activates/de-activates portals and keeps track of a portal's destinations
 | 
			
		||||
 *
 | 
			
		||||
 * <p>The portal activator is responsible for activating/de-activating the portal and contains information about
 | 
			
		||||
 * available destinations and which player activated the portal.</p>
 | 
			
		||||
 */
 | 
			
		||||
public class PortalActivator {
 | 
			
		||||
 | 
			
		||||
    private final Portal portal;
 | 
			
		||||
    private final PortalOpener opener;
 | 
			
		||||
 | 
			
		||||
    private List<String> destinations = new ArrayList<>();
 | 
			
		||||
    private String destination;
 | 
			
		||||
    private String lastDestination = "";
 | 
			
		||||
    private Player activePlayer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new portal destinations object
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal       <p>The portal which this this object stores destinations for</p>
 | 
			
		||||
     * @param portalOpener <p>The portal opener to trigger when the activation causes the portal to open</p>
 | 
			
		||||
     * @param destination  <p>The fixed destination specified on the portal's sign</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalActivator(Portal portal, PortalOpener portalOpener, String destination) {
 | 
			
		||||
        this.portal = portal;
 | 
			
		||||
        this.opener = portalOpener;
 | 
			
		||||
        this.destination = destination;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the player which this activator's portal is currently activated for
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The player this activator's portal is currently activated for</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Player getActivePlayer() {
 | 
			
		||||
        return activePlayer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the available portal destinations
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The available portal destinations</p>
 | 
			
		||||
     */
 | 
			
		||||
    public List<String> getDestinations() {
 | 
			
		||||
        return new ArrayList<>(this.destinations);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the portal destination given a player
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>Used for random gates to determine which destinations are available</p>
 | 
			
		||||
     * @return <p>The destination portal the player should teleport to</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Portal getDestination(Player player) {
 | 
			
		||||
        String portalNetwork = portal.getCleanNetwork();
 | 
			
		||||
        if (portal.getOptions().isRandom()) {
 | 
			
		||||
            //Find possible destinations
 | 
			
		||||
            List<String> destinations = PortalHandler.getDestinations(portal, player, portalNetwork);
 | 
			
		||||
            if (destinations.size() == 0) {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
            //Get one random destination
 | 
			
		||||
            String destination = destinations.get((new Random()).nextInt(destinations.size()));
 | 
			
		||||
            return PortalHandler.getByName(Portal.cleanString(destination), portalNetwork);
 | 
			
		||||
        } else {
 | 
			
		||||
            //Just return the normal fixed destination
 | 
			
		||||
            return PortalHandler.getByName(Portal.cleanString(destination), portalNetwork);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the portal's destination
 | 
			
		||||
     *
 | 
			
		||||
     * <p>For random portals, getDestination must be given a player to decide which destinations are valid. Without a
 | 
			
		||||
     * player, or with a null player, behavior is only defined for a non-random gate.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The portal destination</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Portal getDestination() {
 | 
			
		||||
        return getDestination(null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the destination of this portal activator's portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param destination <p>The new destination of this portal activator's portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setDestination(Portal destination) {
 | 
			
		||||
        setDestination(destination.getName());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the destination of this portal activator's portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param destination <p>The new destination of this portal activator's portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setDestination(String destination) {
 | 
			
		||||
        this.destination = destination;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the name of the selected destination
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The name of the selected destination</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getDestinationName() {
 | 
			
		||||
        return destination;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Activates this activator's portal for the given player
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player to activate the portal for</p>
 | 
			
		||||
     * @return <p>True if the portal was activated</p>
 | 
			
		||||
     */
 | 
			
		||||
    boolean activate(Player player) {
 | 
			
		||||
        //Clear previous destination data
 | 
			
		||||
        this.destination = "";
 | 
			
		||||
        this.destinations.clear();
 | 
			
		||||
 | 
			
		||||
        //Adds the active gate to the active queue to allow it to be remotely deactivated
 | 
			
		||||
        Stargate.getStargateConfig().getActivePortalsQueue().add(portal);
 | 
			
		||||
 | 
			
		||||
        //Set the given player as the active player
 | 
			
		||||
        activePlayer = player;
 | 
			
		||||
 | 
			
		||||
        String network = portal.getCleanNetwork();
 | 
			
		||||
        destinations = PortalHandler.getDestinations(portal, player, network);
 | 
			
		||||
 | 
			
		||||
        //Sort destinations if enabled
 | 
			
		||||
        if (Stargate.getGateConfig().sortNetworkDestinations()) {
 | 
			
		||||
            destinations.sort(Comparator.comparing(Portal::cleanString));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Select last used destination if remember destination is enabled
 | 
			
		||||
        if (Stargate.getGateConfig().rememberDestination() && !lastDestination.isEmpty() &&
 | 
			
		||||
                destinations.contains(lastDestination)) {
 | 
			
		||||
            destination = lastDestination;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Trigger an activation event to allow the cancellation to be cancelled
 | 
			
		||||
        return triggerStargateActivationEvent(player);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Triggers a stargate activation event to allow other plugins to cancel the activation
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The event may also end up changing destinations.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player trying to activate this activator's portal</p>
 | 
			
		||||
     * @return <p>True if the portal was activated. False otherwise</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean triggerStargateActivationEvent(Player player) {
 | 
			
		||||
        StargateActivateEvent event = new StargateActivateEvent(portal, player, destinations, destination);
 | 
			
		||||
        Stargate.getInstance().getServer().getPluginManager().callEvent(event);
 | 
			
		||||
        if (event.isCancelled()) {
 | 
			
		||||
            Stargate.getStargateConfig().getActivePortalsQueue().remove(portal);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Update destinations in case they changed, and update the sign
 | 
			
		||||
        destination = event.getDestination();
 | 
			
		||||
        destinations = event.getDestinations();
 | 
			
		||||
        portal.drawSign();
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Deactivates this portal
 | 
			
		||||
     */
 | 
			
		||||
    public void deactivate() {
 | 
			
		||||
        //Trigger a stargate deactivate event to allow other plugins to cancel the event
 | 
			
		||||
        StargateDeactivateEvent event = new StargateDeactivateEvent(portal);
 | 
			
		||||
        Stargate.getInstance().getServer().getPluginManager().callEvent(event);
 | 
			
		||||
        if (event.isCancelled()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Un-mark the portal as activated
 | 
			
		||||
        Stargate.getStargateConfig().getActivePortalsQueue().remove(portal);
 | 
			
		||||
 | 
			
		||||
        //Fixed portals are active by definition, but should never be de-activated
 | 
			
		||||
        if (portal.getOptions().isFixed()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Clear destinations and the active player before re-drawing the sign to show that it's deactivated
 | 
			
		||||
        destinations.clear();
 | 
			
		||||
        destination = "";
 | 
			
		||||
        activePlayer = null;
 | 
			
		||||
        portal.drawSign();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this portal activator's portal is active
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether this portal activator's portal is active</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isActive() {
 | 
			
		||||
        return portal.getOptions().isFixed() || (destinations.size() > 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Cycles destination for a non-fixed gate by one forwards step
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player to cycle the gate for</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void cycleDestination(Player player) {
 | 
			
		||||
        cycleDestination(player, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Cycles destination for a non-fixed gate
 | 
			
		||||
     *
 | 
			
		||||
     * @param player    <p>The player cycling destinations</p>
 | 
			
		||||
     * @param direction <p>The direction of the cycle (+1 for next, -1 for previous)</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void cycleDestination(Player player, int direction) {
 | 
			
		||||
        //Only allow going exactly one step in either direction
 | 
			
		||||
        if (direction != 1 && direction != -1) {
 | 
			
		||||
            throw new IllegalArgumentException("The destination direction must be 1 or -1.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        boolean activate = false;
 | 
			
		||||
        if (!isActive() || getActivePlayer() != player) {
 | 
			
		||||
            //If not active or not active for the given player, and the activation is denied, just abort
 | 
			
		||||
            if (!activate(player)) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            activate = true;
 | 
			
		||||
 | 
			
		||||
            Stargate.debug("cycleDestination", "Network 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) {
 | 
			
		||||
            if (!portal.getOptions().isSilent()) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("destEmpty"));
 | 
			
		||||
            }
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Cycle if destination remembering is disabled, if the portal was already active, or it has no last destination
 | 
			
		||||
        if (!Stargate.getGateConfig().rememberDestination() || !activate || lastDestination.isEmpty()) {
 | 
			
		||||
            cycleDestination(direction);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Update the activated time to allow it to be deactivated after a timeout, and re-draw the sign to show the
 | 
			
		||||
        // selected destination
 | 
			
		||||
        opener.setTriggeredTime(System.currentTimeMillis() / 1000);
 | 
			
		||||
        portal.drawSign();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Performs the actual destination cycling with no input checks
 | 
			
		||||
     *
 | 
			
		||||
     * @param direction <p>The direction of the cycle (+1 for next, -1 for previous)</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void cycleDestination(int direction) {
 | 
			
		||||
        int index = destinations.indexOf(destination);
 | 
			
		||||
        index += direction;
 | 
			
		||||
 | 
			
		||||
        //Wrap around if the last destination has been reached
 | 
			
		||||
        if (index >= destinations.size()) {
 | 
			
		||||
            index = 0;
 | 
			
		||||
        } else if (index < 0) {
 | 
			
		||||
            index = destinations.size() - 1;
 | 
			
		||||
        }
 | 
			
		||||
        //Store selected destination
 | 
			
		||||
        destination = destinations.get(index);
 | 
			
		||||
        lastDestination = destination;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										327
									
								
								src/main/java/net/knarcraft/stargate/portal/PortalCreator.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										327
									
								
								src/main/java/net/knarcraft/stargate/portal/PortalCreator.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,327 @@
 | 
			
		||||
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.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.block.Block;
 | 
			
		||||
import org.bukkit.block.BlockFace;
 | 
			
		||||
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
 | 
			
		||||
 */
 | 
			
		||||
public class PortalCreator {
 | 
			
		||||
 | 
			
		||||
    private Portal portal;
 | 
			
		||||
    private final SignChangeEvent event;
 | 
			
		||||
    private final Player player;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new portal creator
 | 
			
		||||
     *
 | 
			
		||||
     * @param event  <p>The sign change event which initialized the creation</p>
 | 
			
		||||
     * @param player <p>The player creating the portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalCreator(SignChangeEvent event, Player player) {
 | 
			
		||||
        this.event = event;
 | 
			
		||||
        this.player = player;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new portal
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The created portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Portal createPortal() {
 | 
			
		||||
        BlockLocation signLocation = new BlockLocation(event.getBlock());
 | 
			
		||||
        Block signControlBlock = signLocation.getParent();
 | 
			
		||||
 | 
			
		||||
        //Return early if the sign is not placed on a block, or the block is not a control block
 | 
			
		||||
        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(signControlBlock) != null) {
 | 
			
		||||
            Stargate.debug("createPortal", "idParent belongs to existing stargate");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Get necessary information from the gate's sign
 | 
			
		||||
        String portalName = PortalHandler.filterName(event.getLine(0));
 | 
			
		||||
        String destinationName = PortalHandler.filterName(event.getLine(1));
 | 
			
		||||
        String network = PortalHandler.filterName(event.getLine(2));
 | 
			
		||||
        String options = PortalHandler.filterName(event.getLine(3)).toLowerCase();
 | 
			
		||||
 | 
			
		||||
        //Get portal options available to the player creating the portal
 | 
			
		||||
        Map<PortalOption, Boolean> portalOptions = PortalHandler.getPortalOptions(player, destinationName, options);
 | 
			
		||||
 | 
			
		||||
        //Get the yaw
 | 
			
		||||
        float yaw = DirectionHelper.getYawFromLocationDifference(signControlBlock.getLocation(),
 | 
			
		||||
                signLocation.getLocation());
 | 
			
		||||
 | 
			
		||||
        //Get the direction the button should be facing
 | 
			
		||||
        BlockFace buttonFacing = DirectionHelper.getBlockFaceFromYaw(yaw);
 | 
			
		||||
 | 
			
		||||
        PortalLocation portalLocation = new PortalLocation();
 | 
			
		||||
        portalLocation.setButtonFacing(buttonFacing).setYaw(yaw).setSignLocation(signLocation);
 | 
			
		||||
 | 
			
		||||
        Stargate.debug("createPortal", "Finished getting all portal info");
 | 
			
		||||
 | 
			
		||||
        //Try and find a gate matching the new portal
 | 
			
		||||
        Gate gate = PortalHandler.findMatchingGate(portalLocation, player.getWorld());
 | 
			
		||||
        if ((gate == null) || (portalLocation.getButtonVector() == null)) {
 | 
			
		||||
            Stargate.debug("createPortal", "Could not find matching gate layout");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //If the portal is a bungee portal and invalid, abort here
 | 
			
		||||
        if (!PortalHandler.isValidBungeePortal(portalOptions, player, destinationName, network)) {
 | 
			
		||||
            Stargate.debug("createPortal", "Portal is an invalid bungee portal");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Debug
 | 
			
		||||
        StringBuilder builder = new StringBuilder();
 | 
			
		||||
        for (PortalOption option : portalOptions.keySet()) {
 | 
			
		||||
            builder.append(option.getCharacterRepresentation()).append(" = ").append(portalOptions.get(option)).append(" ");
 | 
			
		||||
        }
 | 
			
		||||
        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() >
 | 
			
		||||
                getMaxNameNetworkLength())) {
 | 
			
		||||
            network = Stargate.getDefaultNetwork();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        boolean deny = false;
 | 
			
		||||
        String denyMessage = "";
 | 
			
		||||
 | 
			
		||||
        //Check if the player can create portals on this network. If not, create a personal portal
 | 
			
		||||
        if (!portalOptions.get(PortalOption.BUNGEE) && !PermissionHelper.canCreateNetworkGate(player, network)) {
 | 
			
		||||
            Stargate.debug("createPortal", "Player doesn't have create permissions on network. Trying personal");
 | 
			
		||||
            if (PermissionHelper.canCreatePersonalPortal(player)) {
 | 
			
		||||
                network = player.getName();
 | 
			
		||||
                if (network.length() > getMaxNameNetworkLength()) {
 | 
			
		||||
                    network = network.substring(0, getMaxNameNetworkLength());
 | 
			
		||||
                }
 | 
			
		||||
                Stargate.debug("createPortal", "Creating personal portal");
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createPersonal"));
 | 
			
		||||
            } else {
 | 
			
		||||
                Stargate.debug("createPortal", "Player does not have access to network");
 | 
			
		||||
                deny = true;
 | 
			
		||||
                denyMessage = Stargate.getString("createNetDeny");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Check if the player can create this gate layout
 | 
			
		||||
        String gateName = gate.getFilename();
 | 
			
		||||
        gateName = gateName.substring(0, gateName.indexOf('.'));
 | 
			
		||||
        if (!deny && !PermissionHelper.canCreatePortal(player, gateName)) {
 | 
			
		||||
            Stargate.debug("createPortal", "Player does not have access to gate layout");
 | 
			
		||||
            deny = true;
 | 
			
		||||
            denyMessage = Stargate.getString("createGateDeny");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Check if the user can create portals to this world.
 | 
			
		||||
        if (!portalOptions.get(PortalOption.BUNGEE) && !deny && destinationName.length() > 0) {
 | 
			
		||||
            Portal portal = PortalHandler.getByName(destinationName, network);
 | 
			
		||||
            if (portal != null) {
 | 
			
		||||
                String world = portal.getWorld().getName();
 | 
			
		||||
                if (PermissionHelper.cannotAccessWorld(player, world)) {
 | 
			
		||||
                    Stargate.debug("canCreateNetworkGate", "Player does not have access to destination world");
 | 
			
		||||
                    deny = true;
 | 
			
		||||
                    denyMessage = Stargate.getString("createWorldDeny");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Check if a conflict exists
 | 
			
		||||
        if (conflictsWithExistingPortal(gate, portalLocation.getTopLeft(), yaw, player)) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        PortalOwner owner = new PortalOwner(player);
 | 
			
		||||
        this.portal = new Portal(portalLocation, null, destinationName, portalName, network, gate, owner,
 | 
			
		||||
                portalOptions);
 | 
			
		||||
        return validatePortal(denyMessage, event.getLines(), deny);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Validates the newly created portal assigned to this portal validator
 | 
			
		||||
     *
 | 
			
		||||
     * @param denyMessage <p>The deny message to displayed if the creation has already been denied</p>
 | 
			
		||||
     * @param lines       <p>The lines on the sign causing the portal to be created</p>
 | 
			
		||||
     * @param deny        <p>Whether the portal creation has already been denied</p>
 | 
			
		||||
     * @return <p>The portal or null if its creation was denied</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Portal validatePortal(String denyMessage, String[] lines, boolean deny) {
 | 
			
		||||
        PortalLocation portalLocation = portal.getLocation();
 | 
			
		||||
        Gate gate = portal.getStructure().getGate();
 | 
			
		||||
        PortalOptions portalOptions = portal.getOptions();
 | 
			
		||||
        String portalName = portal.getName();
 | 
			
		||||
        String destinationName = portal.getDestinationName();
 | 
			
		||||
 | 
			
		||||
        int createCost = Stargate.getEconomyConfig().getCreateCost(player, gate);
 | 
			
		||||
 | 
			
		||||
        //Call StargateCreateEvent to let other plugins cancel or overwrite denial
 | 
			
		||||
        StargateCreateEvent stargateCreateEvent = new StargateCreateEvent(player, portal, lines, deny,
 | 
			
		||||
                denyMessage, createCost);
 | 
			
		||||
        Stargate.getInstance().getServer().getPluginManager().callEvent(stargateCreateEvent);
 | 
			
		||||
        if (stargateCreateEvent.isCancelled()) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Tell the user why it was denied from creating the portal
 | 
			
		||||
        if (stargateCreateEvent.getDeny()) {
 | 
			
		||||
            if (!stargateCreateEvent.getDenyReason().trim().isEmpty()) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, stargateCreateEvent.getDenyReason());
 | 
			
		||||
            }
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        createCost = stargateCreateEvent.getCost();
 | 
			
		||||
 | 
			
		||||
        //Check if the new portal is valid
 | 
			
		||||
        if (!checkIfNewPortalIsValid(createCost, portalName)) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Add button if the portal is not always on
 | 
			
		||||
        if (!portalOptions.isAlwaysOn()) {
 | 
			
		||||
            PortalFileHelper.generatePortalButton(portal, portalLocation.getButtonFacing());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Register the new portal
 | 
			
		||||
        PortalHandler.registerPortal(portal);
 | 
			
		||||
        updateNewPortalOpenState(destinationName);
 | 
			
		||||
 | 
			
		||||
        //Update portals pointing at this one if it's not a bungee portal
 | 
			
		||||
        if (!portal.getOptions().isBungee()) {
 | 
			
		||||
            PortalHandler.updatePortalsPointingAtNewPortal(portal);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        PortalFileHelper.saveAllPortals(portal.getWorld());
 | 
			
		||||
 | 
			
		||||
        return portal;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the newly created, but unregistered portal is valid
 | 
			
		||||
     *
 | 
			
		||||
     * @param cost       <p>The cost of creating the portal</p>
 | 
			
		||||
     * @param portalName <p>The name of the newly created portal</p>
 | 
			
		||||
     * @return <p>True if the portal is completely valid</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean checkIfNewPortalIsValid(int cost, String portalName) {
 | 
			
		||||
        //Check if the portal name can fit on the sign with padding (>name<)
 | 
			
		||||
        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.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.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.getCleanNetwork());
 | 
			
		||||
            int maxGates = Stargate.getGateConfig().maxGatesEachNetwork();
 | 
			
		||||
            if (maxGates > 0 && networkList != null && networkList.size() >= maxGates) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createFull"));
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (cost > 0) {
 | 
			
		||||
            //Deduct the required fee from the player
 | 
			
		||||
            if (!EconomyHelper.chargePlayerIfNecessary(player, cost)) {
 | 
			
		||||
                EconomyHelper.sendInsufficientFundsMessage(portalName, player, cost);
 | 
			
		||||
                Stargate.debug("createPortal", "Insufficient Funds");
 | 
			
		||||
                return false;
 | 
			
		||||
            } else {
 | 
			
		||||
                EconomyHelper.sendDeductMessage(portalName, player, cost);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the open state of the newly created portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param destinationName <p>The name of the destination portal. Only used if set as always on</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void updateNewPortalOpenState(String destinationName) {
 | 
			
		||||
        portal.drawSign();
 | 
			
		||||
        if (portal.getOptions().isRandom() || portal.getOptions().isBungee()) {
 | 
			
		||||
            //Open the implicitly always on portal
 | 
			
		||||
            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.getCleanNetwork());
 | 
			
		||||
            if (destinationPortal != null) {
 | 
			
		||||
                portal.getPortalOpener().openPortal(true);
 | 
			
		||||
                destinationPortal.drawSign();
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            //Update the block type for the portal's opening to the closed block as the closed block can be anything,
 | 
			
		||||
            // not just air or water
 | 
			
		||||
            for (BlockLocation entrance : portal.getStructure().getEntrances()) {
 | 
			
		||||
                entrance.setType(portal.getGate().getPortalClosedBlock());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the new portal conflicts with an existing portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param gate    <p>The gate type of the new portal</p>
 | 
			
		||||
     * @param topLeft <p>The top-left block of the new portal</p>
 | 
			
		||||
     * @param yaw     <p>The yaw when looking directly outwards from the portal</p>
 | 
			
		||||
     * @param player  <p>The player creating the new portal</p>
 | 
			
		||||
     * @return <p>True if a conflict was found. False otherwise</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static boolean conflictsWithExistingPortal(Gate gate, BlockLocation topLeft, double yaw, Player player) {
 | 
			
		||||
        for (RelativeBlockVector borderVector : gate.getLayout().getBorder()) {
 | 
			
		||||
            BlockLocation borderBlockLocation = topLeft.getRelativeLocation(borderVector, yaw);
 | 
			
		||||
            if (PortalHandler.getByBlock(borderBlockLocation.getBlock()) != null) {
 | 
			
		||||
                Stargate.debug("createPortal", "Gate conflicts with existing gate");
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createConflict"));
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										452
									
								
								src/main/java/net/knarcraft/stargate/portal/PortalHandler.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										452
									
								
								src/main/java/net/knarcraft/stargate/portal/PortalHandler.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,452 @@
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Keeps track of all loaded portals, and handles portal creation
 | 
			
		||||
 */
 | 
			
		||||
public class PortalHandler {
 | 
			
		||||
 | 
			
		||||
    private PortalHandler() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a copy of all portal networks
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A copy of all portal networks</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Map<String, List<String>> getAllPortalNetworks() {
 | 
			
		||||
        return PortalRegistry.getAllPortalNetworks();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a copy of all bungee portals
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A copy of all bungee portals</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Map<String, Portal> getBungeePortals() {
 | 
			
		||||
        return PortalRegistry.getBungeePortals();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets names of all portals within a network
 | 
			
		||||
     *
 | 
			
		||||
     * @param network <p>The network to get portals from</p>
 | 
			
		||||
     * @return <p>A list of portal names</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static List<String> getNetwork(String network) {
 | 
			
		||||
        return PortalRegistry.getNetwork(network);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets all destinations in the network viewable by the given player
 | 
			
		||||
     *
 | 
			
		||||
     * @param entrancePortal <p>The portal the user is entering from</p>
 | 
			
		||||
     * @param player         <p>The player who wants to see destinations</p>
 | 
			
		||||
     * @param network        <p>The network to get destinations from</p>
 | 
			
		||||
     * @return <p>All destinations the player can go to</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static List<String> getDestinations(Portal entrancePortal, Player player, String network) {
 | 
			
		||||
        List<String> destinations = new ArrayList<>();
 | 
			
		||||
        for (String destination : PortalRegistry.getAllPortalNetworks().get(network)) {
 | 
			
		||||
            Portal portal = getByName(destination, network);
 | 
			
		||||
            if (portal == null) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            //Check if destination is a random portal
 | 
			
		||||
            if (portal.getOptions().isRandom()) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            //Check if destination is always open (Don't show if so)
 | 
			
		||||
            if (portal.getOptions().isAlwaysOn() && !portal.getOptions().isShown()) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            //Check if destination is this portal
 | 
			
		||||
            if (destination.equals(entrancePortal.getCleanName())) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            //Check if destination is a fixed portal not pointing to this portal
 | 
			
		||||
            if (portal.getOptions().isFixed() &&
 | 
			
		||||
                    !Portal.cleanString(portal.getDestinationName()).equals(entrancePortal.getCleanName())) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            //Allow random use by non-players (Minecarts)
 | 
			
		||||
            if (player == null) {
 | 
			
		||||
                destinations.add(portal.getName());
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            //Check if this player can access the destination world
 | 
			
		||||
            if (PermissionHelper.cannotAccessWorld(player, portal.getWorld().getName())) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            //The portal is visible to the player
 | 
			
		||||
            if (PermissionHelper.canSeePortal(player, portal)) {
 | 
			
		||||
                destinations.add(portal.getName());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return destinations;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Registers a portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal <p>The portal to register</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void registerPortal(Portal portal) {
 | 
			
		||||
        PortalRegistry.registerPortal(portal);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if the new portal is a valid bungee portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param portalOptions   <p>The enabled portal options</p>
 | 
			
		||||
     * @param player          <p>The player trying to create the new portal</p>
 | 
			
		||||
     * @param destinationName <p>The name of the portal's destination</p>
 | 
			
		||||
     * @param network         <p>The name of the portal's network</p>
 | 
			
		||||
     * @return <p>False if the portal is an invalid bungee portal. True otherwise</p>
 | 
			
		||||
     */
 | 
			
		||||
    static boolean isValidBungeePortal(Map<PortalOption, Boolean> portalOptions, Player player,
 | 
			
		||||
                                       String destinationName, String network) {
 | 
			
		||||
        if (portalOptions.get(PortalOption.BUNGEE)) {
 | 
			
		||||
            if (!PermissionHelper.hasPermission(player, "stargate.admin.bungee")) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("bungeeDeny"));
 | 
			
		||||
                return false;
 | 
			
		||||
            } else if (!Stargate.getGateConfig().enableBungee()) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("bungeeDisabled"));
 | 
			
		||||
                return false;
 | 
			
		||||
            } else if (destinationName.isEmpty() || network.isEmpty()) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("bungeeEmpty"));
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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 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, World world) {
 | 
			
		||||
        Block signParent = portalLocation.getSignLocation().getParent();
 | 
			
		||||
        BlockLocation parent = new BlockLocation(world, signParent.getX(), signParent.getY(),
 | 
			
		||||
                signParent.getZ());
 | 
			
		||||
 | 
			
		||||
        //Get all gates with the used type of control blocks
 | 
			
		||||
        Gate[] possibleGates = GateHandler.getGatesByControlBlock(signParent);
 | 
			
		||||
        double yaw = portalLocation.getYaw();
 | 
			
		||||
        Gate gate = null;
 | 
			
		||||
 | 
			
		||||
        for (Gate possibleGate : possibleGates) {
 | 
			
		||||
            //Get gate controls
 | 
			
		||||
            RelativeBlockVector[] vectors = possibleGate.getLayout().getControls();
 | 
			
		||||
 | 
			
		||||
            portalLocation.setButtonVector(null);
 | 
			
		||||
            for (RelativeBlockVector controlVector : vectors) {
 | 
			
		||||
                //Assuming the top-left location is pointing to the gate's top-left location, check if it's a match
 | 
			
		||||
                BlockLocation possibleTopLocation = parent.getRelativeLocation(controlVector.invert(), yaw);
 | 
			
		||||
                if (possibleGate.matches(possibleTopLocation, portalLocation.getYaw(), true)) {
 | 
			
		||||
                    gate = possibleGate;
 | 
			
		||||
                    portalLocation.setTopLeft(possibleTopLocation);
 | 
			
		||||
                } else {
 | 
			
		||||
                    portalLocation.setButtonVector(controlVector);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return gate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the sign and open state of portals pointing at the newly created portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal <p>The newly created portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    static void updatePortalsPointingAtNewPortal(Portal portal) {
 | 
			
		||||
        for (String originName : PortalRegistry.getAllPortalNetworks().get(portal.getCleanNetwork())) {
 | 
			
		||||
            Portal origin = getByName(originName, portal.getCleanNetwork());
 | 
			
		||||
            if (origin == null ||
 | 
			
		||||
                    !Portal.cleanString(origin.getDestinationName()).equals(portal.getCleanName()) ||
 | 
			
		||||
                    !origin.getStructure().isVerified()) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            //Update sign of fixed gates pointing at this gate
 | 
			
		||||
            if (origin.getOptions().isFixed()) {
 | 
			
		||||
                origin.drawSign();
 | 
			
		||||
            }
 | 
			
		||||
            //Open any always on portal pointing at this portal
 | 
			
		||||
            if (origin.getOptions().isAlwaysOn()) {
 | 
			
		||||
                origin.getPortalOpener().openPortal(true);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets all portal options to be applied to a new portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param player          <p>The player creating the portal</p>
 | 
			
		||||
     * @param destinationName <p>The destination of the portal</p>
 | 
			
		||||
     * @param options         <p>The string on the option line of the sign</p>
 | 
			
		||||
     * @return <p>A map containing all portal options and their values</p>
 | 
			
		||||
     */
 | 
			
		||||
    static Map<PortalOption, Boolean> getPortalOptions(Player player, String destinationName, String options) {
 | 
			
		||||
        Map<PortalOption, Boolean> portalOptions = new HashMap<>();
 | 
			
		||||
        for (PortalOption option : PortalOption.values()) {
 | 
			
		||||
            portalOptions.put(option, options.indexOf(option.getCharacterRepresentation()) != -1 &&
 | 
			
		||||
                    PermissionHelper.canUseOption(player, option));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Can not create a non-fixed always-on portal
 | 
			
		||||
        if (portalOptions.get(PortalOption.ALWAYS_ON) && destinationName.length() == 0) {
 | 
			
		||||
            portalOptions.put(PortalOption.ALWAYS_ON, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Show isn't useful if always on is false
 | 
			
		||||
        if (portalOptions.get(PortalOption.SHOW) && !portalOptions.get(PortalOption.ALWAYS_ON)) {
 | 
			
		||||
            portalOptions.put(PortalOption.SHOW, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Random portals are always on and can't be shown
 | 
			
		||||
        if (portalOptions.get(PortalOption.RANDOM)) {
 | 
			
		||||
            portalOptions.put(PortalOption.ALWAYS_ON, true);
 | 
			
		||||
            portalOptions.put(PortalOption.SHOW, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Bungee portals are always on and don't support Random
 | 
			
		||||
        if (portalOptions.get(PortalOption.BUNGEE)) {
 | 
			
		||||
            portalOptions.put(PortalOption.ALWAYS_ON, true);
 | 
			
		||||
            portalOptions.put(PortalOption.RANDOM, false);
 | 
			
		||||
        }
 | 
			
		||||
        return portalOptions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a portal given its name
 | 
			
		||||
     *
 | 
			
		||||
     * @param name    <p>The name of the portal</p>
 | 
			
		||||
     * @param network <p>The network the portal is connected to</p>
 | 
			
		||||
     * @return <p>The portal with the given name or null</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Portal getByName(String name, String network) {
 | 
			
		||||
        Map<String, Map<String, Portal>> lookupMap = PortalRegistry.getPortalLookupByNetwork();
 | 
			
		||||
        if (!lookupMap.containsKey(network.toLowerCase())) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return lookupMap.get(network.toLowerCase()).get(name.toLowerCase());
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a portal given its entrance
 | 
			
		||||
     *
 | 
			
		||||
     * @param location <p>The location of the portal's entrance</p>
 | 
			
		||||
     * @return <p>The portal at the given location</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Portal getByEntrance(Location location) {
 | 
			
		||||
        return PortalRegistry.getLookupEntrances().get(new BlockLocation(location.getWorld(), location.getBlockX(),
 | 
			
		||||
                location.getBlockY(), location.getBlockZ()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a portal given its entrance
 | 
			
		||||
     *
 | 
			
		||||
     * @param block <p>The block at the portal's entrance</p>
 | 
			
		||||
     * @return <p>The portal at the given block's location</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Portal getByEntrance(Block block) {
 | 
			
		||||
        return PortalRegistry.getLookupEntrances().get(new BlockLocation(block));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a portal given a location adjacent to its entrance
 | 
			
		||||
     *
 | 
			
		||||
     * @param location <p>A location adjacent to the portal's entrance</p>
 | 
			
		||||
     * @return <p>The portal adjacent to the given location</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Portal getByAdjacentEntrance(Location location) {
 | 
			
		||||
        return getByAdjacentEntrance(location, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a portal given a location adjacent to its entrance
 | 
			
		||||
     *
 | 
			
		||||
     * @param location <p>A location adjacent to the portal's entrance</p>
 | 
			
		||||
     * @param range    <p>The range to scan for portals</p>
 | 
			
		||||
     * @return <p>The portal adjacent to the given location</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Portal getByAdjacentEntrance(Location location, int range) {
 | 
			
		||||
        List<BlockLocation> adjacentPositions = new ArrayList<>();
 | 
			
		||||
        BlockLocation centerLocation = new BlockLocation(location.getBlock());
 | 
			
		||||
        adjacentPositions.add(centerLocation);
 | 
			
		||||
 | 
			
		||||
        for (int index = 1; index <= range; index++) {
 | 
			
		||||
            adjacentPositions.add(centerLocation.makeRelativeBlockLocation(index, 0, 0));
 | 
			
		||||
            adjacentPositions.add(centerLocation.makeRelativeBlockLocation(-index, 0, 0));
 | 
			
		||||
            adjacentPositions.add(centerLocation.makeRelativeBlockLocation(0, 0, index));
 | 
			
		||||
            adjacentPositions.add(centerLocation.makeRelativeBlockLocation(0, 0, -index));
 | 
			
		||||
            if (index < range) {
 | 
			
		||||
                adjacentPositions.add(centerLocation.makeRelativeBlockLocation(index, 0, index));
 | 
			
		||||
                adjacentPositions.add(centerLocation.makeRelativeBlockLocation(-index, 0, -index));
 | 
			
		||||
                adjacentPositions.add(centerLocation.makeRelativeBlockLocation(index, 0, -index));
 | 
			
		||||
                adjacentPositions.add(centerLocation.makeRelativeBlockLocation(-index, 0, index));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (BlockLocation adjacentPosition : adjacentPositions) {
 | 
			
		||||
            Portal portal = PortalRegistry.getLookupEntrances().get(adjacentPosition);
 | 
			
		||||
            if (portal != null) {
 | 
			
		||||
                return portal;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a portal given its control block (the block type used for the sign and button)
 | 
			
		||||
     *
 | 
			
		||||
     * @param block <p>The portal's control block</p>
 | 
			
		||||
     * @return <p>The portal with the given control block</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Portal getByControl(Block block) {
 | 
			
		||||
        return PortalRegistry.getLookupControls().get(new BlockLocation(block));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a portal given a block
 | 
			
		||||
     *
 | 
			
		||||
     * @param block <p>One of the loaded lookup blocks</p>
 | 
			
		||||
     * @return <p>The portal corresponding to the block</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Portal getByBlock(Block block) {
 | 
			
		||||
        return PortalRegistry.getLookupBlocks().get(new BlockLocation(block));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a bungee portal given its name
 | 
			
		||||
     *
 | 
			
		||||
     * @param name <p>The name of the bungee portal to get</p>
 | 
			
		||||
     * @return <p>A bungee portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Portal getBungeePortal(String name) {
 | 
			
		||||
        return PortalRegistry.getBungeePortals().get(name.toLowerCase());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets all portal options stored in the portal data
 | 
			
		||||
     *
 | 
			
		||||
     * @param portalData <p>The string list containing all information about a portal</p>
 | 
			
		||||
     * @return <p>A map between portal options and booleans</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Map<PortalOption, Boolean> getPortalOptions(String[] portalData) {
 | 
			
		||||
        Map<PortalOption, Boolean> portalOptions = new HashMap<>();
 | 
			
		||||
        for (PortalOption option : PortalOption.values()) {
 | 
			
		||||
            int saveIndex = option.getSaveIndex();
 | 
			
		||||
            portalOptions.put(option, portalData.length > saveIndex && Boolean.parseBoolean(portalData[saveIndex]));
 | 
			
		||||
        }
 | 
			
		||||
        return portalOptions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens all always-on portals
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The number of always open portals enabled</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static int openAlwaysOpenPortals() {
 | 
			
		||||
        int alwaysOpenCount = 0;
 | 
			
		||||
 | 
			
		||||
        for (Portal portal : PortalRegistry.getAllPortals()) {
 | 
			
		||||
            //Open the gate if it's set as always open or if it's a bungee gate
 | 
			
		||||
            if (portal.getOptions().isFixed() && (Stargate.getGateConfig().enableBungee() &&
 | 
			
		||||
                    portal.getOptions().isBungee() || portal.getPortalActivator().getDestination() != null &&
 | 
			
		||||
                    portal.getOptions().isAlwaysOn())) {
 | 
			
		||||
                portal.getPortalOpener().openPortal(true);
 | 
			
		||||
                alwaysOpenCount++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return alwaysOpenCount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Tries to verify all portals and un-registers non-verifiable portals
 | 
			
		||||
     */
 | 
			
		||||
    public static void verifyAllPortals() {
 | 
			
		||||
        List<Portal> invalidPortals = new ArrayList<>();
 | 
			
		||||
        for (Portal portal : PortalRegistry.getAllPortals()) {
 | 
			
		||||
            //Try and verify the portal. Invalidate it if it cannot be validated
 | 
			
		||||
            PortalStructure structure = portal.getStructure();
 | 
			
		||||
            if (!structure.wasVerified() && (!structure.isVerified() || !structure.checkIntegrity())) {
 | 
			
		||||
                invalidPortals.add(portal);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Un-register any invalid portals found
 | 
			
		||||
        for (Portal portal : invalidPortals) {
 | 
			
		||||
            unregisterInvalidPortal(portal);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Un-registers a portal which has failed its integrity tests
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal <p>The portal of the star portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void unregisterInvalidPortal(Portal portal) {
 | 
			
		||||
        //Show debug information
 | 
			
		||||
        for (RelativeBlockVector control : portal.getGate().getLayout().getControls()) {
 | 
			
		||||
            Block block = portal.getBlockAt(control).getBlock();
 | 
			
		||||
            //Log control blocks not matching the gate layout
 | 
			
		||||
            if (!block.getType().equals(portal.getGate().getControlBlock())) {
 | 
			
		||||
                Stargate.debug("PortalHandler::destroyInvalidPortal", "Control Block Type == " +
 | 
			
		||||
                        block.getType().name());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        PortalRegistry.unregisterPortal(portal, false);
 | 
			
		||||
        Stargate.logInfo(String.format("Destroying stargate at %s", portal));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes all portals
 | 
			
		||||
     */
 | 
			
		||||
    public static void closeAllPortals() {
 | 
			
		||||
        Stargate.logInfo("Closing all stargates.");
 | 
			
		||||
        for (Portal portal : PortalRegistry.getAllPortals()) {
 | 
			
		||||
            if (portal != null) {
 | 
			
		||||
                portal.getPortalOpener().closePortal(true);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes the special characters |, : and # from a portal name
 | 
			
		||||
     *
 | 
			
		||||
     * @param input <p>The name to filter</p>
 | 
			
		||||
     * @return <p>The filtered name</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String filterName(String input) {
 | 
			
		||||
        if (input == null) {
 | 
			
		||||
            return "";
 | 
			
		||||
        }
 | 
			
		||||
        return input.replaceAll("[|:#]", "").trim();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										232
									
								
								src/main/java/net/knarcraft/stargate/portal/PortalOpener.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										232
									
								
								src/main/java/net/knarcraft/stargate/portal/PortalOpener.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,232 @@
 | 
			
		||||
package net.knarcraft.stargate.portal;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
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;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The portal opener is responsible for opening and closing a portal
 | 
			
		||||
 */
 | 
			
		||||
public class PortalOpener {
 | 
			
		||||
 | 
			
		||||
    private boolean isOpen = false;
 | 
			
		||||
    private final Portal portal;
 | 
			
		||||
    private long triggeredTime;
 | 
			
		||||
    private Player player;
 | 
			
		||||
    private final PortalActivator portalActivator;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new portal opener
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal      <p>The portal this portal opener should open</p>
 | 
			
		||||
     * @param destination <p>The fixed destination defined on the portal's sign</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalOpener(Portal portal, String destination) {
 | 
			
		||||
        this.portal = portal;
 | 
			
		||||
        this.portalActivator = new PortalActivator(portal, this, destination);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this portal opener's portal is currently open
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether this portal opener's portal is open</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isOpen() {
 | 
			
		||||
        return isOpen || portal.getOptions().isAlwaysOn();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the time when this portal was triggered (activated/opened)
 | 
			
		||||
     *
 | 
			
		||||
     * @param triggeredTime <p>Unix timestamp when portal was triggered</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setTriggeredTime(long triggeredTime) {
 | 
			
		||||
        this.triggeredTime = triggeredTime;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the portal activator belonging to this portal opener
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The portal activator belonging to this portal opener</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalActivator getPortalActivator() {
 | 
			
		||||
        return this.portalActivator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Open this portal opener's portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param force <p>Whether to force the portal open, even if it's already open for some player</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void openPortal(boolean force) {
 | 
			
		||||
        openPortal(null, force);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Open this portal opener's portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param openFor <p>The player to open the portal for</p>
 | 
			
		||||
     * @param force   <p>Whether to force the portal open, even if it's already open for some player</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void openPortal(Player openFor, boolean force) {
 | 
			
		||||
        //Call the StargateOpenEvent to allow the opening to be cancelled
 | 
			
		||||
        StargateOpenEvent event = new StargateOpenEvent(openFor, portal, force);
 | 
			
		||||
        Stargate.getInstance().getServer().getPluginManager().callEvent(event);
 | 
			
		||||
        if (event.isCancelled() || (isOpen() && !event.getForce())) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Get the material to change the opening to
 | 
			
		||||
        Material openType = portal.getGate().getPortalOpenBlock();
 | 
			
		||||
        //Adjust orientation if applicable
 | 
			
		||||
        Axis axis = (openType.createBlockData() instanceof Orientable) ? portal.getLocation().getRotationAxis() : null;
 | 
			
		||||
 | 
			
		||||
        //Change the entrance blocks to the correct type
 | 
			
		||||
        for (BlockLocation inside : portal.getStructure().getEntrances()) {
 | 
			
		||||
            Stargate.addBlockChangeRequest(new BlockChangeRequest(inside, openType, axis));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Update the portal state to make is actually open
 | 
			
		||||
        updatePortalOpenState(openFor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates this portal opener's portal to be recognized as open and opens its destination portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param openFor <p>The player to open this portal opener's portal for</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void updatePortalOpenState(Player openFor) {
 | 
			
		||||
        //Update the open state of this portal
 | 
			
		||||
        isOpen = true;
 | 
			
		||||
        triggeredTime = System.currentTimeMillis() / 1000;
 | 
			
		||||
 | 
			
		||||
        //Change state from active to open
 | 
			
		||||
        Stargate.getStargateConfig().getOpenPortalsQueue().add(portal);
 | 
			
		||||
        Stargate.getStargateConfig().getActivePortalsQueue().remove(portal);
 | 
			
		||||
 | 
			
		||||
        PortalOptions options = portal.getOptions();
 | 
			
		||||
 | 
			
		||||
        //If this portal is always open, opening the destination is not necessary
 | 
			
		||||
        if (options.isAlwaysOn()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Update the player the portal is open for
 | 
			
		||||
        this.player = openFor;
 | 
			
		||||
 | 
			
		||||
        Portal destination = portal.getPortalActivator().getDestination();
 | 
			
		||||
        if (destination == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
            destination.getPortalOpener().openPortal(openFor, false);
 | 
			
		||||
            //Set the destination portal to this opener's portal
 | 
			
		||||
            destination.getPortalActivator().setDestination(portal);
 | 
			
		||||
 | 
			
		||||
            //Update the destination's sign if it's verified
 | 
			
		||||
            if (destination.getStructure().isVerified()) {
 | 
			
		||||
                destination.drawSign();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes this portal opener's portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param force <p>Whether to force the portal closed, even if it's set as always on</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void closePortal(boolean force) {
 | 
			
		||||
        //No need to close a portal which is already closed
 | 
			
		||||
        if (!isOpen()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Call the StargateCloseEvent to allow other plugins to cancel the closing, or change whether to force it closed
 | 
			
		||||
        StargateCloseEvent event = new StargateCloseEvent(portal, force);
 | 
			
		||||
        Stargate.getInstance().getServer().getPluginManager().callEvent(event);
 | 
			
		||||
        if (event.isCancelled()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Only close an always-open portal if forced to
 | 
			
		||||
        if (portal.getOptions().isAlwaysOn() && !event.getForce()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Close the portal by requesting the opening blocks to change
 | 
			
		||||
        Material closedType = portal.getGate().getPortalClosedBlock();
 | 
			
		||||
        for (BlockLocation entrance : portal.getStructure().getEntrances()) {
 | 
			
		||||
            Stargate.addBlockChangeRequest(new BlockChangeRequest(entrance, closedType, null));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Update the portal state to make it actually closed
 | 
			
		||||
        updatePortalClosedState();
 | 
			
		||||
 | 
			
		||||
        //Finally, deactivate the portal
 | 
			
		||||
        portalActivator.deactivate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates this portal to be recognized as closed and closes its destination portal
 | 
			
		||||
     */
 | 
			
		||||
    private void updatePortalClosedState() {
 | 
			
		||||
        //Unset the stored player and set the portal to closed
 | 
			
		||||
        player = null;
 | 
			
		||||
        isOpen = false;
 | 
			
		||||
 | 
			
		||||
        //Un-mark the portal as active and open
 | 
			
		||||
        Stargate.getStargateConfig().getOpenPortalsQueue().remove(portal);
 | 
			
		||||
        Stargate.getStargateConfig().getActivePortalsQueue().remove(portal);
 | 
			
		||||
 | 
			
		||||
        //Close the destination portal if not always open
 | 
			
		||||
        if (!portal.getOptions().isAlwaysOn()) {
 | 
			
		||||
            Portal destination = portal.getPortalActivator().getDestination();
 | 
			
		||||
 | 
			
		||||
            if (destination != null && destination.isOpen()) {
 | 
			
		||||
                //De-activate and close the destination portal
 | 
			
		||||
                destination.getPortalActivator().deactivate();
 | 
			
		||||
                destination.getPortalOpener().closePortal(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this portal opener's portal is open for the given player
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player to check portal state for</p>
 | 
			
		||||
     * @return <p>True if this portal opener's portal is open to the given player</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isOpenFor(Player player) {
 | 
			
		||||
        //If closed, it's closed for everyone
 | 
			
		||||
        if (!isOpen) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        //If always on, or player is null which only happens with an always on portal, allow the player to pass
 | 
			
		||||
        if (portal.getOptions().isAlwaysOn() || this.player == null) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        //If the player is the player which the portal opened for, allow it to pass
 | 
			
		||||
        return player != null && player.getName().equalsIgnoreCase(this.player.getName());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the time this portal opener's portal was triggered (activated/opened)
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The time this portal opener's portal was triggered</p>
 | 
			
		||||
     */
 | 
			
		||||
    public long getTriggeredTime() {
 | 
			
		||||
        return triggeredTime;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										297
									
								
								src/main/java/net/knarcraft/stargate/portal/PortalRegistry.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										297
									
								
								src/main/java/net/knarcraft/stargate/portal/PortalRegistry.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,297 @@
 | 
			
		||||
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 java.util.ArrayList;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The portal registry keeps track of all registered portals and all their lookup blocks
 | 
			
		||||
 */
 | 
			
		||||
public class PortalRegistry {
 | 
			
		||||
 | 
			
		||||
    private static final Map<BlockLocation, Portal> lookupBlocks = new HashMap<>();
 | 
			
		||||
    private static final Map<BlockLocation, Portal> lookupEntrances = new HashMap<>();
 | 
			
		||||
    private static final Map<BlockLocation, Portal> lookupControls = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    private static final Map<String, Map<String, Portal>> portalLookupByNetwork = new HashMap<>();
 | 
			
		||||
    private static final Map<String, List<String>> allPortalNetworks = new HashMap<>();
 | 
			
		||||
    private static final Map<String, Portal> bungeePortals = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    private static final List<Portal> allPortals = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clears all portals and all data held by the portal registry
 | 
			
		||||
     */
 | 
			
		||||
    public static void clearPortals() {
 | 
			
		||||
        lookupBlocks.clear();
 | 
			
		||||
        portalLookupByNetwork.clear();
 | 
			
		||||
        lookupEntrances.clear();
 | 
			
		||||
        lookupControls.clear();
 | 
			
		||||
        allPortals.clear();
 | 
			
		||||
        allPortalNetworks.clear();
 | 
			
		||||
        bungeePortals.clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clears all portals loaded in a given world
 | 
			
		||||
     *
 | 
			
		||||
     * @param world <p>The world containing the portals to clear</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void clearPortals(World world) {
 | 
			
		||||
        //Storing the portals to clear is necessary to avoid a concurrent modification exception
 | 
			
		||||
        List<Portal> portalsToRemove = new ArrayList<>();
 | 
			
		||||
        allPortals.forEach((portal) -> {
 | 
			
		||||
            if (portal.getWorld().equals(world)) {
 | 
			
		||||
                portalsToRemove.add(portal);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        clearPortals(portalsToRemove);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clears a given list of portals from all relevant variables
 | 
			
		||||
     *
 | 
			
		||||
     * @param portalsToRemove <p>A list of portals to remove</p>
 | 
			
		||||
     */
 | 
			
		||||
    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.getCleanName()));
 | 
			
		||||
 | 
			
		||||
        //Clear all the lookup locations for the portals
 | 
			
		||||
        lookupBlocks.keySet().removeIf((key) -> portalsToRemove.contains(lookupBlocks.get(key)));
 | 
			
		||||
        lookupEntrances.keySet().removeIf((key) -> portalsToRemove.contains(lookupEntrances.get(key)));
 | 
			
		||||
        lookupControls.keySet().removeIf((key) -> portalsToRemove.contains(lookupControls.get(key)));
 | 
			
		||||
 | 
			
		||||
        //Remove the portals from all networks, and then remove any empty networks. This is done for both network maps
 | 
			
		||||
        portalLookupByNetwork.keySet().forEach((network) -> portalLookupByNetwork.get(network).keySet().removeIf((key) ->
 | 
			
		||||
                portalsToRemove.contains(portalLookupByNetwork.get(network).get(key))));
 | 
			
		||||
        portalLookupByNetwork.keySet().removeIf((key) -> portalLookupByNetwork.get(key).isEmpty());
 | 
			
		||||
        allPortalNetworks.keySet().forEach((network) -> allPortalNetworks.get(network).removeIf(portalNames::contains));
 | 
			
		||||
        allPortalNetworks.keySet().removeIf((network) -> allPortalNetworks.get(network).isEmpty());
 | 
			
		||||
 | 
			
		||||
        //Finally, remove the portals from the portal list
 | 
			
		||||
        allPortals.removeIf(portalsToRemove::contains);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a copy of the list of all portals
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A copy of the list of all portals</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static List<Portal> getAllPortals() {
 | 
			
		||||
        return new ArrayList<>(allPortals);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a copy of the lookup map for finding a portal by its frame
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A copy of the frame block lookup map</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Map<BlockLocation, Portal> getLookupBlocks() {
 | 
			
		||||
        return new HashMap<>(lookupBlocks);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a copy of the lookup map for finding a portal by its control block
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A copy of the control block lookup map</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Map<BlockLocation, Portal> getLookupControls() {
 | 
			
		||||
        return new HashMap<>(lookupControls);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a copy of the lookup map for finding all portals in a network
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A copy of the network portal lookup map</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Map<String, Map<String, Portal>> getPortalLookupByNetwork() {
 | 
			
		||||
        return new HashMap<>(portalLookupByNetwork);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a copy of all portal entrances available for lookup
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A copy of all entrances to portal mappings</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Map<BlockLocation, Portal> getLookupEntrances() {
 | 
			
		||||
        return new HashMap<>(lookupEntrances);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a copy of all portal networks
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A copy of all portal networks</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Map<String, List<String>> getAllPortalNetworks() {
 | 
			
		||||
        return new HashMap<>(allPortalNetworks);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a copy of all bungee portals
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A copy of all bungee portals</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Map<String, Portal> getBungeePortals() {
 | 
			
		||||
        return new HashMap<>(bungeePortals);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets names of all portals within a network
 | 
			
		||||
     *
 | 
			
		||||
     * @param network <p>The network to get portals from</p>
 | 
			
		||||
     * @return <p>A list of portal names</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static List<String> getNetwork(String network) {
 | 
			
		||||
        return allPortalNetworks.get(network.toLowerCase());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Un-registers the given portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal    <p>The portal to un-register</p>
 | 
			
		||||
     * @param removeAll <p>Whether to remove the portal from the list of all portals</p>
 | 
			
		||||
     */
 | 
			
		||||
    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.getCleanName();
 | 
			
		||||
        String networkName = portal.getCleanNetwork();
 | 
			
		||||
 | 
			
		||||
        //Remove portal from lookup blocks
 | 
			
		||||
        for (BlockLocation block : portal.getStructure().getFrame()) {
 | 
			
		||||
            lookupBlocks.remove(block);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Remove registered info about the lookup controls and blocks
 | 
			
		||||
        lookupBlocks.remove(portal.getSignLocation());
 | 
			
		||||
        lookupControls.remove(portal.getSignLocation());
 | 
			
		||||
 | 
			
		||||
        BlockLocation button = portal.getStructure().getButton();
 | 
			
		||||
        if (button != null) {
 | 
			
		||||
            lookupBlocks.remove(button);
 | 
			
		||||
            lookupControls.remove(button);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Remove entrances
 | 
			
		||||
        for (BlockLocation entrance : portal.getStructure().getEntrances()) {
 | 
			
		||||
            lookupEntrances.remove(entrance);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Remove the portal from the list of all portals
 | 
			
		||||
        if (removeAll) {
 | 
			
		||||
            allPortals.remove(portal);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (portal.getOptions().isBungee()) {
 | 
			
		||||
            //Remove the bungee listing
 | 
			
		||||
            bungeePortals.remove(portalName);
 | 
			
		||||
        } else {
 | 
			
		||||
            //Remove from network lists
 | 
			
		||||
            portalLookupByNetwork.get(networkName).remove(portalName);
 | 
			
		||||
            allPortalNetworks.get(networkName).remove(portalName);
 | 
			
		||||
 | 
			
		||||
            //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.getCleanNetwork());
 | 
			
		||||
                if (origin == null || !origin.getDestinationName().equalsIgnoreCase(portalName) ||
 | 
			
		||||
                        !origin.getStructure().isVerified()) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                //Update the portal's sign
 | 
			
		||||
                if (origin.getOptions().isFixed()) {
 | 
			
		||||
                    origin.drawSign();
 | 
			
		||||
                }
 | 
			
		||||
                //Close portal without destination
 | 
			
		||||
                if (origin.getOptions().isAlwaysOn()) {
 | 
			
		||||
                    origin.getPortalOpener().closePortal(true);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Mark the portal's sign as unregistered
 | 
			
		||||
        new PortalSignDrawer(portal).drawUnregisteredSign();
 | 
			
		||||
 | 
			
		||||
        PortalFileHelper.saveAllPortals(portal.getWorld());
 | 
			
		||||
        portal.setRegistered(false);
 | 
			
		||||
        DynmapManager.removePortalMarker(portal);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Registers a portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal <p>The portal to register</p>
 | 
			
		||||
     */
 | 
			
		||||
    static void registerPortal(Portal portal) {
 | 
			
		||||
        portal.getOptions().setFixed(portal.getDestinationName().length() > 0 || portal.getOptions().isRandom() ||
 | 
			
		||||
                portal.getOptions().isBungee());
 | 
			
		||||
 | 
			
		||||
        String portalName = portal.getCleanName();
 | 
			
		||||
        String networkName = portal.getCleanNetwork();
 | 
			
		||||
 | 
			
		||||
        //Bungee portals are stored in their own list
 | 
			
		||||
        if (portal.getOptions().isBungee()) {
 | 
			
		||||
            bungeePortals.put(portalName, portal);
 | 
			
		||||
        } else {
 | 
			
		||||
            //Check if network exists in the lookup list. If not, register the new network
 | 
			
		||||
            if (!portalLookupByNetwork.containsKey(networkName)) {
 | 
			
		||||
                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", String.format("Network %s not in allPortalsNet, adding",
 | 
			
		||||
                        portal.getNetwork()));
 | 
			
		||||
                allPortalNetworks.put(networkName, new ArrayList<>());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Register the portal
 | 
			
		||||
            portalLookupByNetwork.get(networkName).put(portalName, portal);
 | 
			
		||||
 | 
			
		||||
            if (!allPortalNetworks.get(networkName).contains(portalName)) {
 | 
			
		||||
                allPortalNetworks.get(networkName).add(portalName);
 | 
			
		||||
            } else {
 | 
			
		||||
                Stargate.logSevere(String.format("Portal %s on network %s was registered twice. Check your portal " +
 | 
			
		||||
                        "database for duplicates.", portal.getName(), portal.getNetwork()));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Register all frame blocks to the lookup list
 | 
			
		||||
        for (BlockLocation block : portal.getStructure().getFrame()) {
 | 
			
		||||
            lookupBlocks.put(block, portal);
 | 
			
		||||
        }
 | 
			
		||||
        //Register the sign and button to the lookup lists
 | 
			
		||||
        if (!portal.getOptions().hasNoSign()) {
 | 
			
		||||
            lookupBlocks.put(portal.getSignLocation(), portal);
 | 
			
		||||
            lookupControls.put(portal.getSignLocation(), portal);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        BlockLocation button = portal.getStructure().getButton();
 | 
			
		||||
        if (button != null) {
 | 
			
		||||
            lookupBlocks.put(button, portal);
 | 
			
		||||
            lookupControls.put(button, portal);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Register entrances to the lookup list
 | 
			
		||||
        for (BlockLocation entrance : portal.getStructure().getEntrances()) {
 | 
			
		||||
            lookupEntrances.put(entrance, portal);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        allPortals.add(portal);
 | 
			
		||||
        portal.setRegistered(true);
 | 
			
		||||
        DynmapManager.addPortalMarker(portal);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,406 @@
 | 
			
		||||
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 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
 | 
			
		||||
 */
 | 
			
		||||
public class PortalSignDrawer {
 | 
			
		||||
 | 
			
		||||
    private final Portal portal;
 | 
			
		||||
    private final static ChatColor errorColor = ChatColor.DARK_RED;
 | 
			
		||||
    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
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal <p>The portal whose sign this portal sign drawer is responsible for drawing</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalSignDrawer(Portal portal) {
 | 
			
		||||
        this.portal = portal;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the highlighting sign color
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The highlighting color is used for the markings around portal names and network names ('>','<','-',')','(').</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param newHighlightColor <p>The new highlight color</p>
 | 
			
		||||
     */
 | 
			
		||||
    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() {
 | 
			
		||||
        Sign sign = getSign();
 | 
			
		||||
        if (sign == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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 signData <p>All necessary sign information</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void drawSign(SignData signData) {
 | 
			
		||||
        Sign sign = signData.getSign();
 | 
			
		||||
        ChatColor highlightColor = signData.getHighlightSignColor();
 | 
			
		||||
        ChatColor mainColor = signData.getMainSignColor();
 | 
			
		||||
        //Clear sign
 | 
			
		||||
        clearSign(sign);
 | 
			
		||||
        setLine(signData, 0, highlightColor + "-" + mainColor + translateAllColorCodes(portal.getName()) +
 | 
			
		||||
                highlightColor + "-");
 | 
			
		||||
 | 
			
		||||
        if (!portal.getPortalActivator().isActive()) {
 | 
			
		||||
            //Default sign text
 | 
			
		||||
            drawInactiveSign(signData);
 | 
			
		||||
        } else {
 | 
			
		||||
            if (portal.getOptions().isBungee()) {
 | 
			
		||||
                //Bungee sign
 | 
			
		||||
                drawBungeeSign(signData);
 | 
			
		||||
            } else if (portal.getOptions().isFixed()) {
 | 
			
		||||
                //Sign pointing at one other portal
 | 
			
		||||
                drawFixedSign(signData);
 | 
			
		||||
            } else {
 | 
			
		||||
                //Networking stuff
 | 
			
		||||
                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 signData <p>All necessary sign information</p>
 | 
			
		||||
     */
 | 
			
		||||
    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 freeGatesColored = Stargate.getEconomyConfig().useEconomy() &&
 | 
			
		||||
                Stargate.getEconomyConfig().drawFreePortalsColored();
 | 
			
		||||
 | 
			
		||||
        //Last, and not only entry. Draw the entry two back
 | 
			
		||||
        if ((destinationIndex == maxIndex) && (maxIndex > 1)) {
 | 
			
		||||
            drawNetworkSignLine(signData, freeGatesColored, ++signLineIndex, destinationIndex - 2);
 | 
			
		||||
        }
 | 
			
		||||
        //Not first entry. Draw the previous entry
 | 
			
		||||
        if (destinationIndex > 0) {
 | 
			
		||||
            drawNetworkSignLine(signData, freeGatesColored, ++signLineIndex, destinationIndex - 1);
 | 
			
		||||
        }
 | 
			
		||||
        //Draw the chosen entry (line 2 or 3)
 | 
			
		||||
        drawNetworkSignChosenLine(signData, freeGatesColored, ++signLineIndex);
 | 
			
		||||
        //Has another entry and space on the sign
 | 
			
		||||
        if ((maxIndex >= destinationIndex + 1)) {
 | 
			
		||||
            drawNetworkSignLine(signData, freeGatesColored, ++signLineIndex, destinationIndex + 1);
 | 
			
		||||
        }
 | 
			
		||||
        //Has another entry and space on the sign
 | 
			
		||||
        if ((maxIndex >= destinationIndex + 2) && (++signLineIndex <= 3)) {
 | 
			
		||||
            drawNetworkSignLine(signData, freeGatesColored, signLineIndex, destinationIndex + 2);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Draws the chosen destination on one sign line
 | 
			
		||||
     *
 | 
			
		||||
     * @param signData         <p>All necessary sign information</p>
 | 
			
		||||
     * @param freeGatesColored <p>Whether to display free gates in a different color</p>
 | 
			
		||||
     * @param signLineIndex    <p>The line to draw on</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void drawNetworkSignChosenLine(SignData signData, boolean freeGatesColored, int signLineIndex) {
 | 
			
		||||
        ChatColor highlightColor = signData.getHighlightSignColor();
 | 
			
		||||
        ChatColor mainColor = signData.getMainSignColor();
 | 
			
		||||
        if (freeGatesColored) {
 | 
			
		||||
            Portal destination = PortalHandler.getByName(portal.getDestinationName(), portal.getNetwork());
 | 
			
		||||
            boolean free = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination);
 | 
			
		||||
            ChatColor nameColor = (free ? freeColor : highlightColor);
 | 
			
		||||
            setLine(signData, signLineIndex, nameColor + ">" + (free ? freeColor : mainColor) +
 | 
			
		||||
                    translateAllColorCodes(portal.getDestinationName()) + nameColor + "<");
 | 
			
		||||
        } else {
 | 
			
		||||
            setLine(signData, signLineIndex, highlightColor + ">" + mainColor +
 | 
			
		||||
                    translateAllColorCodes(portal.getDestinationName()) + highlightColor + "<");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets a line on a sign, adding the chosen sign color
 | 
			
		||||
     *
 | 
			
		||||
     * @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(SignData signData, int index, String text) {
 | 
			
		||||
        ChatColor mainColor = signData.getMainSignColor();
 | 
			
		||||
        signData.getSign().setLine(index, mainColor + text);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Draws one network destination on one sign line
 | 
			
		||||
     *
 | 
			
		||||
     * @param signData         <p>All necessary sign information</p>
 | 
			
		||||
     * @param freeGatesColored <p>Whether to display free gates in a different color</p>
 | 
			
		||||
     * @param signLineIndex    <p>The line to draw on</p>
 | 
			
		||||
     * @param destinationIndex <p>The index of the destination to draw</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void drawNetworkSignLine(SignData signData, boolean freeGatesColored, int signLineIndex, int destinationIndex) {
 | 
			
		||||
        ChatColor mainColor = signData.getMainSignColor();
 | 
			
		||||
        PortalActivator destinations = portal.getPortalActivator();
 | 
			
		||||
        String destinationName = destinations.getDestinations().get(destinationIndex);
 | 
			
		||||
        if (freeGatesColored) {
 | 
			
		||||
            Portal destination = PortalHandler.getByName(destinationName, portal.getNetwork());
 | 
			
		||||
            boolean free = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination);
 | 
			
		||||
            setLine(signData, signLineIndex, (free ? freeColor : mainColor) + translateAllColorCodes(destinationName));
 | 
			
		||||
        } else {
 | 
			
		||||
            setLine(signData, signLineIndex, mainColor + translateAllColorCodes(destinationName));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Draws the sign of a BungeeCord portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param signData <p>All necessary sign information</p>
 | 
			
		||||
     */
 | 
			
		||||
    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 the sign of an in-active portal
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The sign for an in-active portal should display the right-click prompt and the network.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param signData <p>All necessary sign information</p>
 | 
			
		||||
     */
 | 
			
		||||
    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(signData, 3, highlightColor + "(" + mainColor + translateAllColorCodes(portal.getNetwork()) +
 | 
			
		||||
                    highlightColor + ")");
 | 
			
		||||
        } else {
 | 
			
		||||
            setLine(signData, 3, "");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Draws a sign pointing to a fixed location
 | 
			
		||||
     *
 | 
			
		||||
     * @param signData <p>All necessary sign information</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void drawFixedSign(SignData signData) {
 | 
			
		||||
        ChatColor highlightColor = signData.getHighlightSignColor();
 | 
			
		||||
        ChatColor mainColor = signData.getMainSignColor();
 | 
			
		||||
        Portal destinationPortal = PortalHandler.getByName(Portal.cleanString(portal.getDestinationName()),
 | 
			
		||||
                portal.getCleanNetwork());
 | 
			
		||||
        String destinationName = portal.getOptions().isRandom() ? Stargate.getString("signRandom") :
 | 
			
		||||
                (destinationPortal != null ? destinationPortal.getName() : portal.getDestinationName());
 | 
			
		||||
        setLine(signData, 1, highlightColor + ">" + mainColor + translateAllColorCodes(destinationName) +
 | 
			
		||||
                highlightColor + "<");
 | 
			
		||||
 | 
			
		||||
        if (portal.getOptions().isNoNetwork()) {
 | 
			
		||||
            setLine(signData, 2, "");
 | 
			
		||||
        } else {
 | 
			
		||||
            setLine(signData, 2, highlightColor + "(" + mainColor +
 | 
			
		||||
                    translateAllColorCodes(portal.getNetwork()) + highlightColor + ")");
 | 
			
		||||
        }
 | 
			
		||||
        Portal destination = PortalHandler.getByName(Portal.cleanString(portal.getDestinationName()),
 | 
			
		||||
                portal.getNetwork());
 | 
			
		||||
        if (destination == null && !portal.getOptions().isRandom()) {
 | 
			
		||||
            setLine(signData, 3, errorColor + Stargate.getString("signDisconnected"));
 | 
			
		||||
        } else {
 | 
			
		||||
            setLine(signData, 3, "");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Marks a portal with an invalid gate by changing its sign and writing to the console
 | 
			
		||||
     *
 | 
			
		||||
     * @param portalLocation <p>The location of the portal with an invalid gate</p>
 | 
			
		||||
     * @param gateName       <p>The name of the invalid gate type</p>
 | 
			
		||||
     * @param lineIndex      <p>The index of the line the invalid portal was found at</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void markPortalWithInvalidGate(PortalLocation portalLocation, String gateName, int lineIndex) {
 | 
			
		||||
        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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,145 @@
 | 
			
		||||
package net.knarcraft.stargate.portal.property;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.container.BlockLocation;
 | 
			
		||||
import net.knarcraft.stargate.container.RelativeBlockVector;
 | 
			
		||||
import org.bukkit.Axis;
 | 
			
		||||
import org.bukkit.World;
 | 
			
		||||
import org.bukkit.block.BlockFace;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Keeps track of location related data for a portal
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("UnusedReturnValue")
 | 
			
		||||
public class PortalLocation {
 | 
			
		||||
 | 
			
		||||
    private BlockLocation topLeft;
 | 
			
		||||
    private float yaw;
 | 
			
		||||
    private BlockLocation signLocation;
 | 
			
		||||
    private RelativeBlockVector buttonVector;
 | 
			
		||||
    private BlockFace buttonFacing;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the top-left block of the portal
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The top-left block of the portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockLocation getTopLeft() {
 | 
			
		||||
        return topLeft;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the yaw for looking outwards from the portal
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The portal's yaw</p>
 | 
			
		||||
     */
 | 
			
		||||
    public float getYaw() {
 | 
			
		||||
        return yaw;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the location of the portal's sign
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The location of the portal's sign</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockLocation getSignLocation() {
 | 
			
		||||
        return signLocation;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The relative block vector pointing to the portal's button
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The relative location of the portal's button</p>
 | 
			
		||||
     */
 | 
			
		||||
    public RelativeBlockVector getButtonVector() {
 | 
			
		||||
        return buttonVector;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the block face determining the button's direction
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The button's block face</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockFace getButtonFacing() {
 | 
			
		||||
        return buttonFacing;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the rotation axis, which is the axis along which the gate is placed
 | 
			
		||||
     * <p>The portal's rotation axis is the cross axis of the button's axis</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The portal's rotation axis</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Axis getRotationAxis() {
 | 
			
		||||
        return getYaw() == 0.0F || getYaw() == 180.0F ? Axis.X : Axis.Z;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the world this portal resides in
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The world this portal resides in</p>
 | 
			
		||||
     */
 | 
			
		||||
    public World getWorld() {
 | 
			
		||||
        return topLeft.getWorld();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the portal's top-left location
 | 
			
		||||
     *
 | 
			
		||||
     * <p>Assuming the portal is a square, the top-left block is the top-left block when looking at the portal at the
 | 
			
		||||
     * side with the portal's sign.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param topLeft <p>The new top-left block of the portal's square structure</p>
 | 
			
		||||
     * @return <p>The portal location Object</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalLocation setTopLeft(BlockLocation topLeft) {
 | 
			
		||||
        this.topLeft = topLeft;
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the portal's yaw
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The portal's yaw is the yaw a player would get when looking directly out from the portal</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param yaw <p>The portal's new yaw</p>
 | 
			
		||||
     * @return <p>The portal location Object</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalLocation setYaw(float yaw) {
 | 
			
		||||
        this.yaw = yaw;
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the location of the portal's sign
 | 
			
		||||
     *
 | 
			
		||||
     * @param signLocation <p>The new sign location</p>
 | 
			
		||||
     * @return <p>The portal location Object</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalLocation setSignLocation(BlockLocation signLocation) {
 | 
			
		||||
        this.signLocation = signLocation;
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the relative location of the portal's button
 | 
			
		||||
     *
 | 
			
		||||
     * @param buttonVector <p>The new relative button location</p>
 | 
			
		||||
     * @return <p>The portal location Object</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalLocation setButtonVector(RelativeBlockVector buttonVector) {
 | 
			
		||||
        this.buttonVector = buttonVector;
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the block face for the direction the portal button is facing
 | 
			
		||||
     *
 | 
			
		||||
     * @param buttonFacing <p>The new block face of the portal's button</p>
 | 
			
		||||
     * @return <p>The portal location Object</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalLocation setButtonFacing(BlockFace buttonFacing) {
 | 
			
		||||
        this.buttonFacing = buttonFacing;
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,106 @@
 | 
			
		||||
package net.knarcraft.stargate.portal.property;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Each enum value represents one option a portal can have/use
 | 
			
		||||
 */
 | 
			
		||||
public enum PortalOption {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This option allows a portal to be hidden from others
 | 
			
		||||
     */
 | 
			
		||||
    HIDDEN('h', "stargate.option.hidden", 11),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This option allows a portal that's always on and does not need to be activated or opened each time
 | 
			
		||||
     */
 | 
			
		||||
    ALWAYS_ON('a', "stargate.option.alwayson", 12),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This option allows a portal that's private to the stargate's owner
 | 
			
		||||
     */
 | 
			
		||||
    PRIVATE('p', "stargate.option.private", 13),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This option allows a portal that's free even if stargates usually are not
 | 
			
		||||
     */
 | 
			
		||||
    FREE('f', "stargate.option.free", 15),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This option allows a portal where players exit through the back of the portal
 | 
			
		||||
     */
 | 
			
		||||
    BACKWARDS('b', "stargate.option.backwards", 16),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This option shows the gate in the network list even if it's always on
 | 
			
		||||
     */
 | 
			
		||||
    SHOW('s', "stargate.option.show", 17),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This option hides the network name on the sign
 | 
			
		||||
     */
 | 
			
		||||
    NO_NETWORK('n', "stargate.option.nonetwork", 18),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This option allows a portal where players teleport to a random exit portal in the network
 | 
			
		||||
     */
 | 
			
		||||
    RANDOM('r', "stargate.option.random", 19),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This option allows a portal to teleport to another server connected through BungeeCord
 | 
			
		||||
     */
 | 
			
		||||
    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;
 | 
			
		||||
    private final int saveIndex;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new portal options
 | 
			
		||||
     *
 | 
			
		||||
     * @param characterRepresentation <p>The character representation used on the sign to allow this option</p>
 | 
			
		||||
     * @param permissionString        <p>The permission necessary to use this option</p>
 | 
			
		||||
     */
 | 
			
		||||
    PortalOption(final char characterRepresentation, String permissionString, int saveIndex) {
 | 
			
		||||
        this.characterRepresentation = characterRepresentation;
 | 
			
		||||
        this.permissionString = permissionString;
 | 
			
		||||
        this.saveIndex = saveIndex;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the character representation used to enable this setting on the sign
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The character representation of this option</p>
 | 
			
		||||
     */
 | 
			
		||||
    public char getCharacterRepresentation() {
 | 
			
		||||
        return this.characterRepresentation;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the permission necessary to use this option
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The permission necessary for this option</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getPermissionString() {
 | 
			
		||||
        return this.permissionString;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the index of the save file this option is stored at
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>This option's save index</p>
 | 
			
		||||
     */
 | 
			
		||||
    public int getSaveIndex() {
 | 
			
		||||
        return this.saveIndex;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,196 @@
 | 
			
		||||
package net.knarcraft.stargate.portal.property;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Keeps track of all options for one portal
 | 
			
		||||
 */
 | 
			
		||||
public class PortalOptions {
 | 
			
		||||
 | 
			
		||||
    private final Map<PortalOption, Boolean> options;
 | 
			
		||||
    private boolean isFixed;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new portal options object
 | 
			
		||||
     *
 | 
			
		||||
     * @param options        <p>All options to keep track of</p>
 | 
			
		||||
     * @param hasDestination <p>Whether the portal has a fixed destination</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalOptions(Map<PortalOption, Boolean> options, boolean hasDestination) {
 | 
			
		||||
        this.options = options;
 | 
			
		||||
 | 
			
		||||
        isFixed = hasDestination || this.isRandom() || this.isBungee();
 | 
			
		||||
 | 
			
		||||
        if (this.isAlwaysOn() && !isFixed) {
 | 
			
		||||
            this.options.put(PortalOption.ALWAYS_ON, false);
 | 
			
		||||
            Stargate.debug("PortalOptions", "Can not create a non-fixed always-on gate. Setting AlwaysOn = false");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((this.isRandom() || this.isBungee()) && !this.isAlwaysOn()) {
 | 
			
		||||
            this.options.put(PortalOption.ALWAYS_ON, true);
 | 
			
		||||
            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");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this portal is fixed
 | 
			
		||||
     *
 | 
			
		||||
     * <p>A fixed portal is a portal for which the player cannot choose destination. A portal with a set destination, a
 | 
			
		||||
     * random portal and bungee portals are fixed. While the player has no choice regarding destinations, a fixed gate
 | 
			
		||||
     * may still need to be activated if not set to always on.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether this portal is fixed</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isFixed() {
 | 
			
		||||
        return this.isFixed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets whether this portal is fixed
 | 
			
		||||
     *
 | 
			
		||||
     * @param fixed <p>Whether this gate should be fixed</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setFixed(boolean fixed) {
 | 
			
		||||
        this.isFixed = fixed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this portal is always on
 | 
			
		||||
     *
 | 
			
		||||
     * <p>An always on portal is always open for everyone, and always uses the open-block. It never needs to be
 | 
			
		||||
     * activated or opened manually.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether this portal is always on</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isAlwaysOn() {
 | 
			
		||||
        return this.options.get(PortalOption.ALWAYS_ON);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this portal is hidden
 | 
			
		||||
     *
 | 
			
		||||
     * <p>A hidden portal will be hidden on a network for everyone but admins and the portal owner. In other words,
 | 
			
		||||
     * when selecting a destination using a portal's sign, hidden gates will only be available in the list for the
 | 
			
		||||
     * owner and players with the appropriate permission.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether this portal is hidden</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isHidden() {
 | 
			
		||||
        return this.options.get(PortalOption.HIDDEN);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this portal is private
 | 
			
		||||
     *
 | 
			
		||||
     * <p>A private portal can only be opened by the owner and players with the appropriate permission. A private gate
 | 
			
		||||
     * is not hidden unless the hidden option is also enabled.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether this portal is private</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isPrivate() {
 | 
			
		||||
        return this.options.get(PortalOption.PRIVATE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this portal is free
 | 
			
		||||
     *
 | 
			
		||||
     * <p>A free portal is exempt from any fees which would normally occur from using the portal. It does nothing if
 | 
			
		||||
     * economy is disabled.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether this portal is free</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isFree() {
 | 
			
		||||
        return this.options.get(PortalOption.FREE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this portal is backwards
 | 
			
		||||
     *
 | 
			
		||||
     * <p>A backwards portal is one where players exit through the back. It's important to note that the exit is
 | 
			
		||||
     * mirrored, not rotated, when exiting backwards.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether this portal is backwards</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isBackwards() {
 | 
			
		||||
        return this.options.get(PortalOption.BACKWARDS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this portal is shown on the network even if it's always on
 | 
			
		||||
     *
 | 
			
		||||
     * <p>Normally, always-on portals are not selectable on a network, but enabling this option allows the portal to be
 | 
			
		||||
     * shown.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether portal gate is shown</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isShown() {
 | 
			
		||||
        return this.options.get(PortalOption.SHOW);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this portal shows no network
 | 
			
		||||
     *
 | 
			
		||||
     * <p>Enabling the no network option allows the portal's network to be hidden for whatever reason. If allowing
 | 
			
		||||
     * normal players to create portals, this can be used to prevent random users from connecting gates to
 | 
			
		||||
     * "protected networks".</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether this portal shows no network/p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isNoNetwork() {
 | 
			
		||||
        return this.options.get(PortalOption.NO_NETWORK);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this portal goes to a random location on the network
 | 
			
		||||
     *
 | 
			
		||||
     * <p>A random portal is always on and will teleport to a random destination within the same network.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether this portal goes to a random location</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isRandom() {
 | 
			
		||||
        return this.options.get(PortalOption.RANDOM);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this portal is a bungee portal
 | 
			
		||||
     *
 | 
			
		||||
     * <p>A bungee portal is able to teleport to a portal on another server. It works differently from other portals as
 | 
			
		||||
     * it does not have a network, but instead the network line specifies the same of the server it connects to.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether this portal is a bungee portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isBungee() {
 | 
			
		||||
        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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,118 @@
 | 
			
		||||
package net.knarcraft.stargate.portal.property;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.OfflinePlayer;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The portal owner represents the owner of a portal
 | 
			
		||||
 */
 | 
			
		||||
public class PortalOwner {
 | 
			
		||||
 | 
			
		||||
    private UUID ownerUUID;
 | 
			
		||||
    private String ownerName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new portal owner
 | 
			
		||||
     *
 | 
			
		||||
     * @param ownerIdentifier <p>A UUID, or a username for legacy support</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalOwner(String ownerIdentifier) {
 | 
			
		||||
        parseIdentifier(ownerIdentifier);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new portal owner
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player which is the owner of the portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalOwner(Player player) {
 | 
			
		||||
        this.ownerUUID = player.getUniqueId();
 | 
			
		||||
        this.ownerName = player.getName();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the UUID of this owner
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The UUID of this owner, or null if a UUID is not available</p>
 | 
			
		||||
     */
 | 
			
		||||
    public UUID getUUID() {
 | 
			
		||||
        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
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The name of this owner</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getName() {
 | 
			
		||||
        return ownerName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the one identifier used for saving the owner
 | 
			
		||||
     *
 | 
			
		||||
     * <p>If the UUID is available, a string representation of the UUID will be returned. If not, the owner's name will
 | 
			
		||||
     * be returned.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The owner's identifier</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getIdentifier() {
 | 
			
		||||
        if (ownerUUID != null) {
 | 
			
		||||
            return ownerUUID.toString();
 | 
			
		||||
        } else {
 | 
			
		||||
            return ownerName;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses the identifier of a portal's owner
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The identifier should be a valid UUID, but can be a username of max 16 characters for legacy support. Strings
 | 
			
		||||
     * longer than 16 characters not parse-able as a UUID will silently fail by setting the owner name to the
 | 
			
		||||
     * identifier.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param ownerIdentifier <p>The identifier for a portal's owner</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void parseIdentifier(String ownerIdentifier) {
 | 
			
		||||
        UUID ownerUUID = null;
 | 
			
		||||
        String ownerName;
 | 
			
		||||
        if (ownerIdentifier.length() > 16) {
 | 
			
		||||
            //If more than 16 characters, the string cannot be a username, so it's probably a UUID
 | 
			
		||||
            try {
 | 
			
		||||
                ownerUUID = UUID.fromString(ownerIdentifier);
 | 
			
		||||
                OfflinePlayer offlineOwner = Bukkit.getServer().getOfflinePlayer(ownerUUID);
 | 
			
		||||
                ownerName = offlineOwner.getName();
 | 
			
		||||
            } catch (IllegalArgumentException ex) {
 | 
			
		||||
                //Invalid as UUID and username, so just keep it as owner name and hope the server owner fixes it
 | 
			
		||||
                ownerName = ownerIdentifier;
 | 
			
		||||
                Stargate.debug("loadAllPortals", "Invalid stargate owner string: " + ownerIdentifier);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            //Old username from the pre-UUID times. Just keep it as the owner name
 | 
			
		||||
            ownerName = ownerIdentifier;
 | 
			
		||||
        }
 | 
			
		||||
        this.ownerName = ownerName;
 | 
			
		||||
        this.ownerUUID = ownerUUID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,150 @@
 | 
			
		||||
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
 | 
			
		||||
 *
 | 
			
		||||
 * <p>The portal structure knows which gate type is used, where the real locations of buttons, frames and entrances are
 | 
			
		||||
 * and whether the portal is verified.</p>
 | 
			
		||||
 */
 | 
			
		||||
public class PortalStructure {
 | 
			
		||||
 | 
			
		||||
    private final Portal portal;
 | 
			
		||||
    private final Gate gate;
 | 
			
		||||
    private BlockLocation button;
 | 
			
		||||
    private BlockLocation[] frame;
 | 
			
		||||
    private BlockLocation[] entrances;
 | 
			
		||||
    private boolean verified;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new portal structure
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal <p>The portal whose structure to store</p>
 | 
			
		||||
     * @param gate   <p>The gate type used by this portal structure</p>
 | 
			
		||||
     * @param button <p>The real location of the portal's button</p>
 | 
			
		||||
     */
 | 
			
		||||
    public PortalStructure(Portal portal, Gate gate, BlockLocation button) {
 | 
			
		||||
        this.portal = portal;
 | 
			
		||||
        this.gate = gate;
 | 
			
		||||
        this.verified = false;
 | 
			
		||||
        this.button = button;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the gate used by this portal structure
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The gate used by this portal structure</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Gate getGate() {
 | 
			
		||||
        return gate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the location of this portal's button
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The location of this portal's button</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockLocation getButton() {
 | 
			
		||||
        return button;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the location of this portal's button
 | 
			
		||||
     *
 | 
			
		||||
     * @param button <p>The location of this portal's button</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void setButton(BlockLocation button) {
 | 
			
		||||
        this.button = button;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Verifies that all control blocks in this portal follows its gate template
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>True if all control blocks were verified</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isVerified() {
 | 
			
		||||
        boolean verified = true;
 | 
			
		||||
        if (!Stargate.getGateConfig().verifyPortals()) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        for (RelativeBlockVector control : gate.getLayout().getControls()) {
 | 
			
		||||
            verified = verified && portal.getBlockAt(control).getBlock().getType().equals(gate.getControlBlock());
 | 
			
		||||
        }
 | 
			
		||||
        this.verified = verified;
 | 
			
		||||
        return verified;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the result of the last portal verification
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>True if this portal was verified</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean wasVerified() {
 | 
			
		||||
        if (!Stargate.getGateConfig().verifyPortals()) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return verified;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if all blocks in a gate matches the gate template
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>True if all blocks match the gate template</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean checkIntegrity() {
 | 
			
		||||
        if (Stargate.getGateConfig().verifyPortals()) {
 | 
			
		||||
            return gate.matches(portal.getTopLeft(), portal.getYaw());
 | 
			
		||||
        } else {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a list of block locations from a list of relative block vectors
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The block locations will be calculated by using this portal's top-left block as the origin for the relative
 | 
			
		||||
     * vectors..</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param vectors <p>The relative block vectors to convert</p>
 | 
			
		||||
     * @return <p>A list of block locations</p>
 | 
			
		||||
     */
 | 
			
		||||
    private BlockLocation[] relativeBlockVectorsToBlockLocations(RelativeBlockVector[] vectors) {
 | 
			
		||||
        BlockLocation[] locations = new BlockLocation[vectors.length];
 | 
			
		||||
        for (int i = 0; i < vectors.length; i++) {
 | 
			
		||||
            locations[i] = portal.getBlockAt(vectors[i]);
 | 
			
		||||
        }
 | 
			
		||||
        return locations;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the locations of this portal's entrances
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The locations of this portal's entrances</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockLocation[] getEntrances() {
 | 
			
		||||
        if (entrances == null) {
 | 
			
		||||
            //Get the locations of the entrances once, and only if necessary as it's an expensive operation
 | 
			
		||||
            entrances = relativeBlockVectorsToBlockLocations(gate.getLayout().getEntrances());
 | 
			
		||||
        }
 | 
			
		||||
        return entrances;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the locations of this portal's frame
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The locations of this portal's frame</p>
 | 
			
		||||
     */
 | 
			
		||||
    public BlockLocation[] getFrame() {
 | 
			
		||||
        if (frame == null) {
 | 
			
		||||
            //Get the locations of the frame blocks once, and only if necessary as it's an expensive operation
 | 
			
		||||
            frame = relativeBlockVectorsToBlockLocations(gate.getLayout().getBorder());
 | 
			
		||||
        }
 | 
			
		||||
        return frame;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,356 @@
 | 
			
		||||
package net.knarcraft.stargate.portal.property.gate;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.container.BlockLocation;
 | 
			
		||||
import net.knarcraft.stargate.container.RelativeBlockVector;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedWriter;
 | 
			
		||||
import java.io.FileWriter;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A gate describes the physical structure of a stargate
 | 
			
		||||
 *
 | 
			
		||||
 * <p>While the portal class represents a portal in space, the Gate class represents the physical gate/portal entrance.</p>
 | 
			
		||||
 */
 | 
			
		||||
public class Gate {
 | 
			
		||||
 | 
			
		||||
    private final String filename;
 | 
			
		||||
    private final GateLayout layout;
 | 
			
		||||
    private final Map<Character, Material> characterMaterialMap;
 | 
			
		||||
    //Gate materials
 | 
			
		||||
    private final Material portalOpenBlock;
 | 
			
		||||
    private final Material portalClosedBlock;
 | 
			
		||||
    private final Material portalButton;
 | 
			
		||||
    //Economy information
 | 
			
		||||
    private final int useCost;
 | 
			
		||||
    private final int createCost;
 | 
			
		||||
    private final int destroyCost;
 | 
			
		||||
    private final boolean toOwner;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new gate
 | 
			
		||||
     *
 | 
			
		||||
     * @param filename             <p>The name of the gate file, including extension</p>
 | 
			
		||||
     * @param layout               <p>The gate layout defined in the gate file</p>
 | 
			
		||||
     * @param characterMaterialMap <p>The material types the different layout characters represent</p>
 | 
			
		||||
     * @param portalOpenBlock      <p>The material to set the opening to when the portal is open</p>
 | 
			
		||||
     * @param portalClosedBlock    <p>The material to set the opening to when the portal is closed</p>
 | 
			
		||||
     * @param portalButton         <p>The material to use for the portal button</p>
 | 
			
		||||
     * @param useCost              <p>The cost of using a portal with this gate layout (-1 to disable)</p>
 | 
			
		||||
     * @param createCost           <p>The cost of creating a portal with this gate layout (-1 to disable)</p>
 | 
			
		||||
     * @param destroyCost          <p>The cost of destroying a portal with this gate layout (-1 to disable)</p>
 | 
			
		||||
     * @param toOwner              <p>Whether any payment should go to the owner of the gate, as opposed to just disappearing</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Gate(String filename, GateLayout layout, Map<Character, Material> characterMaterialMap, Material portalOpenBlock,
 | 
			
		||||
                Material portalClosedBlock, Material portalButton, int useCost, int createCost, int destroyCost,
 | 
			
		||||
                boolean toOwner) {
 | 
			
		||||
        this.filename = filename;
 | 
			
		||||
        this.layout = layout;
 | 
			
		||||
        this.characterMaterialMap = characterMaterialMap;
 | 
			
		||||
        this.portalOpenBlock = portalOpenBlock;
 | 
			
		||||
        this.portalClosedBlock = portalClosedBlock;
 | 
			
		||||
        this.portalButton = portalButton;
 | 
			
		||||
        this.useCost = useCost;
 | 
			
		||||
        this.createCost = createCost;
 | 
			
		||||
        this.destroyCost = destroyCost;
 | 
			
		||||
        this.toOwner = toOwner;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets this gate's layout
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>This gate's layout</p>
 | 
			
		||||
     */
 | 
			
		||||
    public GateLayout getLayout() {
 | 
			
		||||
        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
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The material type used for control blocks</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Material getControlBlock() {
 | 
			
		||||
        return characterMaterialMap.get(GateHandler.getControlBlockCharacter());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the filename of this gate's file
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The filename of this gate's file</p>
 | 
			
		||||
     */
 | 
			
		||||
    public String getFilename() {
 | 
			
		||||
        return filename;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the block type to use for the opening when a portal using this gate is open
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The block type to use for the opening when open</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Material getPortalOpenBlock() {
 | 
			
		||||
        return portalOpenBlock;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the block type to use for the opening when a portal using this gate is closed
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The block type to use for the opening when closed</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Material getPortalClosedBlock() {
 | 
			
		||||
        return portalClosedBlock;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the material to use for a portal's button if using this gate type
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The material to use for a portal's button if using this gate type</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Material getPortalButton() {
 | 
			
		||||
        return portalButton;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the cost of using a portal with this gate
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The cost of using a portal with this gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public int getUseCost() {
 | 
			
		||||
        return useCost < 0 ? Stargate.getEconomyConfig().getDefaultUseCost() : useCost;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the cost of creating a portal with this gate
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The cost of creating a portal with this gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Integer getCreateCost() {
 | 
			
		||||
        return createCost < 0 ? Stargate.getEconomyConfig().getDefaultCreateCost() : createCost;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the cost of destroying a portal with this gate
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The cost of destroying a portal with this gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Integer getDestroyCost() {
 | 
			
		||||
        return destroyCost < 0 ? Stargate.getEconomyConfig().getDefaultDestroyCost() : destroyCost;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether portal payments go to this portal's owner
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether portal payments go to the owner</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Boolean getToOwner() {
 | 
			
		||||
        return toOwner;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a portal's gate matches this gate type
 | 
			
		||||
     *
 | 
			
		||||
     * @param topLeft <p>The top-left block of the portal's gate</p>
 | 
			
		||||
     * @param yaw     <p>The yaw when looking directly outwards</p>
 | 
			
		||||
     * @return <p>True if this gate matches the portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean matches(BlockLocation topLeft, double yaw) {
 | 
			
		||||
        return matches(topLeft, yaw, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a portal's gate matches this gate type
 | 
			
		||||
     *
 | 
			
		||||
     * <p>If enabling onCreate, opening blocks with materials AIR and WATER will be allowed even if the gate closed
 | 
			
		||||
     * material is a different one. If checking and onCreate is not enabled, any inconsistency with opening blocks
 | 
			
		||||
     * containing AIR or WATER will cause the gate to not match.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param topLeft  <p>The top-left block of the portal's gate</p>
 | 
			
		||||
     * @param yaw      <p>The yaw when looking directly outwards</p>
 | 
			
		||||
     * @param onCreate <p>Whether this is used in the context of creating a new gate</p>
 | 
			
		||||
     * @return <p>True if this gate matches the portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean matches(BlockLocation topLeft, double yaw, boolean onCreate) {
 | 
			
		||||
        return verifyGateEntrancesMatch(topLeft, yaw, onCreate) && verifyGateBorderMatches(topLeft, yaw);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Verifies that all border blocks of a portal matches this gate type
 | 
			
		||||
     *
 | 
			
		||||
     * @param topLeft <p>The top-left block of the portal</p>
 | 
			
		||||
     * @param yaw     <p>The yaw when looking directly outwards from the portal</p>
 | 
			
		||||
     * @return <p>True if all border blocks of the gate match the layout</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean verifyGateBorderMatches(BlockLocation topLeft, double yaw) {
 | 
			
		||||
        Map<Character, Material> characterMaterialMap = new HashMap<>(this.characterMaterialMap);
 | 
			
		||||
        for (RelativeBlockVector borderVector : layout.getBorder()) {
 | 
			
		||||
            int rowIndex = borderVector.getRight();
 | 
			
		||||
            int lineIndex = borderVector.getDown();
 | 
			
		||||
            Character key = layout.getLayout()[lineIndex][rowIndex];
 | 
			
		||||
 | 
			
		||||
            Material materialInLayout = characterMaterialMap.get(key);
 | 
			
		||||
            Material materialAtLocation = topLeft.getRelativeLocation(borderVector, yaw).getType();
 | 
			
		||||
 | 
			
		||||
            if (materialInLayout == null) {
 | 
			
		||||
                /* This generally should not happen with proper checking, but just in case a material character is not
 | 
			
		||||
                 * recognized, but still allowed in previous checks, verify the gate as long as all such instances of
 | 
			
		||||
                 * the character correspond to the same material in the physical gate. All subsequent gates will also
 | 
			
		||||
                 * need to match the first verified gate. */
 | 
			
		||||
                characterMaterialMap.put(key, materialAtLocation);
 | 
			
		||||
                Stargate.debug("Gate::Matches", String.format("Missing layout material in %s. Using %s from the" +
 | 
			
		||||
                        " physical portal.", getFilename(), materialAtLocation));
 | 
			
		||||
            } else if (materialAtLocation != materialInLayout) {
 | 
			
		||||
                Stargate.debug("Gate::Matches", String.format("Block Type Mismatch: %s != %s",
 | 
			
		||||
                        materialAtLocation, materialInLayout));
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Verifies that all entrances of a portal gate matches this gate type
 | 
			
		||||
     *
 | 
			
		||||
     * @param topLeft  <p>The top-left block of this portal</p>
 | 
			
		||||
     * @param yaw      <p>The yaw when looking directly outwards</p>
 | 
			
		||||
     * @param onCreate <p>Whether this is used in the context of creating a new gate</p>
 | 
			
		||||
     * @return <p>Whether this is used in the context of creating a new gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean verifyGateEntrancesMatch(BlockLocation topLeft, double yaw, boolean onCreate) {
 | 
			
		||||
        Stargate.debug("verifyGateEntrancesMatch", String.valueOf(topLeft));
 | 
			
		||||
        for (RelativeBlockVector entranceVector : layout.getEntrances()) {
 | 
			
		||||
            Stargate.debug("verifyGateEntrancesMatch", String.valueOf(entranceVector));
 | 
			
		||||
            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.isAir() || type == Material.WATER)) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (type != portalClosedBlock && type != portalOpenBlock) {
 | 
			
		||||
                Stargate.debug("Gate::Matches", "Entrance/Exit Material Mismatch: " + type);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Saves this gate to a file
 | 
			
		||||
     *
 | 
			
		||||
     * <p>This method will save the gate to its filename in the given folder.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param gateFolder <p>The folder to save the gate file in</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void save(String gateFolder) {
 | 
			
		||||
        try {
 | 
			
		||||
            BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(gateFolder + filename));
 | 
			
		||||
 | 
			
		||||
            //Save main material names
 | 
			
		||||
            writeConfig(bufferedWriter, "portal-open", portalOpenBlock.name());
 | 
			
		||||
            writeConfig(bufferedWriter, "portal-closed", portalClosedBlock.name());
 | 
			
		||||
            writeConfig(bufferedWriter, "button", portalButton.name());
 | 
			
		||||
 | 
			
		||||
            //Save the values necessary for economy
 | 
			
		||||
            saveEconomyValues(bufferedWriter);
 | 
			
		||||
 | 
			
		||||
            //Store material types to use for frame blocks
 | 
			
		||||
            saveFrameBlockTypes(bufferedWriter);
 | 
			
		||||
 | 
			
		||||
            bufferedWriter.newLine();
 | 
			
		||||
 | 
			
		||||
            //Save the gate layout
 | 
			
		||||
            layout.saveLayout(bufferedWriter);
 | 
			
		||||
 | 
			
		||||
            bufferedWriter.close();
 | 
			
		||||
        } catch (IOException ex) {
 | 
			
		||||
            Stargate.logSevere(String.format("Could not save Gate %s - %s", filename, ex.getMessage()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Saves current economy related values using a buffered writer
 | 
			
		||||
     *
 | 
			
		||||
     * @param bufferedWriter <p>The buffered writer to write to</p>
 | 
			
		||||
     * @throws IOException <p>If unable to write to the buffered writer</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void saveEconomyValues(BufferedWriter bufferedWriter) throws IOException {
 | 
			
		||||
        //Write use cost if not disabled
 | 
			
		||||
        if (useCost != -1) {
 | 
			
		||||
            writeConfig(bufferedWriter, "usecost", useCost);
 | 
			
		||||
        }
 | 
			
		||||
        //Write create cost if not disabled
 | 
			
		||||
        if (createCost != -1) {
 | 
			
		||||
            writeConfig(bufferedWriter, "createcost", createCost);
 | 
			
		||||
        }
 | 
			
		||||
        //Write destroy cost if not disabled
 | 
			
		||||
        if (destroyCost != -1) {
 | 
			
		||||
            writeConfig(bufferedWriter, "destroycost", destroyCost);
 | 
			
		||||
        }
 | 
			
		||||
        writeConfig(bufferedWriter, "toowner", toOwner);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Saves the types of blocks used for the gate frame/border using a buffered writer
 | 
			
		||||
     *
 | 
			
		||||
     * @param bufferedWriter <p>The buffered writer to write to</p>
 | 
			
		||||
     * @throws IOException <p>If unable to write to the buffered writer</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void saveFrameBlockTypes(BufferedWriter bufferedWriter) throws IOException {
 | 
			
		||||
        for (Map.Entry<Character, Material> entry : characterMaterialMap.entrySet()) {
 | 
			
		||||
            Character type = entry.getKey();
 | 
			
		||||
            Material value = entry.getValue();
 | 
			
		||||
            //Skip characters not part of the frame
 | 
			
		||||
            if (type.equals(GateHandler.getAnythingCharacter()) ||
 | 
			
		||||
                    type.equals(GateHandler.getEntranceCharacter()) ||
 | 
			
		||||
                    type.equals(GateHandler.getExitCharacter())) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            bufferedWriter.append(type);
 | 
			
		||||
            bufferedWriter.append('=');
 | 
			
		||||
            if (value != null) {
 | 
			
		||||
                bufferedWriter.append(value.toString());
 | 
			
		||||
            }
 | 
			
		||||
            bufferedWriter.newLine();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Writes a formatted string to a buffered writer
 | 
			
		||||
     *
 | 
			
		||||
     * @param bufferedWriter <p>The buffered writer to write the formatted string to</p>
 | 
			
		||||
     * @param key            <p>The config key to save</p>
 | 
			
		||||
     * @param value          <p>The config value to save</p>
 | 
			
		||||
     * @throws IOException <p>If unable to write to the buffered writer</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void writeConfig(BufferedWriter bufferedWriter, String key, Object value) throws IOException {
 | 
			
		||||
        //Figure out the correct formatting to use
 | 
			
		||||
        String format = "%s=";
 | 
			
		||||
        if (value instanceof Boolean) {
 | 
			
		||||
            format += "%b";
 | 
			
		||||
        } else if (value instanceof Integer) {
 | 
			
		||||
            format += "%d";
 | 
			
		||||
        } else if (value instanceof String) {
 | 
			
		||||
            format += "%s";
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new IllegalArgumentException("Unrecognized config value type");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bufferedWriter.append(String.format(format, key, value));
 | 
			
		||||
        bufferedWriter.newLine();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,347 @@
 | 
			
		||||
package net.knarcraft.stargate.portal.property.gate;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.utility.GateReader;
 | 
			
		||||
import net.knarcraft.stargate.utility.MaterialHelper;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
import org.bukkit.block.Block;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Scanner;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static net.knarcraft.stargate.utility.GateReader.generateLayoutMatrix;
 | 
			
		||||
import static net.knarcraft.stargate.utility.GateReader.readGateConfig;
 | 
			
		||||
import static net.knarcraft.stargate.utility.GateReader.readGateFile;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The gate handler keeps track of all gates
 | 
			
		||||
 */
 | 
			
		||||
public class GateHandler {
 | 
			
		||||
 | 
			
		||||
    private static final Character ANYTHING = ' ';
 | 
			
		||||
    private static final Character ENTRANCE = '.';
 | 
			
		||||
    private static final Character EXIT = '*';
 | 
			
		||||
    private static final Character CONTROL_BLOCK = '-';
 | 
			
		||||
 | 
			
		||||
    private static final Material defaultPortalBlockOpen = Material.NETHER_PORTAL;
 | 
			
		||||
    private static final Material defaultPortalBlockClosed = Material.AIR;
 | 
			
		||||
    private static final Material defaultButton = Material.STONE_BUTTON;
 | 
			
		||||
 | 
			
		||||
    private static final HashMap<String, Gate> gates = new HashMap<>();
 | 
			
		||||
    private static final HashMap<Material, List<Gate>> controlBlocks = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    private GateHandler() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the character used for blocks that are not part of the gate
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The character used for blocks that are not part of the gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Character getAnythingCharacter() {
 | 
			
		||||
        return ANYTHING;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the character used for defining the entrance
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The character used for defining the entrance</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Character getEntranceCharacter() {
 | 
			
		||||
        return ENTRANCE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the character used for defining the exit
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The character used for defining the exit</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Character getExitCharacter() {
 | 
			
		||||
        return EXIT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the character used for defining control blocks
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The character used for defining control blocks</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Character getControlBlockCharacter() {
 | 
			
		||||
        return CONTROL_BLOCK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Register a gate into the list of available gates
 | 
			
		||||
     *
 | 
			
		||||
     * @param gate <p>The gate to register</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void registerGate(Gate gate) {
 | 
			
		||||
        gates.put(gate.getFilename(), gate);
 | 
			
		||||
 | 
			
		||||
        Material blockID = gate.getControlBlock();
 | 
			
		||||
 | 
			
		||||
        if (!controlBlocks.containsKey(blockID)) {
 | 
			
		||||
            controlBlocks.put(blockID, new ArrayList<>());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        controlBlocks.get(blockID).add(gate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads a gate from a file
 | 
			
		||||
     *
 | 
			
		||||
     * @param file <p>The file containing the gate data</p>
 | 
			
		||||
     * @return <p>The loaded gate, or null if unable to load the gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static Gate loadGate(File file) {
 | 
			
		||||
        try (Scanner scanner = new Scanner(file)) {
 | 
			
		||||
            return loadGate(file.getName(), file.getParent(), scanner);
 | 
			
		||||
        } catch (Exception exception) {
 | 
			
		||||
            Stargate.logSevere(String.format("Could not load Gate %s - %s", file.getName(), exception.getMessage()));
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads a gate from a file
 | 
			
		||||
     *
 | 
			
		||||
     * @param fileName     <p>The name of the file containing the gate data</p>
 | 
			
		||||
     * @param parentFolder <p>The parent folder of the gate data file</p>
 | 
			
		||||
     * @param scanner      <p>The scanner to use for reading the gate data</p>
 | 
			
		||||
     * @return <p>The loaded gate or null if unable to load the gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static Gate loadGate(String fileName, String parentFolder, Scanner scanner) {
 | 
			
		||||
        List<List<Character>> design = new ArrayList<>();
 | 
			
		||||
        Map<Character, Material> characterMaterialMap = new HashMap<>();
 | 
			
		||||
        Map<String, String> config = new HashMap<>();
 | 
			
		||||
        Set<Material> frameTypes = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
        //Initialize character to material map
 | 
			
		||||
        characterMaterialMap.put(ENTRANCE, Material.AIR);
 | 
			
		||||
        characterMaterialMap.put(EXIT, Material.AIR);
 | 
			
		||||
        characterMaterialMap.put(ANYTHING, Material.AIR);
 | 
			
		||||
 | 
			
		||||
        //Read the file into appropriate lists and maps
 | 
			
		||||
        int columns = readGateFile(scanner, characterMaterialMap, fileName, design, frameTypes, config);
 | 
			
		||||
        if (columns < 0) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        Character[][] layout = generateLayoutMatrix(design, columns);
 | 
			
		||||
 | 
			
		||||
        //Create and validate the new gate
 | 
			
		||||
        Gate gate = createGate(config, fileName, layout, characterMaterialMap);
 | 
			
		||||
        if (gate == null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Update gate file in case the format has changed between versions
 | 
			
		||||
        gate.save(parentFolder + "/");
 | 
			
		||||
        return gate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new gate
 | 
			
		||||
     *
 | 
			
		||||
     * @param config               <p>The config map to get configuration values from</p>
 | 
			
		||||
     * @param fileName             <p>The name of the saved gate config file</p>
 | 
			
		||||
     * @param layout               <p>The layout matrix of the new gate</p>
 | 
			
		||||
     * @param characterMaterialMap <p>A map between layout characters and the material to use</p>
 | 
			
		||||
     * @return <p>A new gate, or null if the config is invalid</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static Gate createGate(Map<String, String> config, String fileName, Character[][] layout,
 | 
			
		||||
                                   Map<Character, Material> characterMaterialMap) {
 | 
			
		||||
        //Read relevant material types
 | 
			
		||||
        Material portalOpenBlock = readGateConfig(config, fileName, "portal-open", defaultPortalBlockOpen);
 | 
			
		||||
        Material portalClosedBlock = readGateConfig(config, fileName, "portal-closed", defaultPortalBlockClosed);
 | 
			
		||||
        Material portalButton = readGateConfig(config, fileName, "button", defaultButton);
 | 
			
		||||
 | 
			
		||||
        //Read economy values
 | 
			
		||||
        int useCost = GateReader.readGateConfig(config, fileName, "usecost");
 | 
			
		||||
        int createCost = GateReader.readGateConfig(config, fileName, "createcost");
 | 
			
		||||
        int destroyCost = GateReader.readGateConfig(config, fileName, "destroycost");
 | 
			
		||||
        boolean toOwner = (config.containsKey("toowner") ? Boolean.parseBoolean(config.get("toowner")) :
 | 
			
		||||
                Stargate.getEconomyConfig().sendPaymentToOwner());
 | 
			
		||||
 | 
			
		||||
        //Create the new gate
 | 
			
		||||
        Gate gate = new Gate(fileName, new GateLayout(layout), characterMaterialMap, portalOpenBlock, portalClosedBlock,
 | 
			
		||||
                portalButton, useCost, createCost, destroyCost, toOwner);
 | 
			
		||||
 | 
			
		||||
        if (!validateGate(gate, fileName)) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return gate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Validates that a gate is valid
 | 
			
		||||
     *
 | 
			
		||||
     * @param gate     <p>The gate to validate</p>
 | 
			
		||||
     * @param fileName <p>The filename of the loaded gate file</p>
 | 
			
		||||
     * @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(failString, "Gates must have exactly 2 control points."));
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!MaterialHelper.isButtonCompatible(gate.getPortalButton())) {
 | 
			
		||||
            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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads all gates inside the given folder
 | 
			
		||||
     *
 | 
			
		||||
     * @param gateFolder <p>The folder containing the gates</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void loadGates(String gateFolder) {
 | 
			
		||||
        File directory = new File(gateFolder);
 | 
			
		||||
        File[] files;
 | 
			
		||||
 | 
			
		||||
        if (directory.exists()) {
 | 
			
		||||
            //Get all files with a .gate extension
 | 
			
		||||
            files = directory.listFiles((file) -> file.isFile() && file.getName().endsWith(".gate"));
 | 
			
		||||
        } else {
 | 
			
		||||
            //Set files to empty list to signal that default gates need to be copied
 | 
			
		||||
            files = new File[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (files == null || files.length == 0) {
 | 
			
		||||
            //The gates-folder was not found. Assume this is the first run
 | 
			
		||||
            if (directory.mkdir()) {
 | 
			
		||||
                writeDefaultGatesToFolder(gateFolder);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            //Load and register the corresponding gate for each file
 | 
			
		||||
            for (File file : files) {
 | 
			
		||||
                Gate gate = loadGate(file);
 | 
			
		||||
                if (gate != null) {
 | 
			
		||||
                    registerGate(gate);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Writes the default gates to the given folder
 | 
			
		||||
     *
 | 
			
		||||
     * @param gateFolder <p>The folder containing gate config files</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void writeDefaultGatesToFolder(String gateFolder) {
 | 
			
		||||
        loadGateFromJar("nethergate.gate", gateFolder);
 | 
			
		||||
        loadGateFromJar("watergate.gate", gateFolder);
 | 
			
		||||
        loadGateFromJar("endgate.gate", gateFolder);
 | 
			
		||||
        loadGateFromJar("squarenetherglowstonegate.gate", gateFolder);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads the given gate file from within the Jar's resources directory
 | 
			
		||||
     *
 | 
			
		||||
     * @param gateFile   <p>The name of the gate file</p>
 | 
			
		||||
     * @param gateFolder <p>The folder containing gates</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void loadGateFromJar(String gateFile, String gateFolder) {
 | 
			
		||||
        //Get an input stream for the internal file
 | 
			
		||||
        InputStream gateFileStream = Gate.class.getResourceAsStream("/gates/" + gateFile);
 | 
			
		||||
        if (gateFileStream != null) {
 | 
			
		||||
            Scanner scanner = new Scanner(gateFileStream);
 | 
			
		||||
            //Load and register the gate
 | 
			
		||||
            Gate gate = loadGate(gateFile, gateFolder, scanner);
 | 
			
		||||
            if (gate != null) {
 | 
			
		||||
                registerGate(gate);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the gates with the given control block
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The control block is the block type where the sign should be placed. It is used to decide whether a user
 | 
			
		||||
     * is creating a new portal.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param block <p>The control block to check</p>
 | 
			
		||||
     * @return <p>A list of gates using the given control block</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Gate[] getGatesByControlBlock(Block block) {
 | 
			
		||||
        return getGatesByControlBlock(block.getType());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the gates with the given control block
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The control block is the block type where the sign should be placed. It is used to decide whether a user
 | 
			
		||||
     * is creating a new portal.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param type <p>The type of the control block to check</p>
 | 
			
		||||
     * @return <p>A list of gates using the given material for control block</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Gate[] getGatesByControlBlock(Material type) {
 | 
			
		||||
        Gate[] result = new Gate[0];
 | 
			
		||||
        List<Gate> lookup = controlBlocks.get(type);
 | 
			
		||||
 | 
			
		||||
        if (lookup != null) {
 | 
			
		||||
            result = lookup.toArray(result);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a portal given its filename
 | 
			
		||||
     *
 | 
			
		||||
     * @param fileName <p>The filename of the gate to get</p>
 | 
			
		||||
     * @return <p>The gate with the given filename</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Gate getGateByName(String fileName) {
 | 
			
		||||
        return gates.get(fileName);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the number of loaded gate configurations
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The number of loaded gate configurations</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static int getGateCount() {
 | 
			
		||||
        return gates.size();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clears all loaded gates and control blocks
 | 
			
		||||
     */
 | 
			
		||||
    public static void clearGates() {
 | 
			
		||||
        gates.clear();
 | 
			
		||||
        controlBlocks.clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,209 @@
 | 
			
		||||
package net.knarcraft.stargate.portal.property.gate;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.container.RelativeBlockVector;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedWriter;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The gate layout describes where every part of the gate should be
 | 
			
		||||
 *
 | 
			
		||||
 * <p>The gate layout parses a layout described by a Character matrix and stores the different parts of the gate as
 | 
			
		||||
 * relative block vectors. All relative vectors has an origin in the top-left block when looking at the gate's front
 | 
			
		||||
 * (the side with the sign). The origin of the relative vectors can also be seen as 0,0 in the character matrix.</p>
 | 
			
		||||
 */
 | 
			
		||||
public class GateLayout {
 | 
			
		||||
 | 
			
		||||
    private final Character[][] layout;
 | 
			
		||||
    private final List<RelativeBlockVector> exits = new ArrayList<>();
 | 
			
		||||
    private RelativeBlockVector[] entrances = new RelativeBlockVector[0];
 | 
			
		||||
    private RelativeBlockVector[] border = new RelativeBlockVector[0];
 | 
			
		||||
    private RelativeBlockVector[] controls = new RelativeBlockVector[0];
 | 
			
		||||
    private RelativeBlockVector exitBlock = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new gate layout
 | 
			
		||||
     *
 | 
			
		||||
     * @param layout <p>A character matrix describing the layout</p>
 | 
			
		||||
     */
 | 
			
		||||
    public GateLayout(Character[][] layout) {
 | 
			
		||||
        this.layout = layout;
 | 
			
		||||
        readLayout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the character array describing this layout
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The character array describing this layout</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Character[][] getLayout() {
 | 
			
		||||
        return this.layout;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the locations of all entrances for this gate
 | 
			
		||||
     *
 | 
			
		||||
     * <p>Entrances contain both the portal entrance blocks and the portal exit blocks.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The locations of entrances for this gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public RelativeBlockVector[] getEntrances() {
 | 
			
		||||
        return entrances;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the locations of border blocks for the gate described by this layout
 | 
			
		||||
     *
 | 
			
		||||
     * <p>A border block is basically any block of the frame. In terms of the nether gate, the border blocks are every
 | 
			
		||||
     * block of the gate that's not air when the gate is closed. The sign and button are not border blocks.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The locations of border blocks for this gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public RelativeBlockVector[] getBorder() {
 | 
			
		||||
        return border;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the exit block defined in the layout
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The exit block defined in the layout</p>
 | 
			
		||||
     */
 | 
			
		||||
    public RelativeBlockVector getExit() {
 | 
			
		||||
        return exitBlock;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets all possible exit locations defined in the layout
 | 
			
		||||
     *
 | 
			
		||||
     * <p>This returns all blocks usable as exits. This basically means it returns the lowest block in each opening of
 | 
			
		||||
     * the gate layout.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>All possible exits</p>
 | 
			
		||||
     */
 | 
			
		||||
    public List<RelativeBlockVector> getExits() {
 | 
			
		||||
        return exits;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the locations of the control blocks for this gate
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The control blocks are the blocks where a sign can be placed to create a portal. The control block without a
 | 
			
		||||
     * sign will be used for the button if necessary. There will always be exactly two control blocks.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The locations of the control blocks for this gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public RelativeBlockVector[] getControls() {
 | 
			
		||||
        return controls;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Saves the gate layout using a buffered writer
 | 
			
		||||
     *
 | 
			
		||||
     * @param bufferedWriter <p>The buffered writer to write to</p>
 | 
			
		||||
     * @throws IOException <p>If unable to write to the buffered writer</p>
 | 
			
		||||
     */
 | 
			
		||||
    public void saveLayout(BufferedWriter bufferedWriter) throws IOException {
 | 
			
		||||
        for (Character[] line : this.layout) {
 | 
			
		||||
            for (Character character : line) {
 | 
			
		||||
                bufferedWriter.append(character);
 | 
			
		||||
            }
 | 
			
		||||
            bufferedWriter.newLine();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads the layout and stores key information
 | 
			
		||||
     *
 | 
			
		||||
     * <p>This methods reads the layout and stores exits, entrances, border blocks and control blocks.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void readLayout() {
 | 
			
		||||
        List<RelativeBlockVector> entranceList = new ArrayList<>();
 | 
			
		||||
        List<RelativeBlockVector> borderList = new ArrayList<>();
 | 
			
		||||
        List<RelativeBlockVector> controlList = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        readLayout(controlList, entranceList, borderList);
 | 
			
		||||
 | 
			
		||||
        this.entrances = entranceList.toArray(this.entrances);
 | 
			
		||||
        this.border = borderList.toArray(this.border);
 | 
			
		||||
        this.controls = controlList.toArray(this.controls);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads the given layout matrix, filling in the given lists of relative block vectors
 | 
			
		||||
     *
 | 
			
		||||
     * @param controlList  <p>The list of control blocks to save to</p>
 | 
			
		||||
     * @param entranceList <p>The list of entrances to save to</p>
 | 
			
		||||
     * @param borderList   <p>The list of border blocks to save to</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void readLayout(List<RelativeBlockVector> controlList, List<RelativeBlockVector> entranceList,
 | 
			
		||||
                            List<RelativeBlockVector> borderList) {
 | 
			
		||||
        //Store the lowest opening for each column
 | 
			
		||||
        int[] exitDepths = new int[layout[0].length];
 | 
			
		||||
 | 
			
		||||
        //A row is the same as one line in the gate file
 | 
			
		||||
        int lineCount = layout.length;
 | 
			
		||||
        for (int rowIndex = 0; rowIndex < lineCount; rowIndex++) {
 | 
			
		||||
            Character[] row = layout[rowIndex];
 | 
			
		||||
            int rowSize = row.length;
 | 
			
		||||
            for (int columnIndex = 0; columnIndex < rowSize; columnIndex++) {
 | 
			
		||||
                Character key = row[columnIndex];
 | 
			
		||||
                parseLayoutCharacter(key, columnIndex, rowIndex, exitDepths, controlList, entranceList, borderList);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Generate all possible exits
 | 
			
		||||
        for (int x = 0; x < exitDepths.length; x++) {
 | 
			
		||||
            //Ignore invalid exits
 | 
			
		||||
            if (exitDepths[x] > 0) {
 | 
			
		||||
                this.exits.add(new RelativeBlockVector(x, exitDepths[x], 0));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses one character of the layout
 | 
			
		||||
     *
 | 
			
		||||
     * @param key          <p>The read character</p>
 | 
			
		||||
     * @param columnIndex  <p>The column containing the read character</p>
 | 
			
		||||
     * @param rowIndex     <p>The row containing the read character</p>
 | 
			
		||||
     * @param exitDepths   <p>The list of exit depths to save to</p>
 | 
			
		||||
     * @param controlList  <p>The list of control blocks to save to</p>
 | 
			
		||||
     * @param entranceList <p>The list of entrances to save to</p>
 | 
			
		||||
     * @param borderList   <p>The list of border blocks to save to</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void parseLayoutCharacter(Character key, int columnIndex, int rowIndex, int[] exitDepths,
 | 
			
		||||
                                      List<RelativeBlockVector> controlList, List<RelativeBlockVector> entranceList,
 | 
			
		||||
                                      List<RelativeBlockVector> borderList) {
 | 
			
		||||
        //Add control blocks to the control block list
 | 
			
		||||
        if (key.equals(GateHandler.getControlBlockCharacter())) {
 | 
			
		||||
            controlList.add(new RelativeBlockVector(columnIndex, rowIndex, 0));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isOpening(key)) {
 | 
			
		||||
            //Register entrance
 | 
			
		||||
            entranceList.add(new RelativeBlockVector(columnIndex, rowIndex, 0));
 | 
			
		||||
            //Overwrite the lowest exit location for this column/x-coordinate
 | 
			
		||||
            exitDepths[columnIndex] = rowIndex;
 | 
			
		||||
            //Register exit if found
 | 
			
		||||
            if (key.equals(GateHandler.getExitCharacter())) {
 | 
			
		||||
                this.exitBlock = new RelativeBlockVector(columnIndex, rowIndex, 0);
 | 
			
		||||
            }
 | 
			
		||||
        } else if (!key.equals(GateHandler.getAnythingCharacter())) {
 | 
			
		||||
            //Register border block
 | 
			
		||||
            borderList.add(new RelativeBlockVector(columnIndex, rowIndex, 0));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the given character represents a gate opening
 | 
			
		||||
     *
 | 
			
		||||
     * @param character <p>The character to check</p>
 | 
			
		||||
     * @return <p>True if the character represents an opening</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isOpening(Character character) {
 | 
			
		||||
        return character.equals(GateHandler.getEntranceCharacter()) || character.equals(GateHandler.getExitCharacter());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,319 @@
 | 
			
		||||
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;
 | 
			
		||||
import org.bukkit.block.data.Bisected;
 | 
			
		||||
import org.bukkit.block.data.BlockData;
 | 
			
		||||
import org.bukkit.block.data.type.Slab;
 | 
			
		||||
import org.bukkit.entity.AbstractHorse;
 | 
			
		||||
import org.bukkit.entity.Entity;
 | 
			
		||||
import org.bukkit.event.Event;
 | 
			
		||||
import org.bukkit.scheduler.BukkitScheduler;
 | 
			
		||||
import org.bukkit.util.Vector;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The portal teleporter takes care of common teleportation logic
 | 
			
		||||
 */
 | 
			
		||||
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 teleportedEntity <p>The entity teleported by this teleporter</p>
 | 
			
		||||
     */
 | 
			
		||||
    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 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.setDirection(DirectionHelper.getDirectionVectorFromYaw(newYaw));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads the chunks outside the portal's entrance
 | 
			
		||||
     */
 | 
			
		||||
    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));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adjusts the positioning of the portal exit to prevent the given entity from suffocating
 | 
			
		||||
     *
 | 
			
		||||
     * @param relativeExit <p>The relative exit defined as the portal's exit</p>
 | 
			
		||||
     * @param exitLocation <p>The currently calculated portal exit</p>
 | 
			
		||||
     * @param entity       <p>The travelling entity</p>
 | 
			
		||||
     * @return <p>A location which won't suffocate the entity inside the portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    private Location preventExitSuffocation(RelativeBlockVector relativeExit, Location exitLocation, Entity entity) {
 | 
			
		||||
        //Go left to find start of opening
 | 
			
		||||
        RelativeBlockVector openingLeft = getPortalExitEdge(relativeExit, -1);
 | 
			
		||||
 | 
			
		||||
        //Go right to find the end of the opening
 | 
			
		||||
        RelativeBlockVector openingRight = getPortalExitEdge(relativeExit, 1);
 | 
			
		||||
 | 
			
		||||
        //Get the width to check if the entity fits
 | 
			
		||||
        int openingWidth = openingRight.getRight() - openingLeft.getRight() + 1;
 | 
			
		||||
        int existingOffset = relativeExit.getRight() - openingLeft.getRight();
 | 
			
		||||
        double newOffset = (openingWidth - existingOffset) / 2D;
 | 
			
		||||
 | 
			
		||||
        //Remove the half offset for better centering
 | 
			
		||||
        if (openingWidth > 1) {
 | 
			
		||||
            newOffset -= 0.5;
 | 
			
		||||
        }
 | 
			
		||||
        exitLocation = DirectionHelper.moveLocation(exitLocation, newOffset, 0, 0, portal.getYaw());
 | 
			
		||||
 | 
			
		||||
        //Move large entities further from the portal
 | 
			
		||||
        return moveExitLocationOutwards(exitLocation, entity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Moves the exit location out from the portal to prevent the entity from entering a teleportation loop
 | 
			
		||||
     *
 | 
			
		||||
     * @param exitLocation <p>The current exit location to adjust</p>
 | 
			
		||||
     * @param entity       <p>The entity to adjust the exit location for</p>
 | 
			
		||||
     * @return <p>The adjusted exit location</p>
 | 
			
		||||
     */
 | 
			
		||||
    private Location moveExitLocationOutwards(Location exitLocation, Entity entity) {
 | 
			
		||||
        double entitySize = EntityHelper.getEntityMaxSize(entity);
 | 
			
		||||
        int entityBoxSize = EntityHelper.getEntityMaxSizeInt(entity);
 | 
			
		||||
        if (entitySize > 1) {
 | 
			
		||||
            double entityOffset;
 | 
			
		||||
            if (portal.getOptions().isAlwaysOn()) {
 | 
			
		||||
                entityOffset = (entityBoxSize / 2D);
 | 
			
		||||
            } else {
 | 
			
		||||
                entityOffset = (entitySize / 2D) - 1;
 | 
			
		||||
            }
 | 
			
		||||
            //If a horse has a player riding it, the player will spawn inside the roof of a standard portal unless it's 
 | 
			
		||||
            // moved one block out.
 | 
			
		||||
            if (entity instanceof AbstractHorse) {
 | 
			
		||||
                entityOffset += 1;
 | 
			
		||||
            }
 | 
			
		||||
            exitLocation = DirectionHelper.moveLocation(exitLocation, 0, 0, entityOffset, portal.getYaw());
 | 
			
		||||
        }
 | 
			
		||||
        return exitLocation;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets one of the edges of a portal's opening/exit
 | 
			
		||||
     *
 | 
			
		||||
     * @param relativeExit <p>The known exit to start from</p>
 | 
			
		||||
     * @param direction    <p>The direction to move (+1 for right, -1 for left)</p>
 | 
			
		||||
     * @return <p>The right or left edge of the opening</p>
 | 
			
		||||
     */
 | 
			
		||||
    private RelativeBlockVector getPortalExitEdge(RelativeBlockVector relativeExit, int direction) {
 | 
			
		||||
        RelativeBlockVector openingEdge = relativeExit;
 | 
			
		||||
 | 
			
		||||
        do {
 | 
			
		||||
            RelativeBlockVector possibleOpening = new RelativeBlockVector(openingEdge.getRight() + direction,
 | 
			
		||||
                    openingEdge.getDown(), openingEdge.getOut());
 | 
			
		||||
            if (portal.getGate().getLayout().getExits().contains(possibleOpening)) {
 | 
			
		||||
                openingEdge = possibleOpening;
 | 
			
		||||
            } else {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        } while (true);
 | 
			
		||||
 | 
			
		||||
        return openingEdge;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adjusts an exit location by setting pitch and adjusting height
 | 
			
		||||
     *
 | 
			
		||||
     * <p>If the exit location is a slab or water, the exit location will be changed to arrive one block above. The
 | 
			
		||||
     * 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 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 adjustExitLocationHeight(Entity entity, Location exitLocation) {
 | 
			
		||||
        if (exitLocation != null) {
 | 
			
		||||
            BlockData blockData = exitLocation.getBlock().getBlockData();
 | 
			
		||||
            if ((blockData instanceof Bisected bisected && bisected.getHalf() == Bisected.Half.BOTTOM) ||
 | 
			
		||||
                    (blockData instanceof Slab slab && slab.getType() == Slab.Type.BOTTOM) ||
 | 
			
		||||
                    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);
 | 
			
		||||
            }
 | 
			
		||||
            return exitLocation;
 | 
			
		||||
        } else {
 | 
			
		||||
            Stargate.logWarning("Unable to generate exit location");
 | 
			
		||||
            return entity.getLocation();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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>
 | 
			
		||||
     */
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets all relevant chunks near this teleporter's portal's entrance which need to be loaded before teleportation
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A list of chunks to load</p>
 | 
			
		||||
     */
 | 
			
		||||
    private List<Chunk> getChunksToLoad() {
 | 
			
		||||
        List<Chunk> chunksToLoad = new ArrayList<>();
 | 
			
		||||
        for (RelativeBlockVector vector : portal.getGate().getLayout().getEntrances()) {
 | 
			
		||||
            BlockLocation entranceLocation = portal.getBlockAt(vector);
 | 
			
		||||
            Chunk chunk = entranceLocation.getChunk();
 | 
			
		||||
            //Make sure not to load chunks twice
 | 
			
		||||
            if (!chunksToLoad.contains(chunk)) {
 | 
			
		||||
                chunksToLoad.add(chunk);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Get the chunk in front of the gate entrance
 | 
			
		||||
            int blockOffset = portal.getOptions().isBackwards() ? -5 : 5;
 | 
			
		||||
            Location fiveBlocksForward = DirectionHelper.moveLocation(entranceLocation, 0, 0, blockOffset,
 | 
			
		||||
                    portal.getYaw());
 | 
			
		||||
            //Load the chunk five blocks forward to make sure the teleported entity will never spawn in unloaded chunks
 | 
			
		||||
            Chunk forwardChunk = fiveBlocksForward.getChunk();
 | 
			
		||||
            if (!chunksToLoad.contains(forwardChunk)) {
 | 
			
		||||
                chunksToLoad.add(forwardChunk);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return chunksToLoad;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,83 @@
 | 
			
		||||
package net.knarcraft.stargate.thread;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.container.BlockChangeRequest;
 | 
			
		||||
import org.bukkit.Axis;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
import org.bukkit.World;
 | 
			
		||||
import org.bukkit.block.Block;
 | 
			
		||||
import org.bukkit.block.EndGateway;
 | 
			
		||||
import org.bukkit.block.data.Orientable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This thread changes gate blocks to display a gate as open or closed
 | 
			
		||||
 *
 | 
			
		||||
 * <p>This thread fetches some entries from blockPopulateQueue each time it's called.</p>
 | 
			
		||||
 */
 | 
			
		||||
public class BlockChangeThread implements Runnable {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void run() {
 | 
			
		||||
        long sTime = System.nanoTime();
 | 
			
		||||
        //Repeat for at most 0.025 seconds
 | 
			
		||||
        while (System.nanoTime() - sTime < 25000000) {
 | 
			
		||||
            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 boolean pollQueue() {
 | 
			
		||||
        //Abort if there's no work to be done
 | 
			
		||||
        BlockChangeRequest blockChangeRequest = Stargate.getBlockChangeRequestQueue().poll();
 | 
			
		||||
        if (blockChangeRequest == null) {
 | 
			
		||||
            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) {
 | 
			
		||||
            //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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Prevents end gateway portal from behaving strangely
 | 
			
		||||
     *
 | 
			
		||||
     * @param block <p>The block to fix</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void fixEndGatewayGate(Block block) {
 | 
			
		||||
        EndGateway gateway = (EndGateway) block.getState();
 | 
			
		||||
        gateway.setAge(Long.MIN_VALUE);
 | 
			
		||||
        if (block.getWorld().getEnvironment() == World.Environment.THE_END) {
 | 
			
		||||
            gateway.setExitLocation(block.getLocation());
 | 
			
		||||
            gateway.setExactTeleport(true);
 | 
			
		||||
        }
 | 
			
		||||
        gateway.update(false, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the orientation axis of the placed block
 | 
			
		||||
     *
 | 
			
		||||
     * @param block <p>The block to orient</p>
 | 
			
		||||
     * @param axis  <p>The axis to use for orienting the block</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void orientBlock(Block block, Axis axis) {
 | 
			
		||||
        Orientable orientable = (Orientable) block.getBlockData();
 | 
			
		||||
        orientable.setAxis(axis);
 | 
			
		||||
        block.setBlockData(orientable);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
package net.knarcraft.stargate.thread;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.container.ChunkUnloadRequest;
 | 
			
		||||
import org.bukkit.Chunk;
 | 
			
		||||
 | 
			
		||||
import java.util.Queue;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Unloads chunks which should no longer be forced to stay loaded
 | 
			
		||||
 */
 | 
			
		||||
public class ChunkUnloadThread implements Runnable {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void run() {
 | 
			
		||||
        long systemNanoTime = System.nanoTime();
 | 
			
		||||
        Queue<ChunkUnloadRequest> unloadQueue = Stargate.getChunkUnloadQueue();
 | 
			
		||||
 | 
			
		||||
        //Peek at the first element to check if the chunk should be unloaded
 | 
			
		||||
        ChunkUnloadRequest firstElement = unloadQueue.peek();
 | 
			
		||||
        //Repeat until all un-loadable chunks have been processed
 | 
			
		||||
        while (firstElement != null && firstElement.getUnloadNanoTime() < systemNanoTime) {
 | 
			
		||||
            unloadQueue.remove();
 | 
			
		||||
            Chunk chunkToUnload = firstElement.getChunkToUnload();
 | 
			
		||||
            //Allow the chunk to be unloaded
 | 
			
		||||
            chunkToUnload.removePluginChunkTicket(Stargate.getInstance());
 | 
			
		||||
            firstElement = unloadQueue.peek();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,66 @@
 | 
			
		||||
package net.knarcraft.stargate.thread;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Queue;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class contains the function used to close servers which should no longer be open/active
 | 
			
		||||
 */
 | 
			
		||||
public class StarGateThread implements Runnable {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void run() {
 | 
			
		||||
        long time = System.currentTimeMillis() / 1000;
 | 
			
		||||
        closeOpenPortals(time);
 | 
			
		||||
        deactivateActivePortals(time);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes portals which are open and have timed out
 | 
			
		||||
     *
 | 
			
		||||
     * @param time <p>The current time</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void closeOpenPortals(long time) {
 | 
			
		||||
        List<Portal> closedPortals = new ArrayList<>();
 | 
			
		||||
        Queue<Portal> openPortalsQueue = Stargate.getStargateConfig().getOpenPortalsQueue();
 | 
			
		||||
 | 
			
		||||
        for (Portal portal : openPortalsQueue) {
 | 
			
		||||
            //Skip always open and non-open gates
 | 
			
		||||
            if (portal.getOptions().isAlwaysOn() || !portal.isOpen()) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            if (time > portal.getTriggeredTime() + Stargate.getGateConfig().getOpenTime()) {
 | 
			
		||||
                portal.getPortalOpener().closePortal(false);
 | 
			
		||||
                closedPortals.add(portal);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        openPortalsQueue.removeAll(closedPortals);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * De-activates portals which are active and have timed out
 | 
			
		||||
     *
 | 
			
		||||
     * @param time <p>The current time</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void deactivateActivePortals(long time) {
 | 
			
		||||
        List<Portal> deactivatedPortals = new ArrayList<>();
 | 
			
		||||
        Queue<Portal> activePortalsQueue = Stargate.getStargateConfig().getActivePortalsQueue();
 | 
			
		||||
 | 
			
		||||
        for (Portal portal : activePortalsQueue) {
 | 
			
		||||
            //Skip portals which aren't active
 | 
			
		||||
            if (!portal.getPortalActivator().isActive()) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            if (time > portal.getTriggeredTime() + Stargate.getGateConfig().getActiveTime()) {
 | 
			
		||||
                portal.getPortalActivator().deactivate();
 | 
			
		||||
                deactivatedPortals.add(portal);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        activePortalsQueue.removeAll(deactivatedPortals);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										221
									
								
								src/main/java/net/knarcraft/stargate/utility/BungeeHelper.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								src/main/java/net/knarcraft/stargate/utility/BungeeHelper.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,221 @@
 | 
			
		||||
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.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;
 | 
			
		||||
import java.io.DataInputStream;
 | 
			
		||||
import java.io.DataOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class contains helpful functions to help with sending and receiving BungeeCord plugin messages
 | 
			
		||||
 */
 | 
			
		||||
public final class BungeeHelper {
 | 
			
		||||
 | 
			
		||||
    private final static String bungeeSubChannel = "SGBungee";
 | 
			
		||||
    private final static String bungeeChannel = "BungeeCord";
 | 
			
		||||
    private final static String teleportMessageDelimiter = "#@#";
 | 
			
		||||
    private final static Map<UUID, String> bungeeQueue = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    private BungeeHelper() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the plugin message channel use for BungeeCord messages
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The bungee plugin channel</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String getBungeeChannel() {
 | 
			
		||||
        return bungeeChannel;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes a player from the queue of players teleporting through BungeeCord
 | 
			
		||||
     *
 | 
			
		||||
     * <p>Whenever a BungeeCord teleportation message is received and the player is not currently connected to this
 | 
			
		||||
     * server, it'll be added to this queue. Once the player joins this server, the player should be removed from the
 | 
			
		||||
     * queue and teleported to the destination.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param playerUUID <p>The UUID of the player to remove</p>
 | 
			
		||||
     * @return <p>The name of the destination portal the player should be teleported to</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String removeFromQueue(UUID playerUUID) {
 | 
			
		||||
        return bungeeQueue.remove(playerUUID);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a plugin message to BungeeCord allowing the target server to catch it
 | 
			
		||||
     *
 | 
			
		||||
     * @param player         <p>The teleporting player</p>
 | 
			
		||||
     * @param entrancePortal <p>The portal the player is teleporting from</p>
 | 
			
		||||
     * @return <p>True if the message was successfully sent</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean sendTeleportationMessage(Player player, Portal entrancePortal) {
 | 
			
		||||
        try {
 | 
			
		||||
            //Build the teleportation message, format is <player identifier>delimiter<destination>
 | 
			
		||||
            String message = player.getUniqueId() + teleportMessageDelimiter + entrancePortal.getDestinationName();
 | 
			
		||||
 | 
			
		||||
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
 | 
			
		||||
            DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
 | 
			
		||||
 | 
			
		||||
            //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(stripColor(entrancePortal.getNetwork()));
 | 
			
		||||
            //Specify the sub-channel/tag to make it recognizable on arrival
 | 
			
		||||
            dataOutputStream.writeUTF(bungeeSubChannel);
 | 
			
		||||
            //Write the length of the message
 | 
			
		||||
            dataOutputStream.writeShort(message.length());
 | 
			
		||||
            //Write the actual message
 | 
			
		||||
            dataOutputStream.writeBytes(message);
 | 
			
		||||
            //Send the plugin message
 | 
			
		||||
            player.sendPluginMessage(Stargate.getInstance(), bungeeChannel, byteArrayOutputStream.toByteArray());
 | 
			
		||||
        } catch (IOException ex) {
 | 
			
		||||
            Stargate.logSevere("Error sending BungeeCord teleport packet");
 | 
			
		||||
            ex.printStackTrace();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends the bungee message necessary to make a player connect  to another server
 | 
			
		||||
     *
 | 
			
		||||
     * @param player         <p>The player to teleport</p>
 | 
			
		||||
     * @param entrancePortal <p>The bungee portal the player is teleporting from</p>
 | 
			
		||||
     * @return <p>True if the plugin message was sent successfully</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean changeServer(Player player, Portal entrancePortal) {
 | 
			
		||||
        try {
 | 
			
		||||
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
 | 
			
		||||
            DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
 | 
			
		||||
 | 
			
		||||
            //Send a connect-message to connect the player to the server defined in the entrance portal's network line
 | 
			
		||||
            dataOutputStream.writeUTF("Connect");
 | 
			
		||||
            dataOutputStream.writeUTF(stripColor(entrancePortal.getNetwork()));
 | 
			
		||||
 | 
			
		||||
            //Send the plugin message
 | 
			
		||||
            player.sendPluginMessage(Stargate.getInstance(), bungeeChannel, byteArrayOutputStream.toByteArray());
 | 
			
		||||
        } catch (IOException ex) {
 | 
			
		||||
            Stargate.logSevere("Error sending BungeeCord connect packet");
 | 
			
		||||
            ex.printStackTrace();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads a plugin message byte array to a string if it's sent from another stargate plugin
 | 
			
		||||
     *
 | 
			
		||||
     * @param message <p>The byte array to read</p>
 | 
			
		||||
     * @return <p>The message contained in the byte array, or null on failure</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String readPluginMessage(byte[] message) {
 | 
			
		||||
        byte[] data;
 | 
			
		||||
        try {
 | 
			
		||||
            DataInputStream dataInputStream = new DataInputStream(new ByteArrayInputStream(message));
 | 
			
		||||
            String subChannel = dataInputStream.readUTF();
 | 
			
		||||
            //Only listen for the SGBungee channel
 | 
			
		||||
            if (!subChannel.equals(bungeeSubChannel)) {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Get the length of the contained message
 | 
			
		||||
            short dataLength = dataInputStream.readShort();
 | 
			
		||||
            //Prepare a byte array for the sent message
 | 
			
		||||
            data = new byte[dataLength];
 | 
			
		||||
            //Read the message to the prepared array
 | 
			
		||||
            dataInputStream.readFully(data);
 | 
			
		||||
        } catch (IOException ex) {
 | 
			
		||||
            Stargate.logSevere("Error receiving BungeeCord message");
 | 
			
		||||
            ex.printStackTrace();
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return new String(data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the receival of a teleport message
 | 
			
		||||
     *
 | 
			
		||||
     * @param receivedMessage <p>The received teleport message</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void handleTeleportMessage(String receivedMessage) {
 | 
			
		||||
        //Get the player id and destination from the message
 | 
			
		||||
        String[] messageParts = receivedMessage.split(teleportMessageDelimiter);
 | 
			
		||||
        UUID playerUUID = UUID.fromString(messageParts[0]);
 | 
			
		||||
        String destination = messageParts[1];
 | 
			
		||||
 | 
			
		||||
        //Check if the player is online, if so, teleport, otherwise, queue
 | 
			
		||||
        Player player = Stargate.getInstance().getServer().getPlayer(playerUUID);
 | 
			
		||||
        if (player == null) {
 | 
			
		||||
            bungeeQueue.put(playerUUID, destination);
 | 
			
		||||
        } else {
 | 
			
		||||
            Portal destinationPortal = PortalHandler.getBungeePortal(destination);
 | 
			
		||||
            //If teleporting to an invalid portal, let the server decide where the player arrives
 | 
			
		||||
            if (destinationPortal == null) {
 | 
			
		||||
                Stargate.logInfo(String.format("Bungee portal %s does not exist", destination));
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            new PlayerTeleporter(destinationPortal, player).teleport(destinationPortal, null);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,147 @@
 | 
			
		||||
package net.knarcraft.stargate.utility;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.Location;
 | 
			
		||||
import org.bukkit.block.BlockFace;
 | 
			
		||||
import org.bukkit.util.Vector;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class helps with direction-related calculations
 | 
			
		||||
 */
 | 
			
		||||
public final class DirectionHelper {
 | 
			
		||||
 | 
			
		||||
    private DirectionHelper() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a yaw by comparing two locations
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The yaw here is the direction an observer a the first location has to look to face the second location.
 | 
			
		||||
     * The yaw is only meant to be calculated for locations where both have either the same x value or the same z value.
 | 
			
		||||
     * Equal locations, or locations with equal x and equal z will throw an exception.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param location1 <p>The first location, which works as the origin</p>
 | 
			
		||||
     * @param location2 <p>The second location, which the yaw will point towards</p>
 | 
			
		||||
     * @return <p>The yaw pointing from the first location to the second location</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static float getYawFromLocationDifference(Location location1, Location location2) {
 | 
			
		||||
        Location difference = location1.clone().subtract(location2.clone());
 | 
			
		||||
        if (difference.getX() > 0) {
 | 
			
		||||
            return 90;
 | 
			
		||||
        } else if (difference.getX() < 0) {
 | 
			
		||||
            return 270;
 | 
			
		||||
        } else if (difference.getZ() > 0) {
 | 
			
		||||
            return 180;
 | 
			
		||||
        } else if (difference.getZ() < 0) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        throw new IllegalArgumentException("Locations given are equal or at the same x and y axis");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a block face given a yaw value
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The supplied yaw must be a value such that (yaw mod 90) = 0. If not, an exception is thrown.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param yaw <p>The yaw value to convert</p>
 | 
			
		||||
     * @return <p>The block face the yaw corresponds to</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static BlockFace getBlockFaceFromYaw(double yaw) {
 | 
			
		||||
        //Make sure the yaw is between 0 and 360
 | 
			
		||||
        yaw = normalizeYaw(yaw);
 | 
			
		||||
 | 
			
		||||
        if (yaw == 0) {
 | 
			
		||||
            return BlockFace.SOUTH;
 | 
			
		||||
        } else if (yaw == 90) {
 | 
			
		||||
            return BlockFace.WEST;
 | 
			
		||||
        } else if (yaw == 180) {
 | 
			
		||||
            return BlockFace.NORTH;
 | 
			
		||||
        } else if (yaw == 270) {
 | 
			
		||||
            return BlockFace.EAST;
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new IllegalArgumentException("Invalid yaw given. Yaw must be divisible by 90.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a direction vector given a yaw
 | 
			
		||||
     *
 | 
			
		||||
     * @param yaw <p>The yaw to convert to a direction vector</p>
 | 
			
		||||
     * @return <p>The direction vector pointing in the same direction as the yaw</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Vector getDirectionVectorFromYaw(double yaw) {
 | 
			
		||||
        //Make sure the yaw is between 0 and 360
 | 
			
		||||
        yaw = normalizeYaw(yaw);
 | 
			
		||||
 | 
			
		||||
        if (yaw == 0) {
 | 
			
		||||
            return new Vector(0, 0, 1);
 | 
			
		||||
        } else if (yaw == 90) {
 | 
			
		||||
            return new Vector(-1, 0, 0);
 | 
			
		||||
        } else if (yaw == 180) {
 | 
			
		||||
            return new Vector(0, 0, -1);
 | 
			
		||||
        } else if (yaw == 270) {
 | 
			
		||||
            return new Vector(1, 0, 0);
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new IllegalArgumentException(String.format("Invalid yaw %f given", yaw));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Moves a location by the given amounts
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The right, down and out work the same as for the relative block vector. Looking a the front of a portal,
 | 
			
		||||
     * right goes rightwards, down goes downwards and out goes towards the observer.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param location <p>The location to start at</p>
 | 
			
		||||
     * @param right    <p>The amount to go right</p>
 | 
			
		||||
     * @param down     <p>The amount to go downward</p>
 | 
			
		||||
     * @param out      <p>The amount to go outward</p>
 | 
			
		||||
     * @param yaw      <p>The yaw when looking directly outwards from a portal</p>
 | 
			
		||||
     * @return <p>A location relative to the given location</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Location moveLocation(Location location, double right, double down, double out, double yaw) {
 | 
			
		||||
        return location.add(getCoordinateVectorFromRelativeVector(right, down, out, yaw));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a vector in Minecraft's normal X,Y,Z-space from a relative block vector
 | 
			
		||||
     *
 | 
			
		||||
     * @param right <p>The amount of rightward steps from the top-left origin</p>
 | 
			
		||||
     * @param down  <p>The amount of downward steps from the top-left origin</p>
 | 
			
		||||
     * @param out   <p>The distance outward from the top-left origin</p>
 | 
			
		||||
     * @param yaw   <p>The yaw when looking directly outwards from a portal</p>
 | 
			
		||||
     * @return <p>A normal vector</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Vector getCoordinateVectorFromRelativeVector(double right, double down, double out, double yaw) {
 | 
			
		||||
        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));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Normalizes a yaw to make it positive and no larger than 360 degrees
 | 
			
		||||
     *
 | 
			
		||||
     * @param yaw <p>The yaw to normalize</p>
 | 
			
		||||
     * @return <p>The normalized yaw</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static double normalizeYaw(double yaw) {
 | 
			
		||||
        while (yaw < 0) {
 | 
			
		||||
            yaw += 360;
 | 
			
		||||
        }
 | 
			
		||||
        yaw = yaw % 360;
 | 
			
		||||
        return yaw;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										248
									
								
								src/main/java/net/knarcraft/stargate/utility/EconomyHelper.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										248
									
								
								src/main/java/net/knarcraft/stargate/utility/EconomyHelper.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,248 @@
 | 
			
		||||
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.property.PortalOwner;
 | 
			
		||||
import net.milkbowl.vault.economy.Economy;
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The economy helper class has helper functions for player payment
 | 
			
		||||
 */
 | 
			
		||||
public final class EconomyHelper {
 | 
			
		||||
 | 
			
		||||
    private EconomyHelper() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Tries to make the given user pay the teleport fee
 | 
			
		||||
     *
 | 
			
		||||
     * @param entrancePortal <p>The portal the player is entering</p>
 | 
			
		||||
     * @param player         <p>The player wishing to teleport</p>
 | 
			
		||||
     * @param cost           <p>The cost of teleportation</p>
 | 
			
		||||
     * @return <p>False if payment was successful. True if the payment was unsuccessful</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean cannotPayTeleportFee(Portal entrancePortal, Player player, int cost) {
 | 
			
		||||
        boolean success;
 | 
			
		||||
 | 
			
		||||
        //Try to charge the player. Paying the portal owner is only possible if a UUID is available
 | 
			
		||||
        UUID ownerUUID = entrancePortal.getOwner().getUUID();
 | 
			
		||||
        if (ownerUUID == null) {
 | 
			
		||||
            Stargate.logWarning(String.format("The owner of the portal %s does not have a UUID and payment to owner " +
 | 
			
		||||
                    "was therefore not possible. Make the owner re-create the portal to fix this.", entrancePortal));
 | 
			
		||||
        }
 | 
			
		||||
        if (entrancePortal.getGate().getToOwner() && ownerUUID != null) {
 | 
			
		||||
            success = chargePlayerIfNecessary(player, ownerUUID, cost);
 | 
			
		||||
        } else {
 | 
			
		||||
            success = chargePlayerIfNecessary(player, cost);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Send the insufficient funds message
 | 
			
		||||
        if (!success) {
 | 
			
		||||
            sendInsufficientFundsMessage(entrancePortal.getName(), player, cost);
 | 
			
		||||
            entrancePortal.getPortalOpener().closePortal(false);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Send the deduct-message to the player
 | 
			
		||||
        sendDeductMessage(entrancePortal.getName(), player, cost);
 | 
			
		||||
 | 
			
		||||
        if (entrancePortal.getGate().getToOwner()) {
 | 
			
		||||
            PortalOwner owner = entrancePortal.getOwner();
 | 
			
		||||
            Player portalOwner;
 | 
			
		||||
            if (owner.getUUID() != null) {
 | 
			
		||||
                portalOwner = Stargate.getInstance().getServer().getPlayer(owner.getUUID());
 | 
			
		||||
            } else {
 | 
			
		||||
                portalOwner = Stargate.getInstance().getServer().getPlayer(owner.getName());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Notify the gate owner of received payment
 | 
			
		||||
            if (portalOwner != null) {
 | 
			
		||||
                sendObtainMessage(entrancePortal.getName(), portalOwner, cost);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a message to the gate owner telling him/her how much he/she earned from a player using his/her gate
 | 
			
		||||
     *
 | 
			
		||||
     * @param portalName  <p>The name of the used portal</p>
 | 
			
		||||
     * @param portalOwner <p>The owner of the portal</p>
 | 
			
		||||
     * @param earnings    <p>The amount the owner earned</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void sendObtainMessage(String portalName, Player portalOwner, int earnings) {
 | 
			
		||||
        String obtainedMsg = Stargate.getString("ecoObtain");
 | 
			
		||||
        obtainedMsg = replacePlaceholders(obtainedMsg, portalName, earnings);
 | 
			
		||||
        Stargate.getMessageSender().sendSuccessMessage(portalOwner, obtainedMsg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a message telling the user how much they paid for interacting with a portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param portalName <p>The name of the portal interacted with</p>
 | 
			
		||||
     * @param player     <p>The interacting player</p>
 | 
			
		||||
     * @param cost       <p>The cost of the interaction</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void sendDeductMessage(String portalName, Player player, int cost) {
 | 
			
		||||
        String deductMsg = Stargate.getString("ecoDeduct");
 | 
			
		||||
        deductMsg = replacePlaceholders(deductMsg, portalName, cost);
 | 
			
		||||
        Stargate.getMessageSender().sendSuccessMessage(player, deductMsg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a message telling the user they don't have enough funds to do a portal interaction
 | 
			
		||||
     *
 | 
			
		||||
     * @param portalName <p>The name of the portal interacted with</p>
 | 
			
		||||
     * @param player     <p>The interacting player</p>
 | 
			
		||||
     * @param cost       <p>The cost of the interaction</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void sendInsufficientFundsMessage(String portalName, Player player, int cost) {
 | 
			
		||||
        String inFundMsg = Stargate.getString("ecoInFunds");
 | 
			
		||||
        inFundMsg = replacePlaceholders(inFundMsg, portalName, cost);
 | 
			
		||||
        Stargate.getMessageSender().sendErrorMessage(player, inFundMsg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a message telling the user how much they are refunded for breaking their portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param portalName <p>The name of the broken portal</p>
 | 
			
		||||
     * @param player     <p>The player breaking the portal</p>
 | 
			
		||||
     * @param cost       <p>The amount the user has to pay for destroying the portal. (expects a negative value)</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void sendRefundMessage(String portalName, Player player, int cost) {
 | 
			
		||||
        String refundMsg = Stargate.getString("ecoRefund");
 | 
			
		||||
        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
 | 
			
		||||
     *
 | 
			
		||||
     * @param message    <p>The message to replace variables in</p>
 | 
			
		||||
     * @param portalName <p>The name of the relevant portal</p>
 | 
			
		||||
     * @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 replacePlaceholders(String message, String portalName, int cost) {
 | 
			
		||||
        return StringFormatter.replacePlaceholders(message, new String[]{"%cost%", "%portal%"},
 | 
			
		||||
                new String[]{Stargate.getEconomyConfig().format(cost), portalName});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
package net.knarcraft.stargate.utility;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.entity.Entity;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This helper class helps with entity properties not immediately available
 | 
			
		||||
 */
 | 
			
		||||
public final class EntityHelper {
 | 
			
		||||
 | 
			
		||||
    private EntityHelper() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the max size of an entity along its x and z axis
 | 
			
		||||
     *
 | 
			
		||||
     * <p>This function gets the ceiling of the max size of an entity, thus calculating the smallest box, using whole
 | 
			
		||||
     * blocks as unit, needed to contain the entity. Assuming n is returned, an (n x n) box is needed to contain the
 | 
			
		||||
     * entity.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param entity <p>The entity to get max size for</p>
 | 
			
		||||
     * @return <p>The max size of the entity</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static int getEntityMaxSizeInt(Entity entity) {
 | 
			
		||||
        return (int) Math.ceil((float) getEntityMaxSize(entity));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the max size of an entity along its x and z axis
 | 
			
		||||
     *
 | 
			
		||||
     * @param entity <p>The entity to get max size for</p>
 | 
			
		||||
     * @return <p>The max size of the entity</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static double getEntityMaxSize(Entity entity) {
 | 
			
		||||
        return Math.max(entity.getBoundingBox().getWidthX(), entity.getBoundingBox().getWidthZ());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										210
									
								
								src/main/java/net/knarcraft/stargate/utility/GateReader.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								src/main/java/net/knarcraft/stargate/utility/GateReader.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,210 @@
 | 
			
		||||
package net.knarcraft.stargate.utility;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Scanner;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Helper class for reading gate files
 | 
			
		||||
 */
 | 
			
		||||
public final class GateReader {
 | 
			
		||||
 | 
			
		||||
    private GateReader() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads a gate file
 | 
			
		||||
     *
 | 
			
		||||
     * @param scanner              <p>The scanner to read from</p>
 | 
			
		||||
     * @param characterMaterialMap <p>The map of characters to store valid symbols in</p>
 | 
			
		||||
     * @param fileName             <p>The filename of the loaded gate config file</p>
 | 
			
		||||
     * @param design               <p>The list to store the loaded design/layout to</p>
 | 
			
		||||
     * @param frameTypes           <p>The set to store frame/border materials to</p>
 | 
			
		||||
     * @param config               <p>The map of config values to store to</p>
 | 
			
		||||
     * @return <p>The column count/width of the loaded gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static int readGateFile(Scanner scanner, Map<Character, Material> characterMaterialMap, String fileName,
 | 
			
		||||
                                   List<List<Character>> design, Set<Material> frameTypes, Map<String, String> config) {
 | 
			
		||||
        boolean designing = false;
 | 
			
		||||
        int columns = 0;
 | 
			
		||||
        try {
 | 
			
		||||
            while (scanner.hasNextLine()) {
 | 
			
		||||
                String line = scanner.nextLine();
 | 
			
		||||
 | 
			
		||||
                if (designing) {
 | 
			
		||||
                    //If we have reached the gate's layout/design, read it
 | 
			
		||||
                    columns = readGateDesignLine(line, columns, characterMaterialMap, fileName, design);
 | 
			
		||||
                    if (columns < 0) {
 | 
			
		||||
                        return -1;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    if (!line.isEmpty() && !line.startsWith("#")) {
 | 
			
		||||
                        //Read a normal config value
 | 
			
		||||
                        readGateConfigValue(line, characterMaterialMap, frameTypes, config);
 | 
			
		||||
                    } else if ((line.isEmpty()) || (!line.contains("=") && !line.startsWith("#"))) {
 | 
			
		||||
                        //An empty line marks the start of the gate's layout/design
 | 
			
		||||
                        designing = true;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } catch (Exception exception) {
 | 
			
		||||
            Stargate.logSevere(String.format("Could not load Gate %s - %s", fileName, exception.getMessage()));
 | 
			
		||||
            return -1;
 | 
			
		||||
        } finally {
 | 
			
		||||
            if (scanner != null) {
 | 
			
		||||
                scanner.close();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return columns;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads one design line of the gate layout file
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The max columns value is sent through this method in such a way that when the last gate design line is read,
 | 
			
		||||
     * the max columns value contains the largest amount of columns (character) found in any of the design's lines.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param line                 <p>The line to read</p>
 | 
			
		||||
     * @param maxColumns           <p>The current max columns value of the design</p>
 | 
			
		||||
     * @param characterMaterialMap <p>The map between characters and the corresponding materials to use</p>
 | 
			
		||||
     * @param fileName             <p>The filename of the loaded gate config file</p>
 | 
			
		||||
     * @param design               <p>The two-dimensional list to store the loaded design to</p>
 | 
			
		||||
     * @return <p>The new max columns value of the design</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static int readGateDesignLine(String line, int maxColumns, Map<Character, Material> characterMaterialMap,
 | 
			
		||||
                                          String fileName, List<List<Character>> design) {
 | 
			
		||||
        List<Character> row = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        //Update the max columns number if this line has more columns
 | 
			
		||||
        if (line.length() > maxColumns) {
 | 
			
		||||
            maxColumns = line.length();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (Character symbol : line.toCharArray()) {
 | 
			
		||||
            //Refuse read gate designs with unknown characters
 | 
			
		||||
            if (symbol.equals('?') || (!characterMaterialMap.containsKey(symbol))) {
 | 
			
		||||
                Stargate.logSevere(String.format("Could not load Gate %s - Unknown symbol '%s' in diagram", fileName,
 | 
			
		||||
                        symbol));
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
            //Add the read character to the row
 | 
			
		||||
            row.add(symbol);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Add this row of the gate's design to the two-dimensional design list
 | 
			
		||||
        design.add(row);
 | 
			
		||||
        return maxColumns;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads one config value from the gate layout file
 | 
			
		||||
     *
 | 
			
		||||
     * @param line                 <p>The line to read</p>
 | 
			
		||||
     * @param characterMaterialMap <p>The character to material map to store to</p>
 | 
			
		||||
     * @param frameTypes           <p>The set to store gate frame/border types to</p>
 | 
			
		||||
     * @param config               <p>The config value map to store to</p>
 | 
			
		||||
     * @throws Exception <p>If an invalid material is encountered</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void readGateConfigValue(String line, Map<Character, Material> characterMaterialMap,
 | 
			
		||||
                                            Set<Material> frameTypes, Map<String, String> config) throws Exception {
 | 
			
		||||
        String[] split = line.split("=");
 | 
			
		||||
        String key = split[0].trim();
 | 
			
		||||
        String value = split[1].trim();
 | 
			
		||||
 | 
			
		||||
        if (key.length() == 1) {
 | 
			
		||||
            //Read a gate frame material
 | 
			
		||||
            Character symbol = key.charAt(0);
 | 
			
		||||
            Material material = Material.getMaterial(value);
 | 
			
		||||
            if (material == null) {
 | 
			
		||||
                throw new Exception("Invalid material in line: " + line);
 | 
			
		||||
            }
 | 
			
		||||
            //Register the map between the read symbol and the corresponding material
 | 
			
		||||
            characterMaterialMap.put(symbol, material);
 | 
			
		||||
            //Save the material as one of the frame materials used for this kind of gate
 | 
			
		||||
            frameTypes.add(material);
 | 
			
		||||
        } else {
 | 
			
		||||
            //Read a normal config value
 | 
			
		||||
            config.put(key, value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads an integer configuration value
 | 
			
		||||
     *
 | 
			
		||||
     * @param config   <p>The configuration to read</p>
 | 
			
		||||
     * @param fileName <p>The filename of the config file</p>
 | 
			
		||||
     * @param key      <p>The config key to read</p>
 | 
			
		||||
     * @return <p>The read value, or -1 if it could not be read</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static int readGateConfig(Map<String, String> config, String fileName, String key) {
 | 
			
		||||
        if (config.containsKey(key)) {
 | 
			
		||||
            try {
 | 
			
		||||
                return Integer.parseInt(config.get(key));
 | 
			
		||||
            } catch (NumberFormatException ex) {
 | 
			
		||||
                Stargate.logWarning(String.format("%s reading %s: %s is not numeric", ex.getClass().getName(),
 | 
			
		||||
                        fileName, key));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads a material configuration value
 | 
			
		||||
     *
 | 
			
		||||
     * @param config          <p>The configuration to read</p>
 | 
			
		||||
     * @param fileName        <p>The filename of the config file</p>
 | 
			
		||||
     * @param key             <p>The config key to read</p>
 | 
			
		||||
     * @param defaultMaterial <p>The default material to use, in case the config is invalid</p>
 | 
			
		||||
     * @return <p>The material specified in the config, or the default material if it could not be read</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Material readGateConfig(Map<String, String> config, String fileName, String key,
 | 
			
		||||
                                          Material defaultMaterial) {
 | 
			
		||||
        if (config.containsKey(key)) {
 | 
			
		||||
            Material material = Material.getMaterial(config.get(key));
 | 
			
		||||
            if (material != null) {
 | 
			
		||||
                return material;
 | 
			
		||||
            } else {
 | 
			
		||||
                Stargate.logWarning(String.format("Error reading %s: %s is not a material", fileName, key));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return defaultMaterial;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Generates a matrix containing the gate layout
 | 
			
		||||
     *
 | 
			
		||||
     * <p>This basically changes the list of lists into a primitive matrix. Additionally, spaces are added to the end of
 | 
			
		||||
     * each row which to too short relative to the longest row.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param design  <p>The design of the gate layout</p>
 | 
			
		||||
     * @param columns <p>The largest amount of columns in the design</p>
 | 
			
		||||
     * @return <p>A matrix containing the gate's layout</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static Character[][] generateLayoutMatrix(List<List<Character>> design, int columns) {
 | 
			
		||||
        Character[][] layout = new Character[design.size()][columns];
 | 
			
		||||
        for (int lineIndex = 0; lineIndex < design.size(); lineIndex++) {
 | 
			
		||||
            List<Character> row = design.get(lineIndex);
 | 
			
		||||
            Character[] result = new Character[columns];
 | 
			
		||||
 | 
			
		||||
            for (int rowIndex = 0; rowIndex < columns; rowIndex++) {
 | 
			
		||||
                if (rowIndex < row.size()) {
 | 
			
		||||
                    result[rowIndex] = row.get(rowIndex);
 | 
			
		||||
                } else {
 | 
			
		||||
                    //Add spaces to all lines which are too short
 | 
			
		||||
                    result[rowIndex] = ' ';
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            layout[lineIndex] = result;
 | 
			
		||||
        }
 | 
			
		||||
        return layout;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
package net.knarcraft.stargate.utility;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
import org.bukkit.Tag;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class helps decide properties of materials not already present in the Spigot API
 | 
			
		||||
 */
 | 
			
		||||
public final class MaterialHelper {
 | 
			
		||||
 | 
			
		||||
    private MaterialHelper() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the given material is a dead or alive wall coral
 | 
			
		||||
     *
 | 
			
		||||
     * @param material <p>The material to check</p>
 | 
			
		||||
     * @return <p>True if the material is a wall coral</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean isWallCoral(Material material) {
 | 
			
		||||
        //Unfortunately, there is no tag for dead wall corals, so they need to be checked manually
 | 
			
		||||
        return Tag.WALL_CORALS.isTagged(material) ||
 | 
			
		||||
                material.equals(Material.DEAD_BRAIN_CORAL_WALL_FAN) ||
 | 
			
		||||
                material.equals(Material.DEAD_BUBBLE_CORAL_WALL_FAN) ||
 | 
			
		||||
                material.equals(Material.DEAD_FIRE_CORAL_WALL_FAN) ||
 | 
			
		||||
                material.equals(Material.DEAD_HORN_CORAL_WALL_FAN) ||
 | 
			
		||||
                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
 | 
			
		||||
     *
 | 
			
		||||
     * @param material <p>The material to check</p>
 | 
			
		||||
     * @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) || isContainer(material);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,417 @@
 | 
			
		||||
package net.knarcraft.stargate.utility;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.stargate.Stargate;
 | 
			
		||||
import net.knarcraft.stargate.event.StargateAccessEvent;
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
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
 | 
			
		||||
 */
 | 
			
		||||
public final class PermissionHelper {
 | 
			
		||||
 | 
			
		||||
    private PermissionHelper() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens a portal if the given player is allowed to, and if the portal is not already open
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player opening the portal</p>
 | 
			
		||||
     * @param portal <p>The portal to open</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void openPortal(Player player, Portal portal) {
 | 
			
		||||
        Portal destination = portal.getPortalActivator().getDestination();
 | 
			
		||||
 | 
			
		||||
        //For an always open portal, no action is necessary
 | 
			
		||||
        if (portal.getOptions().isAlwaysOn()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Destination is invalid or the same portal. Send an error message
 | 
			
		||||
        if (destination == null || destination == portal) {
 | 
			
		||||
            if (!portal.getOptions().isSilent()) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("invalidMsg"));
 | 
			
		||||
            }
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Portal is already open
 | 
			
		||||
        if (portal.isOpen()) {
 | 
			
		||||
            //Close the portal if this player opened the portal
 | 
			
		||||
            if (portal.getActivePlayer() == player) {
 | 
			
		||||
                portal.getPortalOpener().closePortal(false);
 | 
			
		||||
            }
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //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) {
 | 
			
		||||
            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)) {
 | 
			
		||||
            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()) {
 | 
			
		||||
            if (!portal.getOptions().isSilent()) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("blockMsg"));
 | 
			
		||||
            }
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Open the portal
 | 
			
		||||
        portal.getPortalOpener().openPortal(player, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a StargateAccessEvent and gets the updated deny value
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The event is used for other plugins to bypass the permission checks.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player trying to use the portal</p>
 | 
			
		||||
     * @param portal <p>The portal the player is trying to use</p>
 | 
			
		||||
     * @param deny   <p>Whether the player's access has already been denied by a previous check</p>
 | 
			
		||||
     * @return <p>False if the player should be allowed through the portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean portalAccessDenied(Player player, Portal portal, boolean deny) {
 | 
			
		||||
        StargateAccessEvent event = new StargateAccessEvent(player, portal, deny);
 | 
			
		||||
        Stargate.getInstance().getServer().getPluginManager().callEvent(event);
 | 
			
		||||
        return event.getDeny();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a given user cannot travel between two portals
 | 
			
		||||
     *
 | 
			
		||||
     * @param player         <p>The player to check</p>
 | 
			
		||||
     * @param entrancePortal <p>The portal the user wants to enter</p>
 | 
			
		||||
     * @param destination    <p>The portal the user wants to exit from</p>
 | 
			
		||||
     * @return <p>False if the user is allowed to access the portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean cannotAccessPortal(Player player, Portal entrancePortal, Portal destination) {
 | 
			
		||||
        boolean deny = false;
 | 
			
		||||
 | 
			
		||||
        if (entrancePortal.getOptions().isBungee()) {
 | 
			
		||||
            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.getCleanNetwork())) {
 | 
			
		||||
            //If the player does not have access to the network, deny
 | 
			
		||||
            Stargate.debug("cannotAccessPortal", "Cannot access network");
 | 
			
		||||
            deny = true;
 | 
			
		||||
        } else if (PermissionHelper.cannotAccessWorld(player, destination.getWorld().getName())) {
 | 
			
		||||
            //If the player does not have access to the portal's world, deny
 | 
			
		||||
            Stargate.debug("cannotAccessPortal", "Cannot access world");
 | 
			
		||||
            deny = true;
 | 
			
		||||
        }
 | 
			
		||||
        //Allow other plugins to override whether the player can access the portal
 | 
			
		||||
        return portalAccessDenied(player, entrancePortal, deny);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a player has the given permission
 | 
			
		||||
     *
 | 
			
		||||
     * <p>This is the same as player.hasPermission(), but this function allows for printing permission debugging info.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param player     <p>The player to check</p>
 | 
			
		||||
     * @param permission <p>The permission to check</p>
 | 
			
		||||
     * @return <p>True if the player has the permission</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean hasPermission(Player player, String permission) {
 | 
			
		||||
        if (Stargate.getStargateConfig().isPermissionDebuggingEnabled()) {
 | 
			
		||||
            Stargate.debug("hasPerm::Permission(" + player.getName() + ")", permission + " => " +
 | 
			
		||||
                    player.hasPermission(permission));
 | 
			
		||||
        }
 | 
			
		||||
        return player.hasPermission(permission);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if a player has been given a permission implicitly
 | 
			
		||||
     *
 | 
			
		||||
     * <p>This should be run if a player has a parent permission to check for the child permission. It is assumed the
 | 
			
		||||
     * player has the child permission unless it's explicitly set to false.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param player     <p>The player to check</p>
 | 
			
		||||
     * @param permission <p>The permission to check</p>
 | 
			
		||||
     * @return <p>True if the player has the permission implicitly or explicitly</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean hasPermissionImplicit(Player player, String permission) {
 | 
			
		||||
        if (!player.isPermissionSet(permission)) {
 | 
			
		||||
            if (Stargate.getStargateConfig().isPermissionDebuggingEnabled()) {
 | 
			
		||||
                Stargate.debug("hasPermissionImplicit::Permission", permission + " => implicitly true");
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        if (Stargate.getStargateConfig().isPermissionDebuggingEnabled()) {
 | 
			
		||||
            Stargate.debug("hasPermissionImplicit::Permission", permission + " => " +
 | 
			
		||||
                    player.hasPermission(permission));
 | 
			
		||||
        }
 | 
			
		||||
        return player.hasPermission(permission);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a player can access the given world
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player trying to access the world</p>
 | 
			
		||||
     * @param world  <p>The world the player is trying to access</p>
 | 
			
		||||
     * @return <p>False if the player should be allowed to access the world</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean cannotAccessWorld(Player player, String world) {
 | 
			
		||||
        //The player can access all worlds
 | 
			
		||||
        if (hasPermission(player, "stargate.world")) {
 | 
			
		||||
            //Check if the world permission has been explicitly denied
 | 
			
		||||
            return !hasPermissionImplicit(player, "stargate.world." + world);
 | 
			
		||||
        }
 | 
			
		||||
        //The player can access the destination world
 | 
			
		||||
        return !hasPermission(player, "stargate.world." + world);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a player can access the given network
 | 
			
		||||
     *
 | 
			
		||||
     * @param player  <p>The player to check</p>
 | 
			
		||||
     * @param network <p>The network to check</p>
 | 
			
		||||
     * @return <p>True if the player is denied from accessing the network</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean cannotAccessNetwork(Player player, String network) {
 | 
			
		||||
        //The player can access all networks
 | 
			
		||||
        if (hasPermission(player, "stargate.network")) {
 | 
			
		||||
            //Check if the world permission has been explicitly denied
 | 
			
		||||
            return !hasPermissionImplicit(player, "stargate.network." + network);
 | 
			
		||||
        }
 | 
			
		||||
        //Check if the player can access this network
 | 
			
		||||
        if (hasPermission(player, "stargate.network." + network)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        //Is able to create personal gates (Assumption is made they can also access them)
 | 
			
		||||
        String playerName = player.getName();
 | 
			
		||||
        if (playerName.length() > getMaxNameNetworkLength()) {
 | 
			
		||||
            playerName = playerName.substring(0, getMaxNameNetworkLength());
 | 
			
		||||
        }
 | 
			
		||||
        return !network.equals(playerName) || !hasPermission(player, "stargate.create.personal");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a player can access the given bungee server
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player trying to teleport</p>
 | 
			
		||||
     * @param server <p>The server the player is trying to connect to</p>
 | 
			
		||||
     * @return <p>True if the player is allowed to access the given server</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean canAccessServer(Player player, String server) {
 | 
			
		||||
        //The player can access all servers
 | 
			
		||||
        if (hasPermission(player, "stargate.server")) {
 | 
			
		||||
            //Check if the server permission has been explicitly denied
 | 
			
		||||
            return hasPermissionImplicit(player, "stargate.server." + server);
 | 
			
		||||
        }
 | 
			
		||||
        //The player can access the destination server
 | 
			
		||||
        return hasPermission(player, "stargate.server." + server);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the given player can teleport the given stretch for free
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player trying to teleport</p>
 | 
			
		||||
     * @param src    <p>The portal the player is entering</p>
 | 
			
		||||
     * @param dest   <p>The portal the player wants to teleport to</p>
 | 
			
		||||
     * @return <p>True if the player can travel for free</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean isFree(Player player, Portal src, Portal dest) {
 | 
			
		||||
        //This portal is free
 | 
			
		||||
        if (src.getOptions().isFree()) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        //Player can use this portal for free
 | 
			
		||||
        if (hasPermission(player, "stargate.free.use")) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        //Don't charge for free destinations unless specified in the config
 | 
			
		||||
        return dest != null && Stargate.getEconomyConfig().freeIfFreeDestination() && dest.getOptions().isFree();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the player can see this gate (Hidden property check)
 | 
			
		||||
     *
 | 
			
		||||
     * <p>This decides if the player can see the gate on the network selection screen</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player to check</p>
 | 
			
		||||
     * @param portal <p>The portal to check</p>
 | 
			
		||||
     * @return <p>True if the given player can see the given portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean canSeePortal(Player player, Portal portal) {
 | 
			
		||||
        //The portal is not hidden
 | 
			
		||||
        if (!portal.getOptions().isHidden()) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        //The player can see all hidden portals
 | 
			
		||||
        if (hasPermission(player, "stargate.admin.hidden")) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        //The player is the owner of the portal
 | 
			
		||||
        return portal.isOwner(player);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if the given player is allowed to use the given private portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player trying to use the portal</p>
 | 
			
		||||
     * @param portal <p>The private portal used</p>
 | 
			
		||||
     * @return <p>True if the player is allowed to use the portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean canUsePrivatePortal(Player player, Portal portal) {
 | 
			
		||||
        //Check if the player is the owner of the gate
 | 
			
		||||
        if (portal.isOwner(player)) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        //The player is an admin with the ability to use private gates
 | 
			
		||||
        return hasPermission(player, "stargate.admin.private");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if the given player has access to the given portal option
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player trying to use the option</p>
 | 
			
		||||
     * @param option <p>The option the player is trying to use</p>
 | 
			
		||||
     * @return <p>True if the player is allowed to create a portal with the given option</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean canUseOption(Player player, PortalOption option) {
 | 
			
		||||
        return hasPermission(player, option.getPermissionString());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if the given player is allowed to create gates on the given network
 | 
			
		||||
     *
 | 
			
		||||
     * @param player  <p>The player trying to create a new gate</p>
 | 
			
		||||
     * @param network <p>The network the player is trying to create a gate on</p>
 | 
			
		||||
     * @return <p>True if the player is allowed to create the new gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean canCreateNetworkGate(Player player, String network) {
 | 
			
		||||
        //Check if the player is allowed to create a portal on any network
 | 
			
		||||
        if (hasPermission(player, "stargate.create.network")) {
 | 
			
		||||
            //Check if the network has been explicitly denied
 | 
			
		||||
            return hasPermissionImplicit(player, "stargate.create.network." + network);
 | 
			
		||||
        }
 | 
			
		||||
        //Check if the player is allowed to create on this specific network
 | 
			
		||||
        return hasPermission(player, "stargate.create.network." + network);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the given player is allowed to create a personal gate
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player trying to create the new gate</p>
 | 
			
		||||
     * @return <p>True if the player is allowed</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean canCreatePersonalPortal(Player player) {
 | 
			
		||||
        return hasPermission(player, "stargate.create.personal");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if the given player can create a portal with the given gate layout
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player trying to create a portal</p>
 | 
			
		||||
     * @param gate   <p>The gate type of the new portal</p>
 | 
			
		||||
     * @return <p>True if the player is allowed to create a portal with the given gate layout</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean canCreatePortal(Player player, String gate) {
 | 
			
		||||
        //Check if the player is allowed to create all gates
 | 
			
		||||
        if (hasPermission(player, "stargate.create.gate")) {
 | 
			
		||||
            //Check if the gate type has been explicitly denied
 | 
			
		||||
            return hasPermissionImplicit(player, "stargate.create.gate." + gate);
 | 
			
		||||
        }
 | 
			
		||||
        //Check if the player can create the specific gate type
 | 
			
		||||
        return hasPermission(player, "stargate.create.gate." + gate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if the given player can destroy the given portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param player <p>The player trying to destroy the portal</p>
 | 
			
		||||
     * @param portal <p>The portal to destroy</p>
 | 
			
		||||
     * @return <p>True if the player is allowed to destroy the portal</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean canDestroyPortal(Player player, Portal portal) {
 | 
			
		||||
        String network = portal.getCleanNetwork();
 | 
			
		||||
 | 
			
		||||
        //Use a special check for bungee portals
 | 
			
		||||
        if (portal.getOptions().isBungee()) {
 | 
			
		||||
            return hasPermission(player, "stargate.admin.bungee");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Check if the player is allowed to destroy on all networks
 | 
			
		||||
        if (hasPermission(player, "stargate.destroy.network")) {
 | 
			
		||||
            //Check if the network has been explicitly denied
 | 
			
		||||
            return hasPermissionImplicit(player, "stargate.destroy.network." + network);
 | 
			
		||||
        }
 | 
			
		||||
        //Check if the player is allowed to destroy on the network
 | 
			
		||||
        if (hasPermission(player, "stargate.destroy.network." + network)) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        //Check if personal portal and if the player is allowed to destroy it
 | 
			
		||||
        return portal.isOwner(player) && hasPermission(player, "stargate.destroy.personal");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Decide of the player can teleport through a portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param entrancePortal <p>The portal the player is entering from</p>
 | 
			
		||||
     * @param destination    <p>The destination of the portal the player is inside</p>
 | 
			
		||||
     * @param player         <p>The player wanting to teleport</p>
 | 
			
		||||
     * @param event          <p>The move event causing the teleportation</p>
 | 
			
		||||
     * @return <p>True if the player cannot teleport. False otherwise</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean playerCannotTeleport(Portal entrancePortal, Portal destination, Player player, PlayerMoveEvent event) {
 | 
			
		||||
        //No portal or not open
 | 
			
		||||
        if (entrancePortal == null || !entrancePortal.isOpen()) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Not open for this player
 | 
			
		||||
        if (!entrancePortal.getPortalOpener().isOpenFor(player)) {
 | 
			
		||||
            if (!entrancePortal.getOptions().isSilent()) {
 | 
			
		||||
                Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
 | 
			
		||||
            }
 | 
			
		||||
            new PlayerTeleporter(entrancePortal, player).teleportPlayer(entrancePortal, event);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //No destination
 | 
			
		||||
        if (!entrancePortal.getOptions().isBungee() && destination == null) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Player cannot access portal
 | 
			
		||||
        if (PermissionHelper.cannotAccessPortal(player, entrancePortal, destination)) {
 | 
			
		||||
            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 = EconomyHelper.getUseCost(player, entrancePortal, destination);
 | 
			
		||||
        if (cost > 0) {
 | 
			
		||||
            return EconomyHelper.cannotPayTeleportFee(entrancePortal, player, cost);
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,401 @@
 | 
			
		||||
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.container.RelativeBlockVector;
 | 
			
		||||
import net.knarcraft.stargate.portal.Portal;
 | 
			
		||||
import net.knarcraft.stargate.portal.PortalHandler;
 | 
			
		||||
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;
 | 
			
		||||
import java.io.FileWriter;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.Scanner;
 | 
			
		||||
 | 
			
		||||
import static net.knarcraft.stargate.portal.PortalSignDrawer.markPortalWithInvalidGate;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Helper class for saving and loading portal save files
 | 
			
		||||
 */
 | 
			
		||||
public final class PortalFileHelper {
 | 
			
		||||
 | 
			
		||||
    private PortalFileHelper() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Saves all portals for the given world
 | 
			
		||||
     *
 | 
			
		||||
     * @param world <p>The world to save portals for</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void saveAllPortals(World world) {
 | 
			
		||||
        Stargate.getStargateConfig().addManagedWorld(world.getName());
 | 
			
		||||
        String saveFileLocation = Stargate.getPortalFolder() + "/" + world.getName() + ".db";
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(saveFileLocation, false));
 | 
			
		||||
 | 
			
		||||
            for (Portal portal : PortalRegistry.getAllPortals()) {
 | 
			
		||||
                //Skip portals in other worlds
 | 
			
		||||
                String worldName = portal.getWorld().getName();
 | 
			
		||||
                if (!worldName.equalsIgnoreCase(world.getName())) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                //Save the portal
 | 
			
		||||
                savePortal(bufferedWriter, portal);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            bufferedWriter.close();
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            Stargate.logSevere(String.format("Exception while writing stargates to %s: %s", saveFileLocation, e));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Saves one portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param bufferedWriter <p>The buffered writer to write to</p>
 | 
			
		||||
     * @param portal         <p>The portal to save</p>
 | 
			
		||||
     * @throws IOException <p>If unable to write to the buffered writer</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void savePortal(BufferedWriter bufferedWriter, Portal portal) throws IOException {
 | 
			
		||||
        StringBuilder builder = new StringBuilder();
 | 
			
		||||
        BlockLocation button = portal.getStructure().getButton();
 | 
			
		||||
 | 
			
		||||
        //WARNING: Because of the primitive save format, any change in order will break everything!
 | 
			
		||||
        builder.append(portal.getName()).append(':');
 | 
			
		||||
        builder.append(portal.getSignLocation().toString()).append(':');
 | 
			
		||||
        builder.append((button != null) ? button.toString() : "").append(':');
 | 
			
		||||
 | 
			
		||||
        //Add removes config values to keep indices consistent
 | 
			
		||||
        builder.append(0).append(':');
 | 
			
		||||
        builder.append(0).append(':');
 | 
			
		||||
 | 
			
		||||
        builder.append(portal.getYaw()).append(':');
 | 
			
		||||
        builder.append(portal.getTopLeft().toString()).append(':');
 | 
			
		||||
        builder.append(portal.getGate().getFilename()).append(':');
 | 
			
		||||
 | 
			
		||||
        //Only save the destination name if the gate is fixed as it doesn't matter otherwise
 | 
			
		||||
        builder.append(portal.getOptions().isFixed() ? portal.getDestinationName() : "").append(':');
 | 
			
		||||
 | 
			
		||||
        builder.append(portal.getNetwork()).append(':');
 | 
			
		||||
 | 
			
		||||
        //Name is saved as a fallback if the UUID is unavailable
 | 
			
		||||
        builder.append(portal.getOwner().getIdentifier());
 | 
			
		||||
 | 
			
		||||
        //Save all the portal options
 | 
			
		||||
        savePortalOptions(portal, builder);
 | 
			
		||||
 | 
			
		||||
        bufferedWriter.append(builder.toString());
 | 
			
		||||
        bufferedWriter.newLine();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Saves all portal options for the given portal
 | 
			
		||||
     *
 | 
			
		||||
     * @param portal  <p>The portal to save</p>
 | 
			
		||||
     * @param builder <p>The string builder to append to</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void savePortalOptions(Portal portal, StringBuilder builder) {
 | 
			
		||||
        PortalOptions options = portal.getOptions();
 | 
			
		||||
        builder.append(':');
 | 
			
		||||
        builder.append(options.isHidden()).append(':');
 | 
			
		||||
        builder.append(options.isAlwaysOn()).append(':');
 | 
			
		||||
        builder.append(options.isPrivate()).append(':');
 | 
			
		||||
        builder.append(portal.getWorld().getName()).append(':');
 | 
			
		||||
        builder.append(options.isFree()).append(':');
 | 
			
		||||
        builder.append(options.isBackwards()).append(':');
 | 
			
		||||
        builder.append(options.isShown()).append(':');
 | 
			
		||||
        builder.append(options.isNoNetwork()).append(':');
 | 
			
		||||
        builder.append(options.isRandom()).append(':');
 | 
			
		||||
        builder.append(options.isBungee()).append(':');
 | 
			
		||||
        builder.append(options.isSilent()).append(':');
 | 
			
		||||
        builder.append(options.hasNoSign());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads all portals for the given world
 | 
			
		||||
     *
 | 
			
		||||
     * @param world <p>The world to load portals for</p>
 | 
			
		||||
     * @return <p>True if portals could be loaded</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean loadAllPortals(World world) {
 | 
			
		||||
        String location = Stargate.getPortalFolder();
 | 
			
		||||
 | 
			
		||||
        File database = new File(location, world.getName() + ".db");
 | 
			
		||||
 | 
			
		||||
        if (database.exists()) {
 | 
			
		||||
            return loadPortals(world, database);
 | 
			
		||||
        } else {
 | 
			
		||||
            Stargate.logInfo(String.format("{%s} No stargates for world ", world.getName()));
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads all the given portals
 | 
			
		||||
     *
 | 
			
		||||
     * @param world    <p>The world to load portals for</p>
 | 
			
		||||
     * @param database <p>The database file containing the portals</p>
 | 
			
		||||
     * @return <p>True if the portals were loaded successfully</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static boolean loadPortals(World world, File database) {
 | 
			
		||||
        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
 | 
			
		||||
                needsToSaveDatabase = readPortalLine(scanner, ++lineIndex, world) || needsToSaveDatabase;
 | 
			
		||||
            }
 | 
			
		||||
            scanner.close();
 | 
			
		||||
 | 
			
		||||
            //Do necessary tasks after all portals have loaded
 | 
			
		||||
            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(),
 | 
			
		||||
                    lineIndex));
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads one file line containing information about one portal
 | 
			
		||||
     *
 | 
			
		||||
     * @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 boolean readPortalLine(Scanner scanner, int lineIndex, World world) {
 | 
			
		||||
        String line = scanner.nextLine().trim();
 | 
			
		||||
 | 
			
		||||
        //Ignore empty and comment lines
 | 
			
		||||
        if (line.startsWith("#") || line.isEmpty()) {
 | 
			
		||||
            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 false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Load the portal defined in the current line
 | 
			
		||||
        return loadPortal(portalData, world, lineIndex);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Performs tasks which must be run after portals have loaded
 | 
			
		||||
     *
 | 
			
		||||
     * <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 needsToSaveDatabase <p>Whether the portal database's file needs to be updated</p>
 | 
			
		||||
     */
 | 
			
		||||
    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();
 | 
			
		||||
        int openCount = PortalHandler.openAlwaysOpenPortals();
 | 
			
		||||
 | 
			
		||||
        //Print info about loaded stargates so that admins can see if all stargates loaded
 | 
			
		||||
        Stargate.logInfo(String.format("{%s} Loaded %d stargates with %d set as always-on", world.getName(),
 | 
			
		||||
                portalCount, openCount));
 | 
			
		||||
 | 
			
		||||
        //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()) {
 | 
			
		||||
            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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads one portal from a data array
 | 
			
		||||
     *
 | 
			
		||||
     * @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 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;
 | 
			
		||||
 | 
			
		||||
        //Load the portal's location
 | 
			
		||||
        PortalLocation portalLocation = new PortalLocation();
 | 
			
		||||
        portalLocation.setSignLocation(new BlockLocation(world, portalData[1]));
 | 
			
		||||
        portalLocation.setYaw(Float.parseFloat(portalData[5]));
 | 
			
		||||
        portalLocation.setTopLeft(new BlockLocation(world, portalData[6]));
 | 
			
		||||
 | 
			
		||||
        //Check if the portal's gate type exists and is loaded
 | 
			
		||||
        Gate gate = GateHandler.getGateByName(portalData[7]);
 | 
			
		||||
        if (gate == null) {
 | 
			
		||||
            //Mark the sign as invalid to reduce some player confusion
 | 
			
		||||
            markPortalWithInvalidGate(portalLocation, portalData[7], lineIndex);
 | 
			
		||||
            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 ownerString = (portalData.length > 10) ? portalData[10] : "";
 | 
			
		||||
 | 
			
		||||
        //Get the owner from the owner string
 | 
			
		||||
        PortalOwner owner = new PortalOwner(ownerString);
 | 
			
		||||
 | 
			
		||||
        //Create the new portal
 | 
			
		||||
        Portal portal = new Portal(portalLocation, button, destination, name, network, gate, owner,
 | 
			
		||||
                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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								src/main/resources/config-migrations.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/main/resources/config-migrations.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
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
 | 
			
		||||
destroyexplosion=gates.integrity.destroyedByExplosion
 | 
			
		||||
maxgates=gates.maxGatesEachNetwork
 | 
			
		||||
destMemory=gates.cosmetic.rememberDestination
 | 
			
		||||
ignoreEntrance=
 | 
			
		||||
gates.integrity.ignoreEntrance=
 | 
			
		||||
handleVehicles=gates.functionality.handleVehicles
 | 
			
		||||
sortLists=gates.cosmetic.sortNetworkDestinations
 | 
			
		||||
protectEntrance=gates.integrity.protectEntrance
 | 
			
		||||
enableBungee=gates.functionality.enableBungee
 | 
			
		||||
verifyPortals=gates.integrity.verifyPortals
 | 
			
		||||
signColor=gates.cosmetic.signColor
 | 
			
		||||
gates.cosmetic.signColor=gates.cosmetic.mainSignColor
 | 
			
		||||
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=
 | 
			
		||||
economy.freeGatesGreen=economy.freeGatesColored
 | 
			
		||||
teleportMessage=
 | 
			
		||||
registerMessage=
 | 
			
		||||
destroyzMessage=
 | 
			
		||||
noownersMessage=
 | 
			
		||||
unselectMessage=
 | 
			
		||||
collisinMessage=
 | 
			
		||||
cantAffordToUse=
 | 
			
		||||
cantAffordToNew=
 | 
			
		||||
portal-open=
 | 
			
		||||
portal-closed=
 | 
			
		||||
cost-type=
 | 
			
		||||
cost-to-activate=
 | 
			
		||||
taxaccount=taxAccount
 | 
			
		||||
usevault=
 | 
			
		||||
							
								
								
									
										107
									
								
								src/main/resources/config.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								src/main/resources/config.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
			
		||||
# stargate Configuration File
 | 
			
		||||
# Main stargate config
 | 
			
		||||
 | 
			
		||||
# 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
 | 
			
		||||
  # 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 - 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
 | 
			
		||||
							
								
								
									
										12
									
								
								src/main/resources/gates/endgate.gate
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/main/resources/gates/endgate.gate
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
portal-open=END_GATEWAY
 | 
			
		||||
portal-closed=AIR
 | 
			
		||||
button=BIRCH_BUTTON
 | 
			
		||||
toowner=false
 | 
			
		||||
X=END_STONE_BRICKS
 | 
			
		||||
-=END_STONE_BRICKS
 | 
			
		||||
 | 
			
		||||
 XX
 | 
			
		||||
X..X
 | 
			
		||||
-..-
 | 
			
		||||
X*.X
 | 
			
		||||
 XX
 | 
			
		||||
							
								
								
									
										24
									
								
								src/main/resources/gates/nethergate.gate
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/main/resources/gates/nethergate.gate
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
#This is the default gate type. You can copy this and make as many .gate files as you need.
 | 
			
		||||
#The portal-open block can be most blocks which do not fill the entire block or otherwise prevent the player from
 | 
			
		||||
#entering the portal, but NETHER_PORTAL, AIR, WATER, LAVA, KELP_PLANT, OAK_FENCE, IRON_BARS, CHAIN, BAMBOO, SUGAR_CANE,
 | 
			
		||||
#COBWEB and VINE gives an impression of which blocks will work.
 | 
			
		||||
portal-open=NETHER_PORTAL
 | 
			
		||||
#The portal-closed block can be any of the blocks used for portal-open, but also any solid, full-size block such as DIRT.
 | 
			
		||||
portal-closed=AIR
 | 
			
		||||
#The button can be the following: A chest (CHEST), any type of button (STONE_BUTTON, OAK_BUTTON), any type of shulker
 | 
			
		||||
#box (LIME_SHULKER_BOX), or any wall coral (DEAD_TUBE_CORAL_WALL_FAN, TUBE_CORAL_WALL_FAN, DEAD_BRAIN_CORAL_WALL_FAN,
 | 
			
		||||
#BRAIN_CORAL_WALL_FAN, etc.)
 | 
			
		||||
button=STONE_BUTTON
 | 
			
		||||
#Whether payment for entry should go to this gate's owner
 | 
			
		||||
toowner=false
 | 
			
		||||
#The material to use for the normal frame
 | 
			
		||||
X=OBSIDIAN
 | 
			
		||||
#The material to use for the sign and button blocks of the frame
 | 
			
		||||
-=OBSIDIAN
 | 
			
		||||
#The description of the required portal blocks. X = Frame block. - = Sign/button position. . = Empty blocks. * = Exit
 | 
			
		||||
 | 
			
		||||
 XX
 | 
			
		||||
X..X
 | 
			
		||||
-..-
 | 
			
		||||
X*.X
 | 
			
		||||
 XX
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
							
								
								
									
										12
									
								
								src/main/resources/gates/watergate.gate
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/main/resources/gates/watergate.gate
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
portal-open=KELP_PLANT
 | 
			
		||||
portal-closed=WATER
 | 
			
		||||
button=BRAIN_CORAL_WALL_FAN
 | 
			
		||||
toowner=false
 | 
			
		||||
X=SEA_LANTERN
 | 
			
		||||
-=SEA_LANTERN
 | 
			
		||||
 | 
			
		||||
 XX
 | 
			
		||||
X..X
 | 
			
		||||
-..-
 | 
			
		||||
X*.X
 | 
			
		||||
 XX
 | 
			
		||||
@@ -1,28 +1,28 @@
 | 
			
		||||
author=EduardBaer
 | 
			
		||||
prefix=[Stargate] 
 | 
			
		||||
teleportMsg=Du wurdest Teleportiert.
 | 
			
		||||
destroyMsg=Gate zerstört
 | 
			
		||||
invalidMsg=Ungültiges Ziel
 | 
			
		||||
blockMsg=Ziel blockiert
 | 
			
		||||
destEmpty=Zielliste leer
 | 
			
		||||
denyMsg=Zugriff verweigert
 | 
			
		||||
 | 
			
		||||
ecoDeduct=%cost% abgezogen
 | 
			
		||||
ecoRefund=%cost% zurückerstattet
 | 
			
		||||
ecoObtain=%cost% von Stargate %portal% erhalten
 | 
			
		||||
ecoInFunds=Das kannst du dir nicht leisten.
 | 
			
		||||
 | 
			
		||||
createMsg=Gate erstellt.
 | 
			
		||||
createNetDeny=Du hast keinen Zugriff auf dieses Netzwerk.
 | 
			
		||||
createGateDeny=Du hast keinen Zugriff auf dieses Gate-Layout.
 | 
			
		||||
createPersonal=Gate im persönlichen Netzwerk erstellt.
 | 
			
		||||
createNameLength=Name zu kurz oder zu lang.
 | 
			
		||||
createExists=Ein Gate mit diesem Name existiert bereits.
 | 
			
		||||
createFull=Dieses Netzwerk ist voll.
 | 
			
		||||
createWorldDeny=Du hast keinen Zugriff auf diese Welt.
 | 
			
		||||
createConflict=Dieses Gate steht im Konflikt mit einem bereits existierenden.
 | 
			
		||||
 | 
			
		||||
signRightClick=Right click
 | 
			
		||||
signToUse=to use gate
 | 
			
		||||
signRandom=Random
 | 
			
		||||
author=EduardBaer
 | 
			
		||||
prefix=[Stargate] 
 | 
			
		||||
teleportMsg=Du wurdest Teleportiert.
 | 
			
		||||
destroyMsg=Gate zerstört
 | 
			
		||||
invalidMsg=Ungültiges Ziel
 | 
			
		||||
blockMsg=Ziel blockiert
 | 
			
		||||
destEmpty=Zielliste leer
 | 
			
		||||
denyMsg=Zugriff verweigert
 | 
			
		||||
 | 
			
		||||
ecoDeduct=%cost% abgezogen
 | 
			
		||||
ecoRefund=%cost% zurückerstattet
 | 
			
		||||
ecoObtain=%cost% von Stargate %portal% erhalten
 | 
			
		||||
ecoInFunds=Das kannst du dir nicht leisten.
 | 
			
		||||
 | 
			
		||||
createMsg=Gate erstellt.
 | 
			
		||||
createNetDeny=Du hast keinen Zugriff auf dieses Netzwerk.
 | 
			
		||||
createGateDeny=Du hast keinen Zugriff auf dieses Gate-Layout.
 | 
			
		||||
createPersonal=Gate im persönlichen Netzwerk erstellt.
 | 
			
		||||
createNameLength=Name zu kurz oder zu lang.
 | 
			
		||||
createExists=Ein Gate mit diesem Name existiert bereits.
 | 
			
		||||
createFull=Dieses Netzwerk ist voll.
 | 
			
		||||
createWorldDeny=Du hast keinen Zugriff auf diese Welt.
 | 
			
		||||
createConflict=Dieses Gate steht im Konflikt mit einem bereits existierenden.
 | 
			
		||||
 | 
			
		||||
signRightClick=Right click
 | 
			
		||||
signToUse=to use gate
 | 
			
		||||
signRandom=Random
 | 
			
		||||
signDisconnected=Disconnected
 | 
			
		||||
@@ -1,32 +1,43 @@
 | 
			
		||||
prefix=[Stargate] 
 | 
			
		||||
teleportMsg=Teleported
 | 
			
		||||
destroyMsg=Gate Destroyed
 | 
			
		||||
invalidMsg=Invalid Destination
 | 
			
		||||
blockMsg=Destination Blocked
 | 
			
		||||
destEmpty=Destination List Empty
 | 
			
		||||
denyMsg=Access Denied
 | 
			
		||||
 | 
			
		||||
ecoDeduct=Deducted %cost%
 | 
			
		||||
ecoRefund=Refunded %cost%
 | 
			
		||||
ecoObtain=Obtained %cost% from Stargate %portal%
 | 
			
		||||
ecoInFunds=Insufficient Funds
 | 
			
		||||
 | 
			
		||||
createMsg=Gate Created
 | 
			
		||||
createNetDeny=You do not have access to that network
 | 
			
		||||
createGateDeny=You do not have access to that gate layout
 | 
			
		||||
createPersonal=Creating gate on personal network
 | 
			
		||||
createNameLength=Name too short or too long.
 | 
			
		||||
createExists=A gate by that name already exists
 | 
			
		||||
createFull=This network is full
 | 
			
		||||
createWorldDeny=You do not have access to that world
 | 
			
		||||
createConflict=Gate conflicts with existing gate
 | 
			
		||||
 | 
			
		||||
signRightClick=Right click
 | 
			
		||||
signToUse=to use gate
 | 
			
		||||
signRandom=Random
 | 
			
		||||
signDisconnected=Disconnected
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
prefix=[Stargate] 
 | 
			
		||||
teleportMsg=Teleported
 | 
			
		||||
destroyMsg=Gate Destroyed
 | 
			
		||||
invalidMsg=Invalid Destination
 | 
			
		||||
blockMsg=Destination Blocked
 | 
			
		||||
destEmpty=Destination List Empty
 | 
			
		||||
denyMsg=Access Denied
 | 
			
		||||
reloaded=Stargate Reloaded
 | 
			
		||||
 | 
			
		||||
ecoDeduct=Deducted %cost%
 | 
			
		||||
ecoRefund=Refunded %cost%
 | 
			
		||||
ecoObtain=Obtained %cost% from Stargate %portal%
 | 
			
		||||
ecoInFunds=Insufficient Funds
 | 
			
		||||
ecoLoadError=Vault was loaded, but no economy plugin could be hooked into
 | 
			
		||||
vaultLoadError=Economy is enabled but Vault could not be loaded. Economy disabled
 | 
			
		||||
vaultLoaded=Vault v%version% found
 | 
			
		||||
 | 
			
		||||
createMsg=Gate Created
 | 
			
		||||
createNetDeny=You do not have access to that network
 | 
			
		||||
createGateDeny=You do not have access to that gate layout
 | 
			
		||||
createPersonal=Creating gate on personal network
 | 
			
		||||
createNameLength=Name too short or too long.
 | 
			
		||||
createExists=A gate by that name already exists
 | 
			
		||||
createFull=This network is full
 | 
			
		||||
createWorldDeny=You do not have access to that world
 | 
			
		||||
createConflict=Gate conflicts with existing gate
 | 
			
		||||
 | 
			
		||||
signRightClick=Right click
 | 
			
		||||
signToUse=to use gate
 | 
			
		||||
signRandom=Random
 | 
			
		||||
signDisconnected=Disconnected
 | 
			
		||||
signInvalidGate=Invalid gate
 | 
			
		||||
 | 
			
		||||
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%
 | 
			
		||||
@@ -1,10 +1,10 @@
 | 
			
		||||
author=Manuestaire
 | 
			
		||||
prefix=[Stargate] 
 | 
			
		||||
teleportMsg=Teletransportado
 | 
			
		||||
destroyMsg=Portal Destruído
 | 
			
		||||
destroyMsg=Portal Destruído
 | 
			
		||||
invalidMsg=Elige Destino
 | 
			
		||||
blockMsg=Destino Bloqueado
 | 
			
		||||
destEmpty=La lista de destinos está vacía
 | 
			
		||||
destEmpty=La lista de destinos está vacía
 | 
			
		||||
denyMsg=Acceso denegado
 | 
			
		||||
 | 
			
		||||
ecoDeduct=Pagaste %cost%
 | 
			
		||||
@@ -14,11 +14,11 @@ ecoInFunds=No tienes suficiente dinero
 | 
			
		||||
 | 
			
		||||
createMsg=Portal creado
 | 
			
		||||
createNetDeny=No tienes acceso a esta red
 | 
			
		||||
createGateDeny=No tienes acceso a este diseño de portal
 | 
			
		||||
createGateDeny=No tienes acceso a este diseño de portal
 | 
			
		||||
createPersonal=Creando el portal en una red personal
 | 
			
		||||
createNameLength=Nombre demasiado largo o demasiado corto
 | 
			
		||||
createExists=Ya existe una puerta con este nombre
 | 
			
		||||
createFull=Esta red está llena
 | 
			
		||||
createFull=Esta red está llena
 | 
			
		||||
createWorldDeny=No tienes permisos para acceder a ese mundo
 | 
			
		||||
createConflict=El portal entra en conflicto con un portal ya existente
 | 
			
		||||
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
author=Dauphin14
 | 
			
		||||
author=Dauphin14
 | 
			
		||||
prefix=[Stargate] 
 | 
			
		||||
teleportMsg=Téléportation Réussie.
 | 
			
		||||
destroyMsg=Portail detruit.
 | 
			
		||||
							
								
								
									
										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%
 | 
			
		||||
							
								
								
									
										43
									
								
								src/main/resources/lang/nb-no.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/main/resources/lang/nb-no.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
author=EpicKnarvik97
 | 
			
		||||
prefix=[Stjerneport] 
 | 
			
		||||
teleportMsg=Teleporterte
 | 
			
		||||
destroyMsg=Port Ødelagt
 | 
			
		||||
invalidMsg=Ugyldig Destinasjon
 | 
			
		||||
blockMsg=Destinasjon Blokkert
 | 
			
		||||
destEmpty=Destinasjonslisten Er Tom
 | 
			
		||||
denyMsg=Tilgang Avslått
 | 
			
		||||
reloaded=Stjerneport Ble Lastet Inn På Nytt
 | 
			
		||||
 | 
			
		||||
ecoDeduct=Fratrekk %cost%
 | 
			
		||||
ecoRefund=Refundert %cost%
 | 
			
		||||
ecoObtain=Fikk %cost% fra Stjerneport %portal%
 | 
			
		||||
ecoInFunds=Manglende Midler
 | 
			
		||||
ecoLoadError=Vault ble lastet inn men ingen brukbar økonomi-utvidelse ble funnet
 | 
			
		||||
vaultLoadError=Økonomi er skrudd på, men Vault kunne ikke lastes inn. Økonomi er skrudd av
 | 
			
		||||
vaultLoaded=Vault v%version% funnet
 | 
			
		||||
 | 
			
		||||
createMsg=Port opprettet
 | 
			
		||||
createNetDeny=Du har ikke tilgang til det nettverket
 | 
			
		||||
createGateDeny=Du har ikke tilgang til den portutformingen
 | 
			
		||||
createPersonal=Oppretter port på personlig nettverk
 | 
			
		||||
createNameLength=Navnet er for kort eller for langt.
 | 
			
		||||
createExists=En port ved det navnet eksisterer allerede
 | 
			
		||||
createFull=Dette nettverket er fullt
 | 
			
		||||
createWorldDeny=Du har ikke tilgang til den verdenen
 | 
			
		||||
createConflict=Port er i konflikt med en eksisterende port
 | 
			
		||||
 | 
			
		||||
signRightClick=Høyreklikk
 | 
			
		||||
signToUse=for å bruke port
 | 
			
		||||
signRandom=Tilfeldig
 | 
			
		||||
signDisconnected=Koblet fra
 | 
			
		||||
 | 
			
		||||
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%
 | 
			
		||||
@@ -16,7 +16,7 @@ createMsg=Gate gemaakt
 | 
			
		||||
createNetDeny=Je hebt geen toegang tot dat netwerk.
 | 
			
		||||
createGateDeny=Je mag die Gate-Layout niet gebruiken
 | 
			
		||||
createPersonal=Gate op persoonlijk netwerk gemaakt.
 | 
			
		||||
createNameLength=Naam te lang of te kort.
 | 
			
		||||
createNameLength=Naam te chosenLanguage of te kort.
 | 
			
		||||
createExists=Er bestaat al een gate met die naam
 | 
			
		||||
createFull=Dit netwerk is vol.
 | 
			
		||||
createWorldDeny=Je mag niet in die wereld komen.
 | 
			
		||||
							
								
								
									
										43
									
								
								src/main/resources/lang/nn-no.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/main/resources/lang/nn-no.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
author=EpicKnarvik97
 | 
			
		||||
prefix=[Stjerneport] 
 | 
			
		||||
teleportMsg=Teleporterte
 | 
			
		||||
destroyMsg=Port Øydelagd
 | 
			
		||||
invalidMsg=Ugyldig Destinasjon
 | 
			
		||||
blockMsg=Destinasjon Blokkert
 | 
			
		||||
destEmpty=Destinasjonslista Er Tom
 | 
			
		||||
denyMsg=Tilgang Avslått
 | 
			
		||||
reloaded=Stjerneport Vart Lasta Inn På Nytt
 | 
			
		||||
 | 
			
		||||
ecoDeduct=Fråtrekk %cost%
 | 
			
		||||
ecoRefund=Refundert %cost%
 | 
			
		||||
ecoObtain=Mottok %cost% frå Stjerneport %portal%
 | 
			
		||||
ecoInFunds=Manglande Midlar
 | 
			
		||||
ecoLoadError=Vault vart lasta inn men inga brukbar økonomi-utviding vart funnen
 | 
			
		||||
vaultLoadError=Økonomi er skrudd på, men Vault kunne ikkje lastas inn. Økonomi er skrudd av
 | 
			
		||||
vaultLoaded=Vault v%version% funnen
 | 
			
		||||
 | 
			
		||||
createMsg=Port oppretta
 | 
			
		||||
createNetDeny=Du har ikkje tilgang til det nettverket
 | 
			
		||||
createGateDeny=Du har ikkje tilgang til den portutforminga
 | 
			
		||||
createPersonal=Opprettar port på personleg nettverk
 | 
			
		||||
createNameLength=Namnet er for kort eller for langt.
 | 
			
		||||
createExists=Ein port med det namnet eksisterar allereie
 | 
			
		||||
createFull=Dette nettverket er fullt
 | 
			
		||||
createWorldDeny=Du har ikkje tilgang til den verda
 | 
			
		||||
createConflict=Port er i konflikt med ein eksisterande port
 | 
			
		||||
 | 
			
		||||
signRightClick=Høgreklikk
 | 
			
		||||
signToUse=for å bruke port
 | 
			
		||||
signRandom=Tilfeldig
 | 
			
		||||
signDisconnected=Kopla frå
 | 
			
		||||
 | 
			
		||||
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%
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user