mirror of
				https://github.com/PlaceholderAPI/PlaceholderAPI
				synced 2025-10-30 18:03:43 +01:00 
			
		
		
		
	Merge pull request #434 from PlaceholderAPI/master
Update docs/wiki from master
This commit is contained in:
		
							
								
								
									
										18
									
								
								.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
								
							| @@ -23,25 +23,21 @@ about: Report bugs of PlaceholderAPI with this template | |||||||
| ## Bug Report | ## Bug Report | ||||||
|  |  | ||||||
| ### Issue | ### Issue | ||||||
| > What is the issue? Describe it like you would tell a friend. | <!-- What is the issue? Describe it like you would tell a friend. --> | ||||||
| <!-- Please write below this line to prevent formatting issues --> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### Expected behaviour | ### Expected behaviour | ||||||
| > What should PlaceholderAPI do? | <!-- What should PlaceholderAPI do? --> | ||||||
| <!-- Please write below this line to prevent formatting issues --> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### Actual behaviour | ### Actual behaviour | ||||||
| > What does PlaceholderAPI actually do? | <!-- What does PlaceholderAPI actually do? --> | ||||||
| <!-- Please write below this line to prevent formatting issues --> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### How to reproduce | ### How to reproduce | ||||||
| > What steps did you made, to get this bug? | <!-- What steps did you made, to get this bug? --> | ||||||
| <!-- Please write below this line to prevent formatting issues --> |  | ||||||
| 1.  | 1.  | ||||||
|  |  | ||||||
| ### Installed expansions | ### `/papi dump` output | ||||||
| > Please list all expansions that are displayed when running `/papi list` | <!-- Please provide the URL that was generated when using /papi dump --> | ||||||
| <!-- Please write below this line to prevent formatting issues --> |  | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								.github/ISSUE_TEMPLATE/feature_request.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/ISSUE_TEMPLATE/feature_request.md
									
									
									
									
										vendored
									
									
								
							| @@ -15,10 +15,9 @@ about: Request a update/change of the PlaceholderAPI-code | |||||||
| ## Feature Request | ## Feature Request | ||||||
|  |  | ||||||
| ### Type | ### Type | ||||||
| > What kind of request is this? (Multiple selections possible) | <!-- What kind of request is this? (Multiple selections possible) --> | ||||||
| <!-- | <!-- To select an option change the [ ] to [x] --> | ||||||
|       Please select the right options by replacing the [ ] with a [x] |  | ||||||
| --> |  | ||||||
| - [ ] New function for PlaceholderAPI.   | - [ ] New function for PlaceholderAPI.   | ||||||
| A new function that developers could use. | A new function that developers could use. | ||||||
| - [ ] Change to code (Internal).   | - [ ] Change to code (Internal).   | ||||||
| @@ -27,7 +26,6 @@ Changes to code that won't affect the end-user. | |||||||
| Changes to code that will affect the end-user (breaks stuff). | Changes to code that will affect the end-user (breaks stuff). | ||||||
| - [ ] Other: __________ <!-- Use this if none of the above matches your request --> | - [ ] Other: __________ <!-- Use this if none of the above matches your request --> | ||||||
|  |  | ||||||
| ### Info | ### Description | ||||||
| > What is the change?   | <!-- Describe what this suggested change should do and why it would be useful --> | ||||||
| > Please provide as much information (including links, images and code-snippeds) as possible. | <!-- When possible, add some code-examples to better illustrate the change --> | ||||||
| <!-- Please write below this line to prevent formatting issues --> |  | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							| @@ -1,8 +1,13 @@ | |||||||
| ## Please read | <!-- | ||||||
| Please make sure you checked the following: |   ### Please read ### | ||||||
| - You checked the [Pull requests] page for any upcoming changes. |   Please make sure you checked the following: | ||||||
| - You documented any public code that the end-user might use. |  | ||||||
| - You followed the [contributing file]  |   - You checked the Pull requests page for any upcoming changes. | ||||||
|  |   - You documented any public code that the end-user might use. | ||||||
|  |   - You followed the contributing file (https://github.com/PlaceholderAPI/PlaceholderAPI/tree/master/.github/CONTRIBUTING.md). | ||||||
|  | --> | ||||||
|  |  | ||||||
|  | ## Pull Request | ||||||
|  |  | ||||||
| ### Type | ### Type | ||||||
| <!-- | <!-- | ||||||
| @@ -14,12 +19,10 @@ Please make sure you checked the following: | |||||||
| - [ ] Other: __________ <!-- Use this if none of the above matches your request --> | - [ ] Other: __________ <!-- Use this if none of the above matches your request --> | ||||||
|  |  | ||||||
| ### Description | ### Description | ||||||
| > Provide additional information if needed. | <!-- What does your Pull request change? --> | ||||||
| <!-- Please type below this line --> |  | ||||||
|  | Closes N/A <!-- If your PR is based on an issue, change "N/A" the the issue ID (#id) --> | ||||||
|  |  | ||||||
|  |  | ||||||
| <!-- DO NOT ALTER ANYTHING BELOW THIS LINE! --> | <!-- DO NOT ALTER ANYTHING BELOW THIS LINE! --> | ||||||
|  |  | ||||||
| [Pull requests]: https://github.com/PlaceholderAPI/PlaceholderAPI/pulls |  | ||||||
| [contributing file]: https://github.com/PlaceholderAPI/PlaceholderAPI/tree/master/.github/CONTRIBUTING.md |  | ||||||
| [Wiki]: https://github.com/PlaceholderAPI/PlaceholderAPI/wiki | [Wiki]: https://github.com/PlaceholderAPI/PlaceholderAPI/wiki | ||||||
|   | |||||||
							
								
								
									
										58
									
								
								.github/workflows/wiki.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										58
									
								
								.github/workflows/wiki.yml
									
									
									
									
										vendored
									
									
								
							| @@ -10,43 +10,43 @@ on: | |||||||
|     # Only trigger when the push changes any files in the wiki-folder. |     # Only trigger when the push changes any files in the wiki-folder. | ||||||
|     # |     # | ||||||
|     paths: |     paths: | ||||||
|     - 'wiki/**' |       - 'wiki/**' | ||||||
|     branches: |     branches: | ||||||
|     - 'docs/wiki' |       - 'docs/wiki' | ||||||
|     # |     # | ||||||
|     # Releases cause this action to also fire. |     # Releases cause this action to also fire. | ||||||
|     # Using this prevents this problem. |     # Using this prevents this problem. | ||||||
|     # |     # | ||||||
|     tags-ignore: |     tags-ignore: | ||||||
|     - '**' |       - '**' | ||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   update: |   update: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     steps: |     steps: | ||||||
|     - name: 'Checkout Code' |       - name: 'Checkout Code' | ||||||
|       uses: actions/Checkout@v2 |         uses: actions/Checkout@v2 | ||||||
|     - name: 'Update Wiki' |       - name: 'Update Wiki' | ||||||
|       uses: docker://decathlon/wiki-page-creator-action:latest |         uses: docker://decathlon/wiki-page-creator-action:latest | ||||||
|       env: |         env: | ||||||
|         # |           # | ||||||
|         # We can use the E-Mail and Name of the GitHub Actions account |           # We can use the E-Mail and Name of the GitHub Actions account | ||||||
|         # for our convenience. |           # for our convenience. | ||||||
|         # |           # | ||||||
|         ACTION_MAIL: 'actions@github.com' |           ACTION_MAIL: 'actions@github.com' | ||||||
|         ACTION_NAME: 'github-actions[bot]' |           ACTION_NAME: 'github-actions[bot]' | ||||||
|         # |           # | ||||||
|         # We (sadly) have to use a PAT (Personal Access Token) for this action. |           # We (sadly) have to use a PAT (Personal Access Token) for this action. | ||||||
|         # |           # | ||||||
|         GH_PAT: '${{ secrets.WORKFLOWPAT }}' |           GH_PAT: '${{ secrets.WORKFLOWPAT }}' | ||||||
|         OWNER: 'PlaceholderAPI' |           OWNER: 'PlaceholderAPI' | ||||||
|         REPO_NAME: 'PlaceholderAPI' |           REPO_NAME: 'PlaceholderAPI' | ||||||
|         # |           # | ||||||
|         # We only want to target files in the wiki folder |           # We only want to target files in the wiki folder | ||||||
|         # |           # | ||||||
|         MD_FOLDER: 'wiki' |           MD_FOLDER: 'wiki' | ||||||
|         WIKI_PUSH_MESSAGE: '${{ github.event.commits[0].message }}' |           WIKI_PUSH_MESSAGE: '${{ github.event.commits[0].message }}' | ||||||
|         # |           # | ||||||
|         # We skip/ignore the README.md file in the Wiki folder |           # We skip/ignore the README.md file in the Wiki folder | ||||||
|         # |           # | ||||||
|         SKIP_MD: README.md |           SKIP_MD: README.md | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ | |||||||
| [ci]: http://ci.extendedclip.com/job/PlaceholderAPI/ | [ci]: http://ci.extendedclip.com/job/PlaceholderAPI/ | ||||||
| [ciImg]: http://ci.extendedclip.com/buildStatus/icon?job=PlaceholderAPI | [ciImg]: http://ci.extendedclip.com/buildStatus/icon?job=PlaceholderAPI | ||||||
|  |  | ||||||
| [APIversionImg]: https://img.shields.io/nexus/r/http/repo.extendedclip.com/me.clip/placeholderapi.svg?label=API-Version | [APIversionImg]: https://img.shields.io/nexus/placeholderapi/me.clip/placeholderapi?server=https%3A%2F%2Frepo.extendedclip.com&label=API%20Version | ||||||
| [logo]: https://i.imgur.com/Ea4PURv.png | [logo]: https://i.imgur.com/Ea4PURv.png | ||||||
| <!-- The stuff above isn't visible in the readme --> | <!-- The stuff above isn't visible in the readme --> | ||||||
|  |  | ||||||
| @@ -27,7 +27,7 @@ | |||||||
|  |  | ||||||
| Support for specific plugins are provided either by the plugin itself or through expansions. The expansions may be downloaded in-game through the PAPI Expansion Cloud. There are currently over 150+ expansions that support a wide variety of plugins, such as Essentials, Factions, LuckPerms, and Vault.  | Support for specific plugins are provided either by the plugin itself or through expansions. The expansions may be downloaded in-game through the PAPI Expansion Cloud. There are currently over 150+ expansions that support a wide variety of plugins, such as Essentials, Factions, LuckPerms, and Vault.  | ||||||
|  |  | ||||||
| PlaceholderAPI has been downloaded over 300,000 times and has been used concurrently on over 20,000 servers, which makes it a must-have for a server of any type or scale. | PlaceholderAPI has been downloaded over 400,000 times and has been used concurrently on over 20,000 servers, which makes it a must-have for a server of any type or scale. | ||||||
|  |  | ||||||
| <!-- TODO: Add contributing section --> | <!-- TODO: Add contributing section --> | ||||||
| <!-- TODO: Add expansion creation section (possibly add to a wiki?) --> | <!-- TODO: Add expansion creation section (possibly add to a wiki?) --> | ||||||
|   | |||||||
							
								
								
									
										132
									
								
								build.gradle
									
									
									
									
									
								
							
							
						
						
									
										132
									
								
								build.gradle
									
									
									
									
									
								
							| @@ -1,105 +1,119 @@ | |||||||
| plugins { | plugins { | ||||||
| 	id "java" |     id "java" | ||||||
| 	id "maven-publish" |     id "maven-publish" | ||||||
| 	id "net.minecrell.licenser" version "0.4.1" |     id "net.minecrell.licenser" version "0.4.1" | ||||||
| 	id "com.github.johnrengelman.shadow" version "6.0.0" |     id "com.github.johnrengelman.shadow" version "6.0.0" | ||||||
| } | } | ||||||
|  |  | ||||||
| group "me.clip" | group "me.clip" | ||||||
| version "2.10.8-DEV-${System.getProperty("BUILD_NUMBER")}" | version "2.10.10-DEV-${System.getProperty("BUILD_NUMBER")}" | ||||||
|  |  | ||||||
| description "An awesome placeholder provider!" | description "An awesome placeholder provider!" | ||||||
|  |  | ||||||
| repositories { | repositories { | ||||||
| 	mavenCentral() |     mavenCentral() | ||||||
|  |  | ||||||
| 	maven({ url = "https://repo.codemc.org/repository/maven-public" }) |     maven({ url = "https://repo.codemc.org/repository/maven-public" }) | ||||||
| 	maven({ url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" }) |     maven({ url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" }) | ||||||
| } | } | ||||||
|  |  | ||||||
| dependencies { | dependencies { | ||||||
| 	implementation "com.google.code.gson:gson:2.8.6" |     implementation "com.google.code.gson:gson:2.8.6" | ||||||
| 	implementation "org.bstats:bstats-bukkit:1.5" |     implementation "org.bstats:bstats-bukkit:1.5" | ||||||
|  |  | ||||||
| 	compileOnly "org.spigotmc:spigot-api:1.16.1-R0.1-SNAPSHOT" |     compileOnly "org.spigotmc:spigot-api:1.16.1-R0.1-SNAPSHOT" | ||||||
| 	compileOnly "org.jetbrains:annotations:19.0.0" |     compileOnly "org.jetbrains:annotations:19.0.0" | ||||||
|  |  | ||||||
| 	testImplementation "org.openjdk.jmh:jmh-core:1.23" |     testImplementation "org.openjdk.jmh:jmh-core:1.23" | ||||||
| 	testImplementation "org.openjdk.jmh:jmh-generator-annprocess:1.23" |     testImplementation "org.openjdk.jmh:jmh-generator-annprocess:1.23" | ||||||
|  |  | ||||||
| 	testCompile "org.junit.jupiter:junit-jupiter-engine:5.6.2" |     testCompile "org.junit.jupiter:junit-jupiter-engine:5.6.2" | ||||||
| 	testRuntime "org.junit.jupiter:junit-jupiter-engine:5.6.2" |     testRuntime "org.junit.jupiter:junit-jupiter-engine:5.6.2" | ||||||
| } | } | ||||||
|  |  | ||||||
| processResources { | processResources { | ||||||
| 	from(sourceSets.main.resources.srcDirs) { |     from(sourceSets.main.resources.srcDirs) { | ||||||
| 		filter org.apache.tools.ant.filters.ReplaceTokens, tokens: [name: rootProject.name, version: project.version.toString(), description: project.description] |         filter org.apache.tools.ant.filters.ReplaceTokens, tokens: [name: rootProject.name, version: project.version.toString(), description: project.description] | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| tasks.withType(JavaCompile) { | tasks.withType(JavaCompile) { | ||||||
| 	options.encoding = "UTF-8" |     options.encoding = "UTF-8" | ||||||
|  |  | ||||||
| 	sourceCompatibility = JavaVersion.VERSION_1_8 |     sourceCompatibility = JavaVersion.VERSION_1_8 | ||||||
| 	targetCompatibility = JavaVersion.VERSION_1_8 |     targetCompatibility = JavaVersion.VERSION_1_8 | ||||||
| } | } | ||||||
|  |  | ||||||
| shadowJar { | shadowJar { | ||||||
| 	archiveClassifier.set("") |     archiveClassifier.set("") | ||||||
|  |  | ||||||
| 	relocate "org.bstats", "me.clip.placeholderapi.metrics" |     relocate "org.bstats", "me.clip.placeholderapi.metrics" | ||||||
| 	relocate "com.google.gson", "me.clip.placeholderapi.libs.gson" |     relocate "com.google.gson", "me.clip.placeholderapi.libs.gson" | ||||||
| } | } | ||||||
|  |  | ||||||
| license { | license { | ||||||
| 	matching('**/*.java') { |     include '**/*.java' | ||||||
| 		header = file('headers/main.txt') |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	matching('**/JSONMessage.java') { |     matching('**/*.java') { | ||||||
| 		header = file('headers/jsonmessage.txt') |         header = file('config/headers/main.txt') | ||||||
| 	} |     } | ||||||
|  |  | ||||||
| 	ext { |     matching('**/JSONMessage.java') { | ||||||
| 		year = 2020 |         header = file('config/headers/jsonmessage.txt') | ||||||
| 	} |     } | ||||||
|  |  | ||||||
|  |     ext { | ||||||
|  |         year = 2020 | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| test { | test { | ||||||
| 	useJUnitPlatform() |     useJUnitPlatform() | ||||||
| } | } | ||||||
|  |  | ||||||
| sourceSets { | sourceSets { | ||||||
| 	test.compileClasspath += configurations.compileOnly |     test.compileClasspath += configurations.compileOnly | ||||||
| 	test.runtimeClasspath += configurations.compileOnly |     test.runtimeClasspath += configurations.compileOnly | ||||||
| } | } | ||||||
|  |  | ||||||
| publishing { | publishing { | ||||||
| 	repositories { |     repositories { | ||||||
| 		maven { |         maven { | ||||||
| 			if (version.contains("-DEV-")) { |             if (version.contains("-DEV-")) { | ||||||
| 				url = uri("https://repo.extendedclip.com/content/repositories/dev/") |                 url = uri("https://repo.extendedclip.com/content/repositories/dev/") | ||||||
| 			} else { |             } else { | ||||||
| 				url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/") |                 url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/") | ||||||
| 			} |             } | ||||||
|  |  | ||||||
| 			credentials { |             credentials { | ||||||
| 				username = System.getenv("JENKINS_USER") |                 username = System.getenv("JENKINS_USER") | ||||||
| 				password = System.getenv("JENKINS_PASS") |                 password = System.getenv("JENKINS_PASS") | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|  |  | ||||||
| 	publications { |     publications { | ||||||
| 		mavenJava(MavenPublication) { |         mavenJava(MavenPublication) { | ||||||
| 			from components.java |             artifactId = "placeholderapi" | ||||||
|  |  | ||||||
| 			pom.withXml { |             from components.java | ||||||
| 				asNode().appendNode("packaging", "jar") |  | ||||||
| 				asNode().remove(asNode().get("dependencies")) |             pom.withXml { | ||||||
| 			} |  | ||||||
| 		} |                 // some are having issues with bstats so we might need to add that to the pom as well | ||||||
| 	} |  | ||||||
|  |                 asNode().appendNode("packaging", "jar") | ||||||
|  |                 asNode().remove(asNode().get("dependencies")) | ||||||
|  |  | ||||||
|  |                 def dependenciesNode = asNode().appendNode("dependencies") | ||||||
|  |                 // jetbrains annotations | ||||||
|  |                 def jetbrainsAnnotations = dependenciesNode.appendNode("dependency") | ||||||
|  |                 jetbrainsAnnotations.appendNode("groupId", "org.jetbrains") | ||||||
|  |                 jetbrainsAnnotations.appendNode("artifactId", "annotations") | ||||||
|  |                 jetbrainsAnnotations.appendNode("version", "19.0.0") | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| publish.dependsOn clean, test, jar | publish.dependsOn clean, test, jar | ||||||
							
								
								
									
										569
									
								
								config/style/daddystyle.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										569
									
								
								config/style/daddystyle.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,569 @@ | |||||||
|  | <code_scheme name="DaddyStyle" version="173"> | ||||||
|  |   <option name="OTHER_INDENT_OPTIONS"> | ||||||
|  |     <value> | ||||||
|  |       <option name="INDENT_SIZE" value="2" /> | ||||||
|  |       <option name="CONTINUATION_INDENT_SIZE" value="4" /> | ||||||
|  |       <option name="TAB_SIZE" value="2" /> | ||||||
|  |     </value> | ||||||
|  |   </option> | ||||||
|  |   <option name="RIGHT_MARGIN" value="100" /> | ||||||
|  |   <AndroidXmlCodeStyleSettings> | ||||||
|  |     <option name="USE_CUSTOM_SETTINGS" value="true" /> | ||||||
|  |     <option name="LAYOUT_SETTINGS"> | ||||||
|  |       <value> | ||||||
|  |         <option name="INSERT_BLANK_LINE_BEFORE_TAG" value="false" /> | ||||||
|  |       </value> | ||||||
|  |     </option> | ||||||
|  |   </AndroidXmlCodeStyleSettings> | ||||||
|  |   <JSCodeStyleSettings version="0"> | ||||||
|  |     <option name="INDENT_CHAINED_CALLS" value="false" /> | ||||||
|  |   </JSCodeStyleSettings> | ||||||
|  |   <JavaCodeStyleSettings> | ||||||
|  |     <option name="INSERT_INNER_CLASS_IMPORTS" value="true" /> | ||||||
|  |     <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" /> | ||||||
|  |     <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" /> | ||||||
|  |     <option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND"> | ||||||
|  |       <value /> | ||||||
|  |     </option> | ||||||
|  |     <option name="IMPORT_LAYOUT_TABLE"> | ||||||
|  |       <value> | ||||||
|  |         <package name="" withSubpackages="true" static="true" /> | ||||||
|  |         <emptyLine /> | ||||||
|  |         <package name="" withSubpackages="true" static="false" /> | ||||||
|  |       </value> | ||||||
|  |     </option> | ||||||
|  |     <option name="JD_ALIGN_PARAM_COMMENTS" value="false" /> | ||||||
|  |     <option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" /> | ||||||
|  |     <option name="JD_P_AT_EMPTY_LINES" value="false" /> | ||||||
|  |     <option name="JD_KEEP_EMPTY_PARAMETER" value="false" /> | ||||||
|  |     <option name="JD_KEEP_EMPTY_EXCEPTION" value="false" /> | ||||||
|  |     <option name="JD_KEEP_EMPTY_RETURN" value="false" /> | ||||||
|  |   </JavaCodeStyleSettings> | ||||||
|  |   <Objective-C> | ||||||
|  |     <option name="INDENT_NAMESPACE_MEMBERS" value="0" /> | ||||||
|  |     <option name="INDENT_C_STRUCT_MEMBERS" value="2" /> | ||||||
|  |     <option name="INDENT_CLASS_MEMBERS" value="2" /> | ||||||
|  |     <option name="INDENT_VISIBILITY_KEYWORDS" value="1" /> | ||||||
|  |     <option name="INDENT_INSIDE_CODE_BLOCK" value="2" /> | ||||||
|  |     <option name="KEEP_STRUCTURES_IN_ONE_LINE" value="true" /> | ||||||
|  |     <option name="FUNCTION_PARAMETERS_WRAP" value="5" /> | ||||||
|  |     <option name="FUNCTION_CALL_ARGUMENTS_WRAP" value="5" /> | ||||||
|  |     <option name="TEMPLATE_CALL_ARGUMENTS_WRAP" value="5" /> | ||||||
|  |     <option name="TEMPLATE_CALL_ARGUMENTS_ALIGN_MULTILINE" value="true" /> | ||||||
|  |     <option name="ALIGN_INIT_LIST_IN_COLUMNS" value="false" /> | ||||||
|  |     <option name="SPACE_BEFORE_SUPERCLASS_COLON" value="false" /> | ||||||
|  |   </Objective-C> | ||||||
|  |   <Objective-C-extensions> | ||||||
|  |     <option name="GENERATE_INSTANCE_VARIABLES_FOR_PROPERTIES" value="ASK" /> | ||||||
|  |     <option name="RELEASE_STYLE" value="IVAR" /> | ||||||
|  |     <option name="TYPE_QUALIFIERS_PLACEMENT" value="BEFORE" /> | ||||||
|  |     <file> | ||||||
|  |       <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" /> | ||||||
|  |       <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" /> | ||||||
|  |       <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" /> | ||||||
|  |       <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" /> | ||||||
|  |       <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" /> | ||||||
|  |       <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" /> | ||||||
|  |       <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" /> | ||||||
|  |       <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" /> | ||||||
|  |       <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" /> | ||||||
|  |     </file> | ||||||
|  |     <class> | ||||||
|  |       <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" /> | ||||||
|  |       <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" /> | ||||||
|  |       <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" /> | ||||||
|  |       <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" /> | ||||||
|  |       <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" /> | ||||||
|  |       <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" /> | ||||||
|  |     </class> | ||||||
|  |     <extensions> | ||||||
|  |       <pair source="cc" header="h" /> | ||||||
|  |       <pair source="c" header="h" /> | ||||||
|  |     </extensions> | ||||||
|  |   </Objective-C-extensions> | ||||||
|  |   <Python> | ||||||
|  |     <option name="USE_CONTINUATION_INDENT_FOR_ARGUMENTS" value="true" /> | ||||||
|  |   </Python> | ||||||
|  |   <TypeScriptCodeStyleSettings version="0"> | ||||||
|  |     <option name="INDENT_CHAINED_CALLS" value="false" /> | ||||||
|  |   </TypeScriptCodeStyleSettings> | ||||||
|  |   <XML> | ||||||
|  |     <option name="XML_ALIGN_ATTRIBUTES" value="false" /> | ||||||
|  |     <option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" /> | ||||||
|  |   </XML> | ||||||
|  |   <codeStyleSettings language="CSS"> | ||||||
|  |     <indentOptions> | ||||||
|  |       <option name="INDENT_SIZE" value="2" /> | ||||||
|  |       <option name="CONTINUATION_INDENT_SIZE" value="4" /> | ||||||
|  |       <option name="TAB_SIZE" value="2" /> | ||||||
|  |     </indentOptions> | ||||||
|  |   </codeStyleSettings> | ||||||
|  |   <codeStyleSettings language="ECMA Script Level 4"> | ||||||
|  |     <option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> | ||||||
|  |     <option name="ALIGN_MULTILINE_PARAMETERS" value="false" /> | ||||||
|  |     <option name="ALIGN_MULTILINE_FOR" value="false" /> | ||||||
|  |     <option name="CALL_PARAMETERS_WRAP" value="1" /> | ||||||
|  |     <option name="METHOD_PARAMETERS_WRAP" value="1" /> | ||||||
|  |     <option name="EXTENDS_LIST_WRAP" value="1" /> | ||||||
|  |     <option name="BINARY_OPERATION_WRAP" value="1" /> | ||||||
|  |     <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> | ||||||
|  |     <option name="TERNARY_OPERATION_WRAP" value="1" /> | ||||||
|  |     <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" /> | ||||||
|  |     <option name="FOR_STATEMENT_WRAP" value="1" /> | ||||||
|  |     <option name="ARRAY_INITIALIZER_WRAP" value="1" /> | ||||||
|  |     <option name="IF_BRACE_FORCE" value="3" /> | ||||||
|  |     <option name="DOWHILE_BRACE_FORCE" value="3" /> | ||||||
|  |     <option name="WHILE_BRACE_FORCE" value="3" /> | ||||||
|  |     <option name="FOR_BRACE_FORCE" value="3" /> | ||||||
|  |   </codeStyleSettings> | ||||||
|  |   <codeStyleSettings language="HTML"> | ||||||
|  |     <indentOptions> | ||||||
|  |       <option name="INDENT_SIZE" value="2" /> | ||||||
|  |       <option name="CONTINUATION_INDENT_SIZE" value="4" /> | ||||||
|  |       <option name="TAB_SIZE" value="2" /> | ||||||
|  |     </indentOptions> | ||||||
|  |   </codeStyleSettings> | ||||||
|  |   <codeStyleSettings language="JAVA"> | ||||||
|  |     <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" /> | ||||||
|  |     <option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> | ||||||
|  |     <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" /> | ||||||
|  |     <option name="ALIGN_MULTILINE_PARAMETERS" value="false" /> | ||||||
|  |     <option name="ALIGN_MULTILINE_RESOURCES" value="false" /> | ||||||
|  |     <option name="ALIGN_MULTILINE_FOR" value="false" /> | ||||||
|  |     <option name="CALL_PARAMETERS_WRAP" value="1" /> | ||||||
|  |     <option name="METHOD_PARAMETERS_WRAP" value="1" /> | ||||||
|  |     <option name="EXTENDS_LIST_WRAP" value="1" /> | ||||||
|  |     <option name="THROWS_KEYWORD_WRAP" value="1" /> | ||||||
|  |     <option name="METHOD_CALL_CHAIN_WRAP" value="1" /> | ||||||
|  |     <option name="BINARY_OPERATION_WRAP" value="1" /> | ||||||
|  |     <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> | ||||||
|  |     <option name="TERNARY_OPERATION_WRAP" value="1" /> | ||||||
|  |     <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" /> | ||||||
|  |     <option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="true" /> | ||||||
|  |     <option name="KEEP_SIMPLE_LAMBDAS_IN_ONE_LINE" value="true" /> | ||||||
|  |     <option name="KEEP_SIMPLE_CLASSES_IN_ONE_LINE" value="true" /> | ||||||
|  |     <option name="FOR_STATEMENT_WRAP" value="1" /> | ||||||
|  |     <option name="ARRAY_INITIALIZER_WRAP" value="1" /> | ||||||
|  |     <option name="WRAP_COMMENTS" value="true" /> | ||||||
|  |     <option name="IF_BRACE_FORCE" value="3" /> | ||||||
|  |     <option name="DOWHILE_BRACE_FORCE" value="3" /> | ||||||
|  |     <option name="WHILE_BRACE_FORCE" value="3" /> | ||||||
|  |     <option name="FOR_BRACE_FORCE" value="3" /> | ||||||
|  |     <indentOptions> | ||||||
|  |       <option name="INDENT_SIZE" value="2" /> | ||||||
|  |       <option name="CONTINUATION_INDENT_SIZE" value="4" /> | ||||||
|  |       <option name="TAB_SIZE" value="2" /> | ||||||
|  |     </indentOptions> | ||||||
|  |   </codeStyleSettings> | ||||||
|  |   <codeStyleSettings language="JSON"> | ||||||
|  |     <indentOptions> | ||||||
|  |       <option name="CONTINUATION_INDENT_SIZE" value="4" /> | ||||||
|  |       <option name="TAB_SIZE" value="2" /> | ||||||
|  |     </indentOptions> | ||||||
|  |   </codeStyleSettings> | ||||||
|  |   <codeStyleSettings language="JavaScript"> | ||||||
|  |     <option name="RIGHT_MARGIN" value="80" /> | ||||||
|  |     <option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> | ||||||
|  |     <option name="ALIGN_MULTILINE_PARAMETERS" value="false" /> | ||||||
|  |     <option name="ALIGN_MULTILINE_FOR" value="false" /> | ||||||
|  |     <option name="CALL_PARAMETERS_WRAP" value="1" /> | ||||||
|  |     <option name="METHOD_PARAMETERS_WRAP" value="1" /> | ||||||
|  |     <option name="BINARY_OPERATION_WRAP" value="1" /> | ||||||
|  |     <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> | ||||||
|  |     <option name="TERNARY_OPERATION_WRAP" value="1" /> | ||||||
|  |     <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" /> | ||||||
|  |     <option name="FOR_STATEMENT_WRAP" value="1" /> | ||||||
|  |     <option name="ARRAY_INITIALIZER_WRAP" value="1" /> | ||||||
|  |     <option name="IF_BRACE_FORCE" value="3" /> | ||||||
|  |     <option name="DOWHILE_BRACE_FORCE" value="3" /> | ||||||
|  |     <option name="WHILE_BRACE_FORCE" value="3" /> | ||||||
|  |     <option name="FOR_BRACE_FORCE" value="3" /> | ||||||
|  |     <indentOptions> | ||||||
|  |       <option name="INDENT_SIZE" value="2" /> | ||||||
|  |       <option name="TAB_SIZE" value="2" /> | ||||||
|  |     </indentOptions> | ||||||
|  |   </codeStyleSettings> | ||||||
|  |   <codeStyleSettings language="ObjectiveC"> | ||||||
|  |     <option name="RIGHT_MARGIN" value="80" /> | ||||||
|  |     <option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" /> | ||||||
|  |     <option name="BLANK_LINES_BEFORE_IMPORTS" value="0" /> | ||||||
|  |     <option name="BLANK_LINES_AFTER_IMPORTS" value="0" /> | ||||||
|  |     <option name="BLANK_LINES_AROUND_CLASS" value="0" /> | ||||||
|  |     <option name="BLANK_LINES_AROUND_METHOD" value="0" /> | ||||||
|  |     <option name="BLANK_LINES_AROUND_METHOD_IN_INTERFACE" value="0" /> | ||||||
|  |     <option name="ALIGN_MULTILINE_BINARY_OPERATION" value="false" /> | ||||||
|  |     <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> | ||||||
|  |     <option name="FOR_STATEMENT_WRAP" value="1" /> | ||||||
|  |     <option name="ASSIGNMENT_WRAP" value="1" /> | ||||||
|  |     <indentOptions> | ||||||
|  |       <option name="INDENT_SIZE" value="2" /> | ||||||
|  |       <option name="CONTINUATION_INDENT_SIZE" value="4" /> | ||||||
|  |     </indentOptions> | ||||||
|  |   </codeStyleSettings> | ||||||
|  |   <codeStyleSettings language="PROTO"> | ||||||
|  |     <option name="RIGHT_MARGIN" value="80" /> | ||||||
|  |     <indentOptions> | ||||||
|  |       <option name="INDENT_SIZE" value="2" /> | ||||||
|  |       <option name="CONTINUATION_INDENT_SIZE" value="2" /> | ||||||
|  |       <option name="TAB_SIZE" value="2" /> | ||||||
|  |     </indentOptions> | ||||||
|  |   </codeStyleSettings> | ||||||
|  |   <codeStyleSettings language="Python"> | ||||||
|  |     <option name="RIGHT_MARGIN" value="80" /> | ||||||
|  |     <option name="ALIGN_MULTILINE_PARAMETERS" value="false" /> | ||||||
|  |     <indentOptions> | ||||||
|  |       <option name="INDENT_SIZE" value="2" /> | ||||||
|  |       <option name="CONTINUATION_INDENT_SIZE" value="4" /> | ||||||
|  |       <option name="TAB_SIZE" value="2" /> | ||||||
|  |     </indentOptions> | ||||||
|  |   </codeStyleSettings> | ||||||
|  |   <codeStyleSettings language="SASS"> | ||||||
|  |     <indentOptions> | ||||||
|  |       <option name="CONTINUATION_INDENT_SIZE" value="4" /> | ||||||
|  |       <option name="TAB_SIZE" value="2" /> | ||||||
|  |     </indentOptions> | ||||||
|  |   </codeStyleSettings> | ||||||
|  |   <codeStyleSettings language="SCSS"> | ||||||
|  |     <indentOptions> | ||||||
|  |       <option name="CONTINUATION_INDENT_SIZE" value="4" /> | ||||||
|  |       <option name="TAB_SIZE" value="2" /> | ||||||
|  |     </indentOptions> | ||||||
|  |   </codeStyleSettings> | ||||||
|  |   <codeStyleSettings language="TypeScript"> | ||||||
|  |     <indentOptions> | ||||||
|  |       <option name="INDENT_SIZE" value="2" /> | ||||||
|  |       <option name="TAB_SIZE" value="2" /> | ||||||
|  |     </indentOptions> | ||||||
|  |   </codeStyleSettings> | ||||||
|  |   <codeStyleSettings language="XML"> | ||||||
|  |     <indentOptions> | ||||||
|  |       <option name="INDENT_SIZE" value="2" /> | ||||||
|  |       <option name="CONTINUATION_INDENT_SIZE" value="2" /> | ||||||
|  |       <option name="TAB_SIZE" value="2" /> | ||||||
|  |     </indentOptions> | ||||||
|  |     <arrangement> | ||||||
|  |       <rules> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>xmlns:android</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>^$</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>xmlns:.*</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>^$</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |             <order>BY_NAME</order> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:id</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>style</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>^$</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>^$</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |             <order>BY_NAME</order> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:.*Style</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |             <order>BY_NAME</order> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:layout_width</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:layout_height</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:layout_weight</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:layout_margin</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:layout_marginTop</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:layout_marginBottom</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:layout_marginStart</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:layout_marginEnd</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:layout_marginLeft</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:layout_marginRight</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:layout_.*</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |             <order>BY_NAME</order> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:padding</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:paddingTop</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:paddingBottom</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:paddingStart</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:paddingEnd</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:paddingLeft</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*:paddingRight</NAME> | ||||||
|  |                 <XML_ATTRIBUTE /> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*</NAME> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |             <order>BY_NAME</order> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*</NAME> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/apk/res-auto</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |             <order>BY_NAME</order> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*</NAME> | ||||||
|  |                 <XML_NAMESPACE>http://schemas.android.com/tools</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |             <order>BY_NAME</order> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |         <section> | ||||||
|  |           <rule> | ||||||
|  |             <match> | ||||||
|  |               <AND> | ||||||
|  |                 <NAME>.*</NAME> | ||||||
|  |                 <XML_NAMESPACE>.*</XML_NAMESPACE> | ||||||
|  |               </AND> | ||||||
|  |             </match> | ||||||
|  |             <order>BY_NAME</order> | ||||||
|  |           </rule> | ||||||
|  |         </section> | ||||||
|  |       </rules> | ||||||
|  |     </arrangement> | ||||||
|  |   </codeStyleSettings> | ||||||
|  |   <codeStyleSettings language="protobuf"> | ||||||
|  |     <option name="RIGHT_MARGIN" value="80" /> | ||||||
|  |     <indentOptions> | ||||||
|  |       <option name="INDENT_SIZE" value="2" /> | ||||||
|  |       <option name="CONTINUATION_INDENT_SIZE" value="2" /> | ||||||
|  |       <option name="TAB_SIZE" value="2" /> | ||||||
|  |     </indentOptions> | ||||||
|  |   </codeStyleSettings> | ||||||
|  | </code_scheme> | ||||||
| @@ -1 +1 @@ | |||||||
| rootProject.name = 'placeholderapi' | rootProject.name = 'PlaceholderAPI' | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ package me.clip.placeholderapi; | |||||||
|  |  | ||||||
| import com.google.common.collect.ImmutableSet; | import com.google.common.collect.ImmutableSet; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.regex.Matcher; | import java.util.regex.Matcher; | ||||||
| import java.util.regex.Pattern; | import java.util.regex.Pattern; | ||||||
| @@ -37,7 +38,6 @@ import org.bukkit.entity.Player; | |||||||
| import org.bukkit.plugin.Plugin; | import org.bukkit.plugin.Plugin; | ||||||
| import org.jetbrains.annotations.ApiStatus; | import org.jetbrains.annotations.ApiStatus; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Nullable; |  | ||||||
|  |  | ||||||
| public final class PlaceholderAPI { | public final class PlaceholderAPI { | ||||||
|  |  | ||||||
| @@ -64,7 +64,7 @@ public final class PlaceholderAPI { | |||||||
|    * @return String containing all translated placeholders |    * @return String containing all translated placeholders | ||||||
|    */ |    */ | ||||||
|   @NotNull |   @NotNull | ||||||
|   public static String setPlaceholders(@Nullable final OfflinePlayer player, |   public static String setPlaceholders(final OfflinePlayer player, | ||||||
|       @NotNull final String text) { |       @NotNull final String text) { | ||||||
|     return REPLACER_PERCENT.apply(text, player, |     return REPLACER_PERCENT.apply(text, player, | ||||||
|         PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion); |         PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion); | ||||||
| @@ -79,11 +79,37 @@ public final class PlaceholderAPI { | |||||||
|    * @return String containing all translated placeholders |    * @return String containing all translated placeholders | ||||||
|    */ |    */ | ||||||
|   @NotNull |   @NotNull | ||||||
|   public static List<String> setPlaceholders(@Nullable final OfflinePlayer player, |   public static List<String> setPlaceholders(final OfflinePlayer player, | ||||||
|       @NotNull final List<@NotNull String> text) { |       @NotNull final List<@NotNull String> text) { | ||||||
|     return text.stream().map(line -> setPlaceholders(player, line)).collect(Collectors.toList()); |     return text.stream().map(line -> setPlaceholders(player, line)).collect(Collectors.toList()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Translates all placeholders into their corresponding values. | ||||||
|  |    * <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}. | ||||||
|  |    * | ||||||
|  |    * @param player Player to parse the placeholders against | ||||||
|  |    * @param text Text to set the placeholder values in | ||||||
|  |    * @return String containing all translated placeholders | ||||||
|  |    */ | ||||||
|  |   @NotNull | ||||||
|  |   public static String setPlaceholders(final Player player, @NotNull String text) { | ||||||
|  |     return setPlaceholders(((OfflinePlayer) player), text); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Translates all placeholders into their corresponding values. | ||||||
|  |    * <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}. | ||||||
|  |    * | ||||||
|  |    * @param player Player to parse the placeholders against | ||||||
|  |    * @param text List of Strings to set the placeholder values in | ||||||
|  |    * @return String containing all translated placeholders | ||||||
|  |    */ | ||||||
|  |   @NotNull | ||||||
|  |   public static List<String> setPlaceholders(final Player player, @NotNull List<@NotNull String> text) { | ||||||
|  |     return setPlaceholders(((OfflinePlayer) player), text); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Translates all placeholders into their corresponding values. |    * Translates all placeholders into their corresponding values. | ||||||
|    * <br>The pattern of a valid placeholder is {@literal {<identifier>_<params>}}. |    * <br>The pattern of a valid placeholder is {@literal {<identifier>_<params>}}. | ||||||
| @@ -93,7 +119,7 @@ public final class PlaceholderAPI { | |||||||
|    * @return String containing all translated placeholders |    * @return String containing all translated placeholders | ||||||
|    */ |    */ | ||||||
|   @NotNull |   @NotNull | ||||||
|   public static String setBracketPlaceholders(@Nullable final OfflinePlayer player, |   public static String setBracketPlaceholders(final OfflinePlayer player, | ||||||
|       @NotNull final String text) { |       @NotNull final String text) { | ||||||
|     return REPLACER_BRACKET.apply(text, player, |     return REPLACER_BRACKET.apply(text, player, | ||||||
|         PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion); |         PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion); | ||||||
| @@ -108,12 +134,72 @@ public final class PlaceholderAPI { | |||||||
|    * @return String containing all translated placeholders |    * @return String containing all translated placeholders | ||||||
|    */ |    */ | ||||||
|   @NotNull |   @NotNull | ||||||
|   public static List<String> setBracketPlaceholders(@Nullable final OfflinePlayer player, |   public static List<String> setBracketPlaceholders(final OfflinePlayer player, | ||||||
|       @NotNull final List<@NotNull String> text) { |       @NotNull final List<@NotNull String> text) { | ||||||
|     return text.stream().map(line -> setBracketPlaceholders(player, line)) |     return text.stream().map(line -> setBracketPlaceholders(player, line)) | ||||||
|         .collect(Collectors.toList()); |         .collect(Collectors.toList()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   public static String setBracketPlaceholders(Player player, String text) { | ||||||
|  |     return setBracketPlaceholders((OfflinePlayer) player, text); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public static List<String> setBracketPlaceholders(Player player, List<String> text) { | ||||||
|  |     return setPlaceholders((OfflinePlayer) player, text); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * set relational placeholders in the text specified placeholders are matched with the pattern | ||||||
|  |    * %<rel_(identifier)_(params)>% when set with this method | ||||||
|  |    * | ||||||
|  |    * @param one First player to compare | ||||||
|  |    * @param two Second player to compare | ||||||
|  |    * @param text Text to parse the placeholders in | ||||||
|  |    * @return The text containing the parsed relational placeholders | ||||||
|  |    */ | ||||||
|  |   public static String setRelationalPlaceholders(Player one, Player two, String text) { | ||||||
|  |     final Matcher matcher = RELATIONAL_PLACEHOLDER_PATTERN.matcher(text); | ||||||
|  |  | ||||||
|  |     while (matcher.find()) { | ||||||
|  |       final String format = matcher.group(2); | ||||||
|  |       final int index = format.indexOf("_"); | ||||||
|  |  | ||||||
|  |       if (index <= 0 || index >= format.length()) { | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       String identifier = format.substring(0, index).toLowerCase(); | ||||||
|  |       String params = format.substring(index + 1); | ||||||
|  |       final PlaceholderExpansion expansion = PlaceholderAPIPlugin.getInstance() | ||||||
|  |           .getLocalExpansionManager().getExpansion(identifier); | ||||||
|  |  | ||||||
|  |       if (!(expansion instanceof Relational)) { | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       final String value = ((Relational) expansion).onPlaceholderRequest(one, two, params); | ||||||
|  |  | ||||||
|  |       if (value != null) { | ||||||
|  |         text = text.replaceAll(Pattern.quote(matcher.group()), Matcher.quoteReplacement(value)); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return Msg.color(text); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Translate placeholders in the provided List based on the relation of the two provided players. | ||||||
|  |    * <br>The pattern of a valid placeholder is {@literal %rel_<identifier>_<param>%}. | ||||||
|  |    * | ||||||
|  |    * @param one Player to compare | ||||||
|  |    * @param two Player to compare | ||||||
|  |    * @param text text to parse the placeholder values to | ||||||
|  |    * @return The text containing the parsed relational placeholders | ||||||
|  |    */ | ||||||
|  |   public static List<String> setRelationalPlaceholders(Player one, Player two, List<String> text) { | ||||||
|  |     return text.stream().map(line -> setRelationalPlaceholders(one, two, line)) | ||||||
|  |         .collect(Collectors.toList()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Check if a specific placeholder identifier is currently registered |    * Check if a specific placeholder identifier is currently registered | ||||||
| @@ -126,7 +212,6 @@ public final class PlaceholderAPI { | |||||||
|         .findExpansionByIdentifier(identifier).isPresent(); |         .findExpansionByIdentifier(identifier).isPresent(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Get all registered placeholder identifiers |    * Get all registered placeholder identifiers | ||||||
|    * |    * | ||||||
| @@ -183,111 +268,33 @@ public final class PlaceholderAPI { | |||||||
|  |  | ||||||
|   // === Deprecated API === |   // === Deprecated API === | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * set relational placeholders in the text specified placeholders are matched with the pattern |  | ||||||
|    * %<rel_(identifier)_(params)>% when set with this method |  | ||||||
|    * |  | ||||||
|    * @param one First player to compare |  | ||||||
|    * @param two Second player to compare |  | ||||||
|    * @param text Text to parse the placeholders in |  | ||||||
|    * @return The text containing the parsed relational placeholders |  | ||||||
|    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead. |  | ||||||
|    */ |  | ||||||
|   @Deprecated |   @Deprecated | ||||||
|   public static String setRelationalPlaceholders(Player one, Player two, String text) { |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|     return setRelationalPlaceholders(one, two, text, true); |   public static boolean registerExpansion(PlaceholderExpansion expansion) | ||||||
|  |   { | ||||||
|  |     return expansion.register(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Deprecated | ||||||
|  |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|  |   public static boolean unregisterExpansion(PlaceholderExpansion expansion) | ||||||
|  |   { | ||||||
|  |     return expansion.unregister(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Translate placeholders in the provided List based on the relation of the two provided players. |    * Get map of registered placeholders | ||||||
|    * <br>The pattern of a valid placeholder is {@literal %rel_<identifier>_<param>%}. |  | ||||||
|    * |    * | ||||||
|    * @param one Player to compare |    * @return Map of registered placeholders | ||||||
|    * @param two Player to compare |    * @deprecated Use {@link me.clip.placeholderapi.PlaceholderAPIPlugin().getLocalExpansionManager() | ||||||
|    * @param text text to parse the placeholder values to |    * .getExpansions()} instead. | ||||||
|    * @return The text containing the parsed relational placeholders |  | ||||||
|    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead. |  | ||||||
|    */ |  | ||||||
|   @Deprecated |  | ||||||
|   public static List<String> setRelationalPlaceholders(Player one, Player two, List<String> text) { |  | ||||||
|     return setRelationalPlaceholders(one, two, text, true); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * Translate placeholders in the provided list based on the relation of the two provided players. |  | ||||||
|    * <br>The pattern of a valid placeholder is {@literal %rel_<identifier>_<params>%}. |  | ||||||
|    * |  | ||||||
|    * @param one First player to compare |  | ||||||
|    * @param two Second player to compare |  | ||||||
|    * @param text Text to parse the placeholders in |  | ||||||
|    * @param colorize If color codes (&[0-1a-fk-o]) should be translated |  | ||||||
|    * @return The text containing the parsed relational placeholders |  | ||||||
|    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead. |  | ||||||
|    */ |    */ | ||||||
|   @Deprecated |   @Deprecated | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|   public static List<String> setRelationalPlaceholders(Player one, Player two, List<String> text, |   public static Map<String, PlaceholderHook> getPlaceholders() { | ||||||
|       boolean colorize) { |     return PlaceholderAPIPlugin.getInstance().getLocalExpansionManager() | ||||||
|     if (text == null) { |         .getExpansions().stream() | ||||||
|       return null; |         .collect(Collectors.toMap(PlaceholderExpansion::getIdentifier, ex -> ex)); | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return text.stream() |  | ||||||
|         .map(line -> setRelationalPlaceholders(one, two, line, colorize)) |  | ||||||
|         .collect(Collectors.toList()); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * set relational placeholders in the text specified placeholders are matched with the pattern |  | ||||||
|    * %<rel_(identifier)_(params)>% when set with this method |  | ||||||
|    * |  | ||||||
|    * @param one Player to compare |  | ||||||
|    * @param two Player to compare |  | ||||||
|    * @param text Text to parse the placeholders in |  | ||||||
|    * @param colorize If color codes (&[0-1a-fk-o]) should be translated |  | ||||||
|    * @return The text containing the parsed relational placeholders |  | ||||||
|    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead. |  | ||||||
|    */ |  | ||||||
|   @Deprecated |  | ||||||
|   @SuppressWarnings("DuplicatedCode") |  | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |  | ||||||
|   public static String setRelationalPlaceholders(Player one, Player two, String text, |  | ||||||
|       boolean colorize) { |  | ||||||
|     if (text == null) { |  | ||||||
|       return null; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (PlaceholderAPIPlugin.getInstance().getLocalExpansionManager().getExpansionsCount() == 0) { |  | ||||||
|       return colorize ? Msg.color(text) : text; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     final Matcher matcher = RELATIONAL_PLACEHOLDER_PATTERN.matcher(text); |  | ||||||
|  |  | ||||||
|     while (matcher.find()) { |  | ||||||
|       final String format = matcher.group(2); |  | ||||||
|       final int index = format.indexOf("_"); |  | ||||||
|  |  | ||||||
|       if (index <= 0 || index >= format.length()) { |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       String identifier = format.substring(0, index).toLowerCase(); |  | ||||||
|       String params = format.substring(index + 1); |  | ||||||
|       final PlaceholderExpansion expansion = PlaceholderAPIPlugin.getInstance() |  | ||||||
|           .getLocalExpansionManager().getExpansion(identifier); |  | ||||||
|  |  | ||||||
|       if (!(expansion instanceof Relational)) { |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       final String value = ((Relational) expansion).onPlaceholderRequest(one, two, params); |  | ||||||
|  |  | ||||||
|       if (value != null) { |  | ||||||
|         text = text.replaceAll(Pattern.quote(matcher.group()), Matcher.quoteReplacement(value)); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return colorize ? Msg.color(text) : text; |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
| @@ -317,7 +324,6 @@ public final class PlaceholderAPI { | |||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * @deprecated Please use {@link me.clip.placeholderapi.expansion.PlaceholderExpansion} to |    * @deprecated Please use {@link me.clip.placeholderapi.expansion.PlaceholderExpansion} to | ||||||
|    * unregister placeholders instead |    * unregister placeholders instead | ||||||
| @@ -344,86 +350,6 @@ public final class PlaceholderAPI { | |||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * @deprecated Please use {@link #setPlaceholders(OfflinePlayer, String)} instead |  | ||||||
|    */ |  | ||||||
|   @NotNull |  | ||||||
|   @Deprecated |  | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |  | ||||||
|   public static String setPlaceholders(@Nullable final OfflinePlayer player, |  | ||||||
|       @NotNull final String text, @NotNull final Pattern pattern, final boolean colorize) { |  | ||||||
|     return setPlaceholders(player, text); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * @deprecated Please use {@link #setPlaceholders(OfflinePlayer, List)} instead |  | ||||||
|    */ |  | ||||||
|   @NotNull |  | ||||||
|   @Deprecated |  | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |  | ||||||
|   public static List<String> setPlaceholders(@Nullable final OfflinePlayer player, |  | ||||||
|       @NotNull final List<String> text, @NotNull final Pattern pattern, final boolean colorize) { |  | ||||||
|     return setPlaceholders(player, text); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead. |  | ||||||
|    */ |  | ||||||
|   @Deprecated |  | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |  | ||||||
|   public static List<String> setBracketPlaceholders(OfflinePlayer player, List<String> text, |  | ||||||
|       boolean colorize) { |  | ||||||
|     return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, colorize); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead. |  | ||||||
|    */ |  | ||||||
|   @Deprecated |  | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |  | ||||||
|   public static List<String> setPlaceholders(OfflinePlayer player, List<String> text, |  | ||||||
|       boolean colorize) { |  | ||||||
|     return setPlaceholders(player, text, PLACEHOLDER_PATTERN, colorize); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead. |  | ||||||
|    */ |  | ||||||
|   @Deprecated |  | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |  | ||||||
|   public static List<String> setPlaceholders(OfflinePlayer player, List<String> text, |  | ||||||
|       Pattern pattern) { |  | ||||||
|     return setPlaceholders(player, text, pattern, true); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead. |  | ||||||
|    */ |  | ||||||
|   @Deprecated |  | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |  | ||||||
|   public static String setBracketPlaceholders(OfflinePlayer player, String text, boolean colorize) { |  | ||||||
|     return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, colorize); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead. |  | ||||||
|    */ |  | ||||||
|   @Deprecated |  | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |  | ||||||
|   public static String setPlaceholders(OfflinePlayer player, String text, boolean colorize) { |  | ||||||
|     return setPlaceholders(player, text, PLACEHOLDER_PATTERN, colorize); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead. |  | ||||||
|    */ |  | ||||||
|   @Deprecated |  | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |  | ||||||
|   public static String setPlaceholders(OfflinePlayer player, String text, Pattern pattern) { |  | ||||||
|     return setPlaceholders(player, text, pattern, true); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * @deprecated Will be removed in a future release. |    * @deprecated Will be removed in a future release. | ||||||
|    */ |    */ | ||||||
| @@ -443,30 +369,51 @@ public final class PlaceholderAPI { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * @deprecated Will be removed in a future release. |    * @deprecated Please use {@link #setPlaceholders(OfflinePlayer, String)} instead | ||||||
|    */ |    */ | ||||||
|   @Deprecated |   @Deprecated | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|   public static String setPlaceholders(Player player, String text) { |   public static String setPlaceholders(OfflinePlayer player, | ||||||
|     return setPlaceholders(((OfflinePlayer) player), text); |       String text, Pattern pattern, boolean colorize) { | ||||||
|  |     return setPlaceholders(player, text); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * @deprecated Please use {@link #setPlaceholders(OfflinePlayer, List)} instead | ||||||
|  |    */ | ||||||
|  |   @Deprecated | ||||||
|  |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|  |   public static List<String> setPlaceholders(OfflinePlayer player, | ||||||
|  |       List<String> text, Pattern pattern, boolean colorize) { | ||||||
|  |     return setPlaceholders(player, text); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead. | ||||||
|  |    */ | ||||||
|  |   @Deprecated | ||||||
|  |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|  |   public static List<String> setPlaceholders(OfflinePlayer player, List<String> text, | ||||||
|  |       boolean colorize) { | ||||||
|  |     return setPlaceholders(player, text); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead. | ||||||
|  |    */ | ||||||
|  |   @Deprecated | ||||||
|  |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|  |   public static List<String> setPlaceholders(OfflinePlayer player, List<String> text, | ||||||
|  |       Pattern pattern) { | ||||||
|  |     return setPlaceholders(player, text); | ||||||
|  |   } | ||||||
|   /** |   /** | ||||||
|    * @deprecated Will be removed in a future release. |    * @deprecated Will be removed in a future release. | ||||||
|    */ |    */ | ||||||
|   @Deprecated |   @Deprecated | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|   public static String setPlaceholders(Player player, String text, boolean colorize) { |   public static String setPlaceholders(Player player, String text, boolean colorize) { | ||||||
|     return setPlaceholders(player, text, PLACEHOLDER_PATTERN, colorize); |     return setPlaceholders(player, text); | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * @deprecated Will be removed in a future release. |  | ||||||
|    */ |  | ||||||
|   @Deprecated |  | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |  | ||||||
|   public static List<String> setPlaceholders(Player player, List<String> text) { |  | ||||||
|     return setPlaceholders(player, text, PLACEHOLDER_PATTERN, true); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
| @@ -475,16 +422,44 @@ public final class PlaceholderAPI { | |||||||
|   @Deprecated |   @Deprecated | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|   public static List<String> setPlaceholders(Player player, List<String> text, boolean colorize) { |   public static List<String> setPlaceholders(Player player, List<String> text, boolean colorize) { | ||||||
|     return setPlaceholders(player, text, PLACEHOLDER_PATTERN, colorize); |     return setPlaceholders(player, text); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * @deprecated Will be removed in a future release. |    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead. | ||||||
|    */ |    */ | ||||||
|   @Deprecated |   @Deprecated | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|   public static String setBracketPlaceholders(Player player, String text) { |   public static String setPlaceholders(OfflinePlayer player, String text, boolean colorize) { | ||||||
|     return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, true); |     return setPlaceholders(player, text); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead. | ||||||
|  |    */ | ||||||
|  |   @Deprecated | ||||||
|  |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|  |   public static String setPlaceholders(OfflinePlayer player, String text, Pattern pattern) { | ||||||
|  |     return setPlaceholders(player, text); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead. | ||||||
|  |    */ | ||||||
|  |   @Deprecated | ||||||
|  |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|  |   public static List<String> setBracketPlaceholders(OfflinePlayer player, List<String> text, | ||||||
|  |       boolean colorize) { | ||||||
|  |     return setBracketPlaceholders(player, text); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead. | ||||||
|  |    */ | ||||||
|  |   @Deprecated | ||||||
|  |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|  |   public static String setBracketPlaceholders(OfflinePlayer player, String text, boolean colorize) { | ||||||
|  |     return setBracketPlaceholders(player, text); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
| @@ -493,16 +468,7 @@ public final class PlaceholderAPI { | |||||||
|   @Deprecated |   @Deprecated | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|   public static String setBracketPlaceholders(Player player, String text, boolean colorize) { |   public static String setBracketPlaceholders(Player player, String text, boolean colorize) { | ||||||
|     return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, colorize); |     return setBracketPlaceholders(player, text); | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * @deprecated Will be removed in a future release. |  | ||||||
|    */ |  | ||||||
|   @Deprecated |  | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |  | ||||||
|   public static List<String> setBracketPlaceholders(Player player, List<String> text) { |  | ||||||
|     return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, true); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
| @@ -512,7 +478,42 @@ public final class PlaceholderAPI { | |||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|   public static List<String> setBracketPlaceholders(Player player, List<String> text, |   public static List<String> setBracketPlaceholders(Player player, List<String> text, | ||||||
|       boolean colorize) { |       boolean colorize) { | ||||||
|     return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, colorize); |     return setBracketPlaceholders(player, text); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * set relational placeholders in the text specified placeholders are matched with the pattern | ||||||
|  |    * %<rel_(identifier)_(params)>% when set with this method | ||||||
|  |    * | ||||||
|  |    * @param one Player to compare | ||||||
|  |    * @param two Player to compare | ||||||
|  |    * @param text Text to parse the placeholders in | ||||||
|  |    * @param colorize If color codes (&[0-1a-fk-o]) should be translated | ||||||
|  |    * @return The text containing the parsed relational placeholders | ||||||
|  |    * @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead. | ||||||
|  |    */ | ||||||
|  |   @Deprecated | ||||||
|  |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|  |   public static String setRelationalPlaceholders(Player one, Player two, String text, | ||||||
|  |       boolean colorize) { | ||||||
|  |     return setRelationalPlaceholders(one, two, text); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Translate placeholders in the provided list based on the relation of the two provided players. | ||||||
|  |    * <br>The pattern of a valid placeholder is {@literal %rel_<identifier>_<params>%}. | ||||||
|  |    * | ||||||
|  |    * @param one First player to compare | ||||||
|  |    * @param two Second player to compare | ||||||
|  |    * @param text Text to parse the placeholders in | ||||||
|  |    * @param colorize If color codes (&[0-1a-fk-o]) should be translated | ||||||
|  |    * @return The text containing the parsed relational placeholders | ||||||
|  |    * @deprecated Use {@link #setRelationalPlaceholders(Player, Player, List<String>)} instead. | ||||||
|  |    */ | ||||||
|  |   @Deprecated | ||||||
|  |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|  |   public static List<String> setRelationalPlaceholders(Player one, Player two, List<String> text, | ||||||
|  |       boolean colorize) { | ||||||
|  |     return setRelationalPlaceholders(one, two, text); | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,10 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi; | package me.clip.placeholderapi; | ||||||
|  |  | ||||||
|  | import java.text.SimpleDateFormat; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.logging.Level; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommandRouter; | import me.clip.placeholderapi.commands.PlaceholderCommandRouter; | ||||||
| import me.clip.placeholderapi.configuration.PlaceholderAPIConfig; | import me.clip.placeholderapi.configuration.PlaceholderAPIConfig; | ||||||
| import me.clip.placeholderapi.expansion.PlaceholderExpansion; | import me.clip.placeholderapi.expansion.PlaceholderExpansion; | ||||||
| @@ -36,243 +40,200 @@ import org.bukkit.event.HandlerList; | |||||||
| import org.bukkit.plugin.java.JavaPlugin; | import org.bukkit.plugin.java.JavaPlugin; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
| import java.text.SimpleDateFormat; |  | ||||||
| import java.util.HashMap; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.logging.Level; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Yes I have a shit load of work to do... |  * Yes I have a shit load of work to do... | ||||||
|  * |  * | ||||||
|  * @author Ryan McCarthy |  * @author Ryan McCarthy | ||||||
|  */ |  */ | ||||||
| public final class PlaceholderAPIPlugin extends JavaPlugin | public final class PlaceholderAPIPlugin extends JavaPlugin { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private static final Version VERSION; |   private static final Version VERSION; | ||||||
|  |   private static PlaceholderAPIPlugin instance; | ||||||
|  |  | ||||||
| 	static |   static { | ||||||
| 	{ |     final String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; | ||||||
| 		final String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; |  | ||||||
|  |  | ||||||
| 		boolean isSpigot; |     boolean isSpigot; | ||||||
| 		try |     try { | ||||||
| 		{ |       Class.forName("org.spigotmc.SpigotConfig"); | ||||||
| 			Class.forName("org.spigotmc.SpigotConfig"); |       isSpigot = true; | ||||||
| 			isSpigot = true; |     } catch (final ExceptionInInitializerError | ClassNotFoundException ignored) { | ||||||
| 		} |       isSpigot = false; | ||||||
| 		catch (final ExceptionInInitializerError | ClassNotFoundException ignored) |     } | ||||||
| 		{ |  | ||||||
| 			isSpigot = false; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		VERSION = new Version(version, isSpigot); |     VERSION = new Version(version, isSpigot); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	private static PlaceholderAPIPlugin instance; |   @NotNull | ||||||
|  |   private final PlaceholderAPIConfig config = new PlaceholderAPIConfig(this); | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private final PlaceholderAPIConfig config = new PlaceholderAPIConfig(this); |   private final LocalExpansionManager localExpansionManager = new LocalExpansionManager(this); | ||||||
|  |   @NotNull | ||||||
|  |   private final CloudExpansionManager cloudExpansionManager = new CloudExpansionManager(this); | ||||||
|  |  | ||||||
| 	@NotNull |   /** | ||||||
| 	private final LocalExpansionManager localExpansionManager = new LocalExpansionManager(this); |    * Gets the static instance of the main class for PlaceholderAPI. This class is not the actual API | ||||||
| 	@NotNull |    * class, this is the main class that extends JavaPlugin. For most API methods, use static methods | ||||||
| 	private final CloudExpansionManager cloudExpansionManager = new CloudExpansionManager(this); |    * available from the class: {@link PlaceholderAPI} | ||||||
|  |    * | ||||||
|  |    * @return PlaceholderAPIPlugin instance | ||||||
|  |    */ | ||||||
|  |   @NotNull | ||||||
|  |   public static PlaceholderAPIPlugin getInstance() { | ||||||
|  |     return instance; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Get the configurable {@linkplain String} value that should be returned when a boolean is true | ||||||
|  |    * | ||||||
|  |    * @return string value of true | ||||||
|  |    */ | ||||||
|  |   @NotNull | ||||||
|  |   public static String booleanTrue() { | ||||||
|  |     return getInstance().getPlaceholderAPIConfig().booleanTrue(); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	@Override |   /** | ||||||
| 	public void onLoad() |    * Get the configurable {@linkplain String} value that should be returned when a boolean is false | ||||||
| 	{ |    * | ||||||
| 		instance = this; |    * @return string value of false | ||||||
|  |    */ | ||||||
|  |   @NotNull | ||||||
|  |   public static String booleanFalse() { | ||||||
|  |     return getInstance().getPlaceholderAPIConfig().booleanFalse(); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 		saveDefaultConfig(); |   /** | ||||||
| 	} |    * Get the configurable {@linkplain SimpleDateFormat} object that is used to parse time for | ||||||
|  |    * generic time based placeholders | ||||||
|  |    * | ||||||
|  |    * @return date format | ||||||
|  |    */ | ||||||
|  |   @NotNull | ||||||
|  |   public static SimpleDateFormat getDateFormat() { | ||||||
|  |     try { | ||||||
|  |       return new SimpleDateFormat(getInstance().getPlaceholderAPIConfig().dateFormat()); | ||||||
|  |     } catch (final IllegalArgumentException ex) { | ||||||
|  |       getInstance().getLogger().log(Level.WARNING, "configured date format is invalid", ex); | ||||||
|  |       return new SimpleDateFormat("MM/dd/yy HH:mm:ss"); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	@Override |   public static Version getServerVersion() { | ||||||
| 	public void onEnable() |     return VERSION; | ||||||
| 	{ |   } | ||||||
| 		setupCommand(); |  | ||||||
| 		setupMetrics(); |  | ||||||
| 		setupExpansions(); |  | ||||||
|  |  | ||||||
| 		if (config.isCloudEnabled()) |   @Override | ||||||
| 		{ |   public void onLoad() { | ||||||
| 			getCloudExpansionManager().load(); |     instance = this; | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (config.checkUpdates()) |     saveDefaultConfig(); | ||||||
| 		{ |   } | ||||||
| 			new UpdateChecker(this).fetch(); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Override |   @Override | ||||||
| 	public void onDisable() |   public void onEnable() { | ||||||
| 	{ |     setupCommand(); | ||||||
| 		getCloudExpansionManager().kill(); |     setupMetrics(); | ||||||
| 		getLocalExpansionManager().kill(); |     setupExpansions(); | ||||||
|  |  | ||||||
| 		HandlerList.unregisterAll(this); |     if (config.isCloudEnabled()) { | ||||||
|  |       getCloudExpansionManager().load(); | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		Bukkit.getScheduler().cancelTasks(this); |     if (config.checkUpdates()) { | ||||||
|  |       new UpdateChecker(this).fetch(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
| 		instance = null; |   @Override | ||||||
| 	} |   public void onDisable() { | ||||||
|  |     getCloudExpansionManager().kill(); | ||||||
|  |     getLocalExpansionManager().kill(); | ||||||
|  |  | ||||||
|  |     HandlerList.unregisterAll(this); | ||||||
|  |  | ||||||
| 	public void reloadConf(@NotNull final CommandSender sender) |     Bukkit.getScheduler().cancelTasks(this); | ||||||
| 	{ |  | ||||||
| 		getLocalExpansionManager().kill(); |  | ||||||
|  |  | ||||||
| 		reloadConfig(); |     instance = null; | ||||||
|  |   } | ||||||
|  |  | ||||||
| 		getLocalExpansionManager().load(sender); |   public void reloadConf(@NotNull final CommandSender sender) { | ||||||
|  |     getLocalExpansionManager().kill(); | ||||||
|  |  | ||||||
| 		if (config.isCloudEnabled()) |     reloadConfig(); | ||||||
| 		{ |  | ||||||
| 			getCloudExpansionManager().load(); |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			getCloudExpansionManager().kill(); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |     getLocalExpansionManager().load(sender); | ||||||
|  |  | ||||||
| 	@NotNull |     if (config.isCloudEnabled()) { | ||||||
| 	public LocalExpansionManager getLocalExpansionManager() |       getCloudExpansionManager().load(); | ||||||
| 	{ |     } else { | ||||||
| 		return localExpansionManager; |       getCloudExpansionManager().kill(); | ||||||
| 	} |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	public CloudExpansionManager getCloudExpansionManager() |   public LocalExpansionManager getLocalExpansionManager() { | ||||||
| 	{ |     return localExpansionManager; | ||||||
| 		return cloudExpansionManager; |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
|  |   public CloudExpansionManager getCloudExpansionManager() { | ||||||
|  |     return cloudExpansionManager; | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	/** |   /** | ||||||
| 	 * Obtain the configuration class for PlaceholderAPI. |    * Obtain the configuration class for PlaceholderAPI. | ||||||
| 	 * |    * | ||||||
| 	 * @return PlaceholderAPIConfig instance |    * @return PlaceholderAPIConfig instance | ||||||
| 	 */ |    */ | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	public PlaceholderAPIConfig getPlaceholderAPIConfig() |   public PlaceholderAPIConfig getPlaceholderAPIConfig() { | ||||||
| 	{ |     return config; | ||||||
| 		return config; |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   private void setupCommand() { | ||||||
|  |     final PluginCommand pluginCommand = getCommand("placeholderapi"); | ||||||
|  |     if (pluginCommand == null) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 	private void setupCommand() |     final PlaceholderCommandRouter router = new PlaceholderCommandRouter(this); | ||||||
| 	{ |     pluginCommand.setExecutor(router); | ||||||
| 		final PluginCommand pluginCommand = getCommand("placeholderapi"); |     pluginCommand.setTabCompleter(router); | ||||||
| 		if (pluginCommand == null) |   } | ||||||
| 		{ |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final PlaceholderCommandRouter router = new PlaceholderCommandRouter(this); |   private void setupMetrics() { | ||||||
| 		pluginCommand.setExecutor(router); |     final Metrics metrics = new Metrics(this); | ||||||
| 		pluginCommand.setTabCompleter(router); |     metrics.addCustomChart(new Metrics.SimplePie("using_expansion_cloud", | ||||||
| 	} |         () -> getPlaceholderAPIConfig().isCloudEnabled() ? "yes" : "no")); | ||||||
|  |  | ||||||
| 	private void setupMetrics() |     metrics.addCustomChart( | ||||||
| 	{ |         new Metrics.SimplePie("using_spigot", () -> getServerVersion().isSpigot() ? "yes" : "no")); | ||||||
| 		final Metrics metrics = new Metrics(this); |  | ||||||
| 		metrics.addCustomChart(new Metrics.SimplePie("using_expansion_cloud", () -> getPlaceholderAPIConfig().isCloudEnabled() ? "yes" : "no")); |  | ||||||
|  |  | ||||||
| 		metrics.addCustomChart(new Metrics.SimplePie("using_spigot", () -> getServerVersion().isSpigot() ? "yes" : "no")); |     metrics.addCustomChart(new Metrics.AdvancedPie("expansions_used", () -> { | ||||||
|  |       final Map<String, Integer> values = new HashMap<>(); | ||||||
|  |  | ||||||
| 		metrics.addCustomChart(new Metrics.AdvancedPie("expansions_used", () -> { |       for (final PlaceholderExpansion expansion : getLocalExpansionManager().getExpansions()) { | ||||||
| 			final Map<String, Integer> values = new HashMap<>(); |         values.put(expansion.getRequiredPlugin() == null ? expansion.getIdentifier() | ||||||
|  |             : expansion.getRequiredPlugin(), 1); | ||||||
|  |       } | ||||||
|  |  | ||||||
| 			for (final PlaceholderExpansion expansion : getLocalExpansionManager().getExpansions()) |       return values; | ||||||
| 			{ |     })); | ||||||
| 				values.put(expansion.getRequiredPlugin() == null ? expansion.getIdentifier() : expansion.getRequiredPlugin(), 1); |   } | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			return values; |   private void setupExpansions() { | ||||||
| 		})); |     Bukkit.getPluginManager().registerEvents(getLocalExpansionManager(), this); | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	private void setupExpansions() |     try { | ||||||
| 	{ |       Class.forName("org.bukkit.event.server.ServerLoadEvent"); | ||||||
| 		Bukkit.getPluginManager().registerEvents(getLocalExpansionManager(), this); |       new ServerLoadEventListener(this); | ||||||
|  |     } catch (final ExceptionInInitializerError | ClassNotFoundException ignored) { | ||||||
| 		try |       Bukkit.getScheduler() | ||||||
| 		{ |           .runTaskLater(this, () -> getLocalExpansionManager().load(Bukkit.getConsoleSender()), 1); | ||||||
| 			Class.forName("org.bukkit.event.server.ServerLoadEvent"); |     } | ||||||
| 			new ServerLoadEventListener(this); |   } | ||||||
| 		} |  | ||||||
| 		catch (final ExceptionInInitializerError | ClassNotFoundException ignored) |  | ||||||
| 		{ |  | ||||||
| 			Bukkit.getScheduler().runTaskLater(this, () -> getLocalExpansionManager().load(Bukkit.getConsoleSender()), 1); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Gets the static instance of the main class for PlaceholderAPI. This class is not the actual API |  | ||||||
| 	 * class, this is the main class that extends JavaPlugin. For most API methods, use static methods |  | ||||||
| 	 * available from the class: {@link PlaceholderAPI} |  | ||||||
| 	 * |  | ||||||
| 	 * @return PlaceholderAPIPlugin instance |  | ||||||
| 	 */ |  | ||||||
| 	@NotNull |  | ||||||
| 	public static PlaceholderAPIPlugin getInstance() |  | ||||||
| 	{ |  | ||||||
| 		return instance; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Get the configurable {@linkplain String} value that should be returned when a boolean is true |  | ||||||
| 	 * |  | ||||||
| 	 * @return string value of true |  | ||||||
| 	 */ |  | ||||||
| 	@NotNull |  | ||||||
| 	public static String booleanTrue() |  | ||||||
| 	{ |  | ||||||
| 		return getInstance().getPlaceholderAPIConfig().booleanTrue(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Get the configurable {@linkplain String} value that should be returned when a boolean is false |  | ||||||
| 	 * |  | ||||||
| 	 * @return string value of false |  | ||||||
| 	 */ |  | ||||||
| 	@NotNull |  | ||||||
| 	public static String booleanFalse() |  | ||||||
| 	{ |  | ||||||
| 		return getInstance().getPlaceholderAPIConfig().booleanFalse(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Get the configurable {@linkplain SimpleDateFormat} object that is used to parse time for |  | ||||||
| 	 * generic time based placeholders |  | ||||||
| 	 * |  | ||||||
| 	 * @return date format |  | ||||||
| 	 */ |  | ||||||
| 	@NotNull |  | ||||||
| 	public static SimpleDateFormat getDateFormat() |  | ||||||
| 	{ |  | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
| 			return new SimpleDateFormat(getInstance().getPlaceholderAPIConfig().dateFormat()); |  | ||||||
| 		} |  | ||||||
| 		catch (final IllegalArgumentException ex) |  | ||||||
| 		{ |  | ||||||
| 			getInstance().getLogger().log(Level.WARNING, "configured date format is invalid", ex); |  | ||||||
| 			return new SimpleDateFormat("MM/dd/yy HH:mm:ss"); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public static Version getServerVersion() |  | ||||||
| 	{ |  | ||||||
| 		return VERSION; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,38 +22,19 @@ package me.clip.placeholderapi; | |||||||
|  |  | ||||||
| import org.bukkit.OfflinePlayer; | import org.bukkit.OfflinePlayer; | ||||||
| import org.bukkit.entity.Player; | import org.bukkit.entity.Player; | ||||||
| import org.jetbrains.annotations.ApiStatus; |  | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Nullable; |  | ||||||
|  |  | ||||||
| /** | public abstract class PlaceholderHook { | ||||||
|  * @deprecated This class will be completely removed in the next release, please use {@link me.clip.placeholderapi.expansion.PlaceholderExpansion} |  | ||||||
|  */ |  | ||||||
| @Deprecated |  | ||||||
| @ApiStatus.NonExtendable |  | ||||||
| @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |  | ||||||
| public abstract class PlaceholderHook |  | ||||||
| { |  | ||||||
|  |  | ||||||
| 	@Nullable |   public String onRequest(final OfflinePlayer player, @NotNull final String params) { | ||||||
| 	public String onRequest(@Nullable final OfflinePlayer player, @NotNull final String params) |     if (player != null && player.isOnline()) { | ||||||
| 	{ |       return onPlaceholderRequest((Player) player, params); | ||||||
| 		if (player != null && player.isOnline()) |     } | ||||||
| 		{ |  | ||||||
| 			return onPlaceholderRequest((Player) player, params); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return onPlaceholderRequest(null, params); |     return onPlaceholderRequest(null, params); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * @deprecated This method will be completely removed, please use {@link me.clip.placeholderapi.expansion.PlaceholderExpansion#onRequest(OfflinePlayer, String)} |  | ||||||
| 	 */ |  | ||||||
| 	@Nullable |  | ||||||
| 	@Deprecated |  | ||||||
| 	public String onPlaceholderRequest(@Nullable final Player player, @NotNull final String params) |  | ||||||
| 	{ |  | ||||||
| 		return null; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   public String onPlaceholderRequest(final Player player, @NotNull final String params) { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,97 +22,86 @@ package me.clip.placeholderapi.commands; | |||||||
|  |  | ||||||
| import com.google.common.collect.ImmutableSet; | import com.google.common.collect.ImmutableSet; | ||||||
| import com.google.common.collect.Sets; | import com.google.common.collect.Sets; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Set; | ||||||
|  | import java.util.stream.Stream; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.List; | public abstract class PlaceholderCommand { | ||||||
| import java.util.Set; |  | ||||||
| import java.util.stream.Stream; |  | ||||||
|  |  | ||||||
| public abstract class PlaceholderCommand |   @NotNull | ||||||
| { |   private final String label; | ||||||
|  |   @NotNull | ||||||
|  |   private final Set<String> alias; | ||||||
|  |  | ||||||
| 	@NotNull |   @Nullable | ||||||
| 	private final String      label; |   private String permission; | ||||||
| 	@NotNull |  | ||||||
| 	private final Set<String> alias; |  | ||||||
|  |  | ||||||
| 	@Nullable |  | ||||||
| 	private String permission; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	protected PlaceholderCommand(@NotNull final String label, @NotNull final String... alias) |   protected PlaceholderCommand(@NotNull final String label, @NotNull final String... alias) { | ||||||
| 	{ |     this.label = label; | ||||||
| 		this.label = label; |     this.alias = Sets.newHashSet(alias); | ||||||
| 		this.alias = Sets.newHashSet(alias); |  | ||||||
|  |  | ||||||
| 		setPermission("placeholderapi." + label); |     setPermission("placeholderapi." + label); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
|  |   public static Stream<PlaceholderCommand> filterByPermission(@NotNull final CommandSender sender, | ||||||
|  |       @NotNull final Stream<PlaceholderCommand> commands) { | ||||||
|  |     return commands.filter( | ||||||
|  |         target -> target.getPermission() == null || sender.hasPermission(target.getPermission())); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	@NotNull |   public static void suggestByParameter(@NotNull final Stream<String> possible, | ||||||
| 	public final String getLabel() |       @NotNull final List<String> suggestions, @Nullable final String parameter) { | ||||||
| 	{ |     if (parameter == null) { | ||||||
| 		return label; |       possible.forEach(suggestions::add); | ||||||
| 	} |     } else { | ||||||
|  |       possible.filter(suggestion -> suggestion.toLowerCase().startsWith(parameter.toLowerCase())) | ||||||
|  |           .forEach(suggestions::add); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	@Unmodifiable |   public final String getLabel() { | ||||||
| 	public final Set<String> getAlias() |     return label; | ||||||
| 	{ |   } | ||||||
| 		return ImmutableSet.copyOf(alias); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	@Unmodifiable |   @Unmodifiable | ||||||
| 	public final Set<String> getLabels() |   public final Set<String> getAlias() { | ||||||
| 	{ |     return ImmutableSet.copyOf(alias); | ||||||
| 		return ImmutableSet.<String>builder().add(label).addAll(alias).build(); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
|  |   @Unmodifiable | ||||||
|  |   public final Set<String> getLabels() { | ||||||
|  |     return ImmutableSet.<String>builder().add(label).addAll(alias).build(); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	@Nullable |   @Nullable | ||||||
| 	public final String getPermission() |   public final String getPermission() { | ||||||
| 	{ |     return permission; | ||||||
| 		return permission; |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public void setPermission(@NotNull final String permission) |   public void setPermission(@NotNull final String permission) { | ||||||
| 	{ |     this.permission = permission; | ||||||
| 		this.permission = permission; |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
|  |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|  |  | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |   } | ||||||
| 	{ |  | ||||||
|  |  | ||||||
| 	} |   public void complete(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
|  |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) { | ||||||
|  |  | ||||||
| 	public void complete(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) |   } | ||||||
| 	{ |  | ||||||
|  |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public static Stream<PlaceholderCommand> filterByPermission(@NotNull final CommandSender sender, @NotNull final Stream<PlaceholderCommand> commands) |  | ||||||
| 	{ |  | ||||||
| 		return commands.filter(target -> target.getPermission() == null || sender.hasPermission(target.getPermission())); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public static void suggestByParameter(@NotNull final Stream<String> possible, @NotNull final List<String> suggestions, @Nullable final String parameter) |  | ||||||
| 	{ |  | ||||||
| 		if (parameter == null) |  | ||||||
| 		{ |  | ||||||
| 			possible.forEach(suggestions::add); |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			possible.filter(suggestion -> suggestion.toLowerCase().startsWith(parameter.toLowerCase())).forEach(suggestions::add); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,6 +22,13 @@ package me.clip.placeholderapi.commands; | |||||||
|  |  | ||||||
| import com.google.common.collect.ImmutableList; | import com.google.common.collect.ImmutableList; | ||||||
| import com.google.common.collect.ImmutableMap; | import com.google.common.collect.ImmutableMap; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.stream.Stream; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.impl.cloud.CommandECloud; | import me.clip.placeholderapi.commands.impl.cloud.CommandECloud; | ||||||
| import me.clip.placeholderapi.commands.impl.local.CommandDump; | import me.clip.placeholderapi.commands.impl.local.CommandDump; | ||||||
| @@ -41,103 +48,95 @@ import org.bukkit.command.TabCompleter; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.*; | public final class PlaceholderCommandRouter implements CommandExecutor, TabCompleter { | ||||||
| import java.util.stream.Stream; |  | ||||||
|  |  | ||||||
| public final class PlaceholderCommandRouter implements CommandExecutor, TabCompleter |   @Unmodifiable | ||||||
| { |   private static final List<PlaceholderCommand> COMMANDS = ImmutableList.of(new CommandHelp(), | ||||||
|  |       new CommandInfo(), | ||||||
| 	@Unmodifiable |       new CommandList(), | ||||||
| 	private static final List<PlaceholderCommand> COMMANDS = ImmutableList.of(new CommandHelp(), |       new CommandDump(), | ||||||
| 																			  new CommandInfo(), |       new CommandECloud(), | ||||||
| 																			  new CommandList(), |       new CommandParse(), | ||||||
| 																			  new CommandDump(), |       new CommandReload(), | ||||||
| 																			  new CommandECloud(), |       new CommandVersion(), | ||||||
| 																			  new CommandParse(), |       new CommandExpansionRegister(), | ||||||
| 																			  new CommandReload(), |       new CommandExpansionUnregister()); | ||||||
| 																			  new CommandVersion(), |  | ||||||
| 																			  new CommandExpansionRegister(), |  | ||||||
| 																			  new CommandExpansionUnregister()); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private final PlaceholderAPIPlugin            plugin; |   private final PlaceholderAPIPlugin plugin; | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	@Unmodifiable |   @Unmodifiable | ||||||
| 	private final Map<String, PlaceholderCommand> commands; |   private final Map<String, PlaceholderCommand> commands; | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public PlaceholderCommandRouter(@NotNull final PlaceholderAPIPlugin plugin) |   public PlaceholderCommandRouter(@NotNull final PlaceholderAPIPlugin plugin) { | ||||||
| 	{ |     this.plugin = plugin; | ||||||
| 		this.plugin = plugin; |  | ||||||
|  |  | ||||||
| 		final ImmutableMap.Builder<String, PlaceholderCommand> commands = ImmutableMap.builder(); |     final ImmutableMap.Builder<String, PlaceholderCommand> commands = ImmutableMap.builder(); | ||||||
|  |  | ||||||
| 		for (final PlaceholderCommand command : COMMANDS) |     for (final PlaceholderCommand command : COMMANDS) { | ||||||
| 		{ |       command.getLabels().forEach(label -> commands.put(label, command)); | ||||||
| 			command.getLabels().forEach(label -> commands.put(label, command)); |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		this.commands = commands.build(); |     this.commands = commands.build(); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@Override |   @Override | ||||||
| 	public boolean onCommand(@NotNull final CommandSender sender, @NotNull final Command command, @NotNull final String alias, @NotNull final String[] args) |   public boolean onCommand(@NotNull final CommandSender sender, @NotNull final Command command, | ||||||
| 	{ |       @NotNull final String alias, @NotNull final String[] args) { | ||||||
| 		if (args.length == 0) |     if (args.length == 0) { | ||||||
| 		{ |       final PlaceholderCommand fallback = commands.get("version"); | ||||||
| 			final PlaceholderCommand fallback = commands.get("version"); |       if (fallback != null) { | ||||||
| 			if (fallback != null) |         fallback.evaluate(plugin, sender, "", Collections.emptyList()); | ||||||
| 			{ |       } | ||||||
| 				fallback.evaluate(plugin, sender, "", Collections.emptyList()); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			return true; |       return true; | ||||||
| 		} |     } | ||||||
|  |  | ||||||
| 		final String             search = args[0].toLowerCase(); |     final String search = args[0].toLowerCase(); | ||||||
| 		final PlaceholderCommand target = commands.get(search); |     final PlaceholderCommand target = commands.get(search); | ||||||
|  |  | ||||||
| 		if (target == null) |     if (target == null) { | ||||||
| 		{ |       Msg.msg(sender, "&cUnknown command &7" + search); | ||||||
| 			Msg.msg(sender, "&cUnknown command &7" + search); |       return true; | ||||||
| 			return true; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final String permission = target.getPermission(); |     final String permission = target.getPermission(); | ||||||
| 		if (permission != null && !permission.isEmpty() && !sender.hasPermission(permission)) |     if (permission != null && !permission.isEmpty() && !sender.hasPermission(permission)) { | ||||||
| 		{ |       Msg.msg(sender, "&cYou do not have permission to do this!"); | ||||||
| 			Msg.msg(sender, "&cYou do not have permission to do this!"); |       return true; | ||||||
| 			return true; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		target.evaluate(plugin, sender, search, Arrays.asList(Arrays.copyOfRange(args, 1, args.length))); |     target | ||||||
|  |         .evaluate(plugin, sender, search, Arrays.asList(Arrays.copyOfRange(args, 1, args.length))); | ||||||
|  |  | ||||||
| 		return true; |     return true; | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	@Override |   @Override | ||||||
| 	public List<String> onTabComplete(@NotNull final CommandSender sender, @NotNull final Command command, @NotNull final String alias, @NotNull final String[] args) |   public List<String> onTabComplete(@NotNull final CommandSender sender, | ||||||
| 	{ |       @NotNull final Command command, @NotNull final String alias, @NotNull final String[] args) { | ||||||
| 		final List<String> suggestions = new ArrayList<>(); |     final List<String> suggestions = new ArrayList<>(); | ||||||
|  |  | ||||||
| 		if (args.length > 1) |     if (args.length > 1) { | ||||||
| 		{ |       final PlaceholderCommand target = this.commands.get(args[0].toLowerCase()); | ||||||
| 			final PlaceholderCommand target = this.commands.get(args[0].toLowerCase()); |  | ||||||
|  |  | ||||||
| 			if (target != null) |       if (target != null) { | ||||||
| 			{ |         target.complete(plugin, sender, args[0].toLowerCase(), | ||||||
| 				target.complete(plugin, sender, args[0].toLowerCase(), Arrays.asList(Arrays.copyOfRange(args, 1, args.length)), suggestions); |             Arrays.asList(Arrays.copyOfRange(args, 1, args.length)), suggestions); | ||||||
| 			} |       } | ||||||
|  |  | ||||||
| 			return suggestions; |       return suggestions; | ||||||
| 		} |     } | ||||||
|  |  | ||||||
| 		final Stream<String> targets = PlaceholderCommand.filterByPermission(sender, commands.values().stream()).map(PlaceholderCommand::getLabels).flatMap(Collection::stream); |     final Stream<String> targets = PlaceholderCommand | ||||||
| 		PlaceholderCommand.suggestByParameter(targets, suggestions, args.length == 0 ? null : args[0]); |         .filterByPermission(sender, commands.values().stream()).map(PlaceholderCommand::getLabels) | ||||||
|  |         .flatMap(Collection::stream); | ||||||
|  |     PlaceholderCommand.suggestByParameter(targets, suggestions, args.length == 0 ? null : args[0]); | ||||||
|  |  | ||||||
| 		return suggestions; |     return suggestions; | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,6 +22,10 @@ package me.clip.placeholderapi.commands.impl.cloud; | |||||||
|  |  | ||||||
| import com.google.common.collect.ImmutableList; | import com.google.common.collect.ImmutableList; | ||||||
| import com.google.common.collect.ImmutableMap; | import com.google.common.collect.ImmutableMap; | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.stream.Stream; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import me.clip.placeholderapi.util.Msg; | import me.clip.placeholderapi.util.Msg; | ||||||
| @@ -29,126 +33,117 @@ import org.bukkit.command.CommandSender; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.Collection; | public final class CommandECloud extends PlaceholderCommand { | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.stream.Stream; |  | ||||||
|  |  | ||||||
| public final class CommandECloud extends PlaceholderCommand |   @Unmodifiable | ||||||
| { |   private static final List<PlaceholderCommand> COMMANDS = ImmutableList | ||||||
|  |       .of(new CommandECloudClear(), | ||||||
|  |           new CommandECloudToggle(), | ||||||
|  |           new CommandECloudStatus(), | ||||||
|  |           new CommandECloudUpdate(), | ||||||
|  |           new CommandECloudRefresh(), | ||||||
|  |           new CommandECloudDownload(), | ||||||
|  |           new CommandECloudExpansionInfo(), | ||||||
|  |           new CommandECloudExpansionList(), | ||||||
|  |           new CommandECloudExpansionPlaceholders()); | ||||||
|  |  | ||||||
| 	@Unmodifiable |   static { | ||||||
| 	private static final List<PlaceholderCommand> COMMANDS = ImmutableList.of(new CommandECloudClear(), |     COMMANDS | ||||||
| 																			  new CommandECloudToggle(), |         .forEach(command -> command.setPermission("placeholderapi.ecloud." + command.getLabel())); | ||||||
| 																			  new CommandECloudStatus(), |   } | ||||||
| 																			  new CommandECloudUpdate(), |  | ||||||
| 																			  new CommandECloudRefresh(), |  | ||||||
| 																			  new CommandECloudDownload(), |  | ||||||
| 																			  new CommandECloudExpansionInfo(), |  | ||||||
| 																			  new CommandECloudExpansionList(), |  | ||||||
| 																			  new CommandECloudExpansionPlaceholders()); |  | ||||||
|  |  | ||||||
| 	static |   @NotNull | ||||||
| 	{ |   @Unmodifiable | ||||||
| 		COMMANDS.forEach(command -> command.setPermission("placeholderapi.ecloud." + command.getLabel())); |   private final Map<String, PlaceholderCommand> commands; | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	@Unmodifiable |  | ||||||
| 	private final Map<String, PlaceholderCommand> commands; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public CommandECloud() |   public CommandECloud() { | ||||||
| 	{ |     super("ecloud"); | ||||||
| 		super("ecloud"); |  | ||||||
|  |  | ||||||
| 		final ImmutableMap.Builder<String, PlaceholderCommand> commands = ImmutableMap.builder(); |     final ImmutableMap.Builder<String, PlaceholderCommand> commands = ImmutableMap.builder(); | ||||||
|  |  | ||||||
| 		for (final PlaceholderCommand command : COMMANDS) |     for (final PlaceholderCommand command : COMMANDS) { | ||||||
| 		{ |       command.getLabels().forEach(label -> commands.put(label, command)); | ||||||
| 			command.getLabels().forEach(label -> commands.put(label, command)); |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		this.commands = commands.build(); |     this.commands = commands.build(); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@Override |   @Override | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 	{ |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 		if (params.isEmpty()) |       @NotNull @Unmodifiable final List<String> params) { | ||||||
| 		{ |     if (params.isEmpty()) { | ||||||
| 			Msg.msg(sender, |       Msg.msg(sender, | ||||||
| 					"&b&lPlaceholderAPI &8- &7eCloud Help Menu &8- ", |           "&b&lPlaceholderAPI &8- &7eCloud Help Menu &8- ", | ||||||
| 					" ", |           " ", | ||||||
| 					"&b/papi &fenable/disable/toggle", |           "&b/papi &fenable/disable/toggle", | ||||||
| 					"  &7&oEnable or disable the eCloud", |           "  &7&oEnable or disable the eCloud", | ||||||
| 					"&b/papi &fecloud status", |           "&b/papi &fecloud status", | ||||||
| 					"  &7&oView status of the eCloud", |           "  &7&oView status of the eCloud", | ||||||
| 					"&b/papi &fecloud list <all/{author}/installed> {page}", |           "&b/papi &fecloud list <all/{author}/installed> {page}", | ||||||
| 					"  &7&oList all/author specific available expansions", |           "  &7&oList all/author specific available expansions", | ||||||
| 					"&b/papi &fecloud info <expansion name> {version}", |           "&b/papi &fecloud info <expansion name> {version}", | ||||||
| 					"  &7&oView information about a specific expansion available on the eCloud", |           "  &7&oView information about a specific expansion available on the eCloud", | ||||||
| 					"&b/papi &fecloud placeholders <expansion name>", |           "&b/papi &fecloud placeholders <expansion name>", | ||||||
| 					"  &7&oView placeholders for an expansion", |           "  &7&oView placeholders for an expansion", | ||||||
| 					"&b/papi &fecloud download <expansion name> {version}", |           "&b/papi &fecloud download <expansion name> {version}", | ||||||
| 					"  &7&oDownload an expansion from the eCloud", |           "  &7&oDownload an expansion from the eCloud", | ||||||
| 					"&b/papi &fecloud update <expansion name/all>", |           "&b/papi &fecloud update <expansion name/all>", | ||||||
| 					"  &7&oUpdate a specific/all installed expansions", |           "  &7&oUpdate a specific/all installed expansions", | ||||||
| 					"&b/papi &fecloud refresh", |           "&b/papi &fecloud refresh", | ||||||
| 					"  &7&oFetch the most up to date list of expansions available.", |           "  &7&oFetch the most up to date list of expansions available.", | ||||||
| 					"&b/papi &fecloud clear", |           "&b/papi &fecloud clear", | ||||||
| 					"  &7&oClear the expansion cloud cache."); |           "  &7&oClear the expansion cloud cache."); | ||||||
|  |  | ||||||
| 			return; |       return; | ||||||
| 		} |     } | ||||||
|  |  | ||||||
| 		final String             search = params.get(0).toLowerCase(); |     final String search = params.get(0).toLowerCase(); | ||||||
| 		final PlaceholderCommand target = commands.get(search); |     final PlaceholderCommand target = commands.get(search); | ||||||
|  |  | ||||||
| 		if (target == null) |     if (target == null) { | ||||||
| 		{ |       Msg.msg(sender, "&cUnknown command &7ecloud " + search); | ||||||
| 			Msg.msg(sender, "&cUnknown command &7ecloud " + search); |       return; | ||||||
| 			return; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final String permission = target.getPermission(); |     final String permission = target.getPermission(); | ||||||
| 		if (permission != null && !permission.isEmpty() && !sender.hasPermission(permission)) |     if (permission != null && !permission.isEmpty() && !sender.hasPermission(permission)) { | ||||||
| 		{ |       Msg.msg(sender, "&cYou do not have permission to do this!"); | ||||||
| 			Msg.msg(sender, "&cYou do not have permission to do this!"); |       return; | ||||||
| 			return; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (!(target instanceof CommandECloudToggle) && !plugin.getPlaceholderAPIConfig().isCloudEnabled()) |     if (!(target instanceof CommandECloudToggle) && !plugin.getPlaceholderAPIConfig() | ||||||
| 		{ |         .isCloudEnabled()) { | ||||||
| 			Msg.msg(sender, |       Msg.msg(sender, | ||||||
| 					"&cThe eCloud Manager is not enabled!"); |           "&cThe eCloud Manager is not enabled!"); | ||||||
| 			return; |       return; | ||||||
| 		} |     } | ||||||
|  |  | ||||||
| 		target.evaluate(plugin, sender, search, params.subList(1, params.size())); |     target.evaluate(plugin, sender, search, params.subList(1, params.size())); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	@Override |   @Override | ||||||
| 	public void complete(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) |   public void complete(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 	{ |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 		if (params.size() <= 1) |       @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) { | ||||||
| 		{ |     if (params.size() <= 1) { | ||||||
| 			final Stream<String> targets = filterByPermission(sender, commands.values().stream()).map(PlaceholderCommand::getLabels).flatMap(Collection::stream); |       final Stream<String> targets = filterByPermission(sender, commands.values().stream()) | ||||||
| 			suggestByParameter(targets, suggestions, params.isEmpty() ? null : params.get(0)); |           .map(PlaceholderCommand::getLabels).flatMap(Collection::stream); | ||||||
|  |       suggestByParameter(targets, suggestions, params.isEmpty() ? null : params.get(0)); | ||||||
|  |  | ||||||
| 			return; // send sub commands |       return; // send sub commands | ||||||
| 		} |     } | ||||||
|  |  | ||||||
| 		final String             search = params.get(0).toLowerCase(); |     final String search = params.get(0).toLowerCase(); | ||||||
| 		final PlaceholderCommand target = commands.get(search); |     final PlaceholderCommand target = commands.get(search); | ||||||
|  |  | ||||||
| 		if (target == null) |     if (target == null) { | ||||||
| 		{ |       return; | ||||||
| 			return; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		target.complete(plugin, sender, search, params.subList(1, params.size()), suggestions); |     target.complete(plugin, sender, search, params.subList(1, params.size()), suggestions); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.commands.impl.cloud; | package me.clip.placeholderapi.commands.impl.cloud; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import me.clip.placeholderapi.util.Msg; | import me.clip.placeholderapi.util.Msg; | ||||||
| @@ -27,22 +28,19 @@ import org.bukkit.command.CommandSender; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.List; | public final class CommandECloudClear extends PlaceholderCommand { | ||||||
|  |  | ||||||
| public final class CommandECloudClear extends PlaceholderCommand |   public CommandECloudClear() { | ||||||
| { |     super("clear"); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	public CommandECloudClear() |   @Override | ||||||
| 	{ |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 		super("clear"); |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 	} |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|  |     plugin.getCloudExpansionManager().clean(); | ||||||
| 	@Override |     Msg.msg(sender, | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |         "&aThe eCloud cache has been cleared!"); | ||||||
| 	{ |   } | ||||||
| 		plugin.getCloudExpansionManager().clean(); |  | ||||||
| 		Msg.msg(sender, |  | ||||||
| 				"&aThe eCloud cache has been cleared!"); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,9 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.commands.impl.cloud; | package me.clip.placeholderapi.commands.impl.cloud; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Optional; | ||||||
|  | import java.util.stream.Stream; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import me.clip.placeholderapi.expansion.cloud.CloudExpansion; | import me.clip.placeholderapi.expansion.cloud.CloudExpansion; | ||||||
| @@ -28,98 +31,89 @@ import org.bukkit.command.CommandSender; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.List; | public final class CommandECloudDownload extends PlaceholderCommand { | ||||||
| import java.util.Optional; |  | ||||||
| import java.util.stream.Stream; |  | ||||||
|  |  | ||||||
| public final class CommandECloudDownload extends PlaceholderCommand |   public CommandECloudDownload() { | ||||||
| { |     super("download"); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	public CommandECloudDownload() |   @Override | ||||||
| 	{ |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 		super("download"); |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 	} |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|  |     if (params.isEmpty()) { | ||||||
|  |       Msg.msg(sender, | ||||||
|  |           "&cYou must supply the name of an expansion."); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 	@Override |     final CloudExpansion expansion = plugin.getCloudExpansionManager() | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |         .findCloudExpansionByName(params.get(0)).orElse(null); | ||||||
| 	{ |     if (expansion == null) { | ||||||
| 		if (params.isEmpty()) |       Msg.msg(sender, | ||||||
| 		{ |           "&cFailed to find an expansion named: &f" + params.get(0)); | ||||||
| 			Msg.msg(sender, |       return; | ||||||
| 					"&cYou must supply the name of an expansion."); |     } | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final CloudExpansion expansion = plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)).orElse(null); |     final CloudExpansion.Version version; | ||||||
| 		if (expansion == null) |     if (params.size() < 2) { | ||||||
| 		{ |       version = expansion.getVersion(expansion.getLatestVersion()); | ||||||
| 			Msg.msg(sender, |       if (version == null) { | ||||||
| 					"&cFailed to find an expansion named: &f" + params.get(0)); |         Msg.msg(sender, | ||||||
| 			return; |             "&cCould not find latest version for expansion."); | ||||||
| 		} |         return; | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       version = expansion.getVersion(params.get(1)); | ||||||
|  |       if (version == null) { | ||||||
|  |         Msg.msg(sender, | ||||||
|  |             "&cCould not find specified version: &f" + params.get(1), | ||||||
|  |             "&7Available versions: &f" + expansion.getAvailableVersions()); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		final CloudExpansion.Version version; |     plugin.getCloudExpansionManager().downloadExpansion(expansion, version) | ||||||
| 		if (params.size() < 2) |         .whenComplete((file, exception) -> { | ||||||
| 		{ |           if (exception != null) { | ||||||
| 			version = expansion.getVersion(expansion.getLatestVersion()); |             Msg.msg(sender, | ||||||
| 			if (version == null) |                 "&cFailed to download expansion: &f" + exception.getMessage()); | ||||||
| 			{ |             return; | ||||||
| 				Msg.msg(sender, |           } | ||||||
| 						"&cCould not find latest version for expansion."); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			version = expansion.getVersion(params.get(1)); |  | ||||||
| 			if (version == null) |  | ||||||
| 			{ |  | ||||||
| 				Msg.msg(sender, |  | ||||||
| 						"&cCould not find specified version: &f" + params.get(1), |  | ||||||
| 						"&7Available versions: &f" + expansion.getAvailableVersions()); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		plugin.getCloudExpansionManager().downloadExpansion(expansion, version).whenComplete((file, exception) -> { |           Msg.msg(sender, | ||||||
| 			if (exception != null) |               "&aSuccessfully downloaded expansion &f" + expansion.getName() + " [" + version | ||||||
| 			{ |                   .getVersion() + "] &ato file: &f" + file.getName(), | ||||||
| 				Msg.msg(sender, |               "&aMake sure to type &f/papi reload &ato enable your new expansion!"); | ||||||
| 						"&cFailed to download expansion: &f" + exception.getMessage()); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			Msg.msg(sender, |           plugin.getCloudExpansionManager().clean(); | ||||||
| 					"&aSuccessfully downloaded expansion &f" + expansion.getName() + " [" + version.getVersion() + "] &ato file: &f" + file.getName(), |           plugin.getCloudExpansionManager() | ||||||
| 					"&aMake sure to type &f/papi reload &ato enable your new expansion!"); |               .fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); | ||||||
|  |         }); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 			plugin.getCloudExpansionManager().clean(); |   @Override | ||||||
| 			plugin.getCloudExpansionManager().fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); |   public void complete(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 		}); |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 	} |       @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) { | ||||||
|  |     if (params.size() > 2) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 	@Override |     if (params.size() <= 1) { | ||||||
| 	public void complete(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) |       final Stream<String> names = plugin.getCloudExpansionManager().getCloudExpansions().values() | ||||||
| 	{ |           .stream().map(CloudExpansion::getName).map(name -> name.replace(' ', '_')); | ||||||
| 		if (params.size() > 2) |       suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); | ||||||
| 		{ |       return; | ||||||
| 			return; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (params.size() <= 1) |     final Optional<CloudExpansion> expansion = plugin.getCloudExpansionManager() | ||||||
| 		{ |         .findCloudExpansionByName(params.get(0)); | ||||||
| 			final Stream<String> names = plugin.getCloudExpansionManager().getCloudExpansions().values().stream().map(CloudExpansion::getName).map(name -> name.replace(' ', '_')); |     if (!expansion.isPresent()) { | ||||||
| 			suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); |       return; | ||||||
| 			return; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final Optional<CloudExpansion> expansion = plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)); |     suggestByParameter(expansion.get().getAvailableVersions().stream(), suggestions, params.get(1)); | ||||||
| 		if (!expansion.isPresent()) |   } | ||||||
| 		{ |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		suggestByParameter(expansion.get().getAvailableVersions().stream(), suggestions, params.get(1)); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,9 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.commands.impl.cloud; | package me.clip.placeholderapi.commands.impl.cloud; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Optional; | ||||||
|  | import java.util.stream.Stream; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import me.clip.placeholderapi.expansion.cloud.CloudExpansion; | import me.clip.placeholderapi.expansion.cloud.CloudExpansion; | ||||||
| @@ -28,109 +31,99 @@ import org.bukkit.command.CommandSender; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.List; | public final class CommandECloudExpansionInfo extends PlaceholderCommand { | ||||||
| import java.util.Optional; |  | ||||||
| import java.util.stream.Stream; |  | ||||||
|  |  | ||||||
| public final class CommandECloudExpansionInfo extends PlaceholderCommand |   public CommandECloudExpansionInfo() { | ||||||
| { |     super("info"); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	public CommandECloudExpansionInfo() |   @Override | ||||||
| 	{ |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 		super("info"); |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 	} |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|  |     if (params.isEmpty()) { | ||||||
|  |       Msg.msg(sender, | ||||||
|  |           "&cYou must specify the name of the expansion."); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 	@Override |     final CloudExpansion expansion = plugin.getCloudExpansionManager() | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |         .findCloudExpansionByName(params.get(0)).orElse(null); | ||||||
| 	{ |     if (expansion == null) { | ||||||
| 		if (params.isEmpty()) |       Msg.msg(sender, | ||||||
| 		{ |           "&cThere is no expansion with the name: &f" + params.get(0)); | ||||||
| 			Msg.msg(sender, |       return; | ||||||
| 					"&cYou must specify the name of the expansion."); |     } | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final CloudExpansion expansion = plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)).orElse(null); |     final StringBuilder builder = new StringBuilder(); | ||||||
| 		if (expansion == null) |  | ||||||
| 		{ |  | ||||||
| 			Msg.msg(sender, |  | ||||||
| 					"&cThere is no expansion with the name: &f" + params.get(0)); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final StringBuilder builder = new StringBuilder(); |     builder.append("&bExpansion: &f") | ||||||
|  |         .append(expansion.shouldUpdate() ? "&e" : "&a") | ||||||
|  |         .append(expansion.getName()) | ||||||
|  |         .append('\n') | ||||||
|  |         .append("&bAuthor: &f") | ||||||
|  |         .append(expansion.getAuthor()) | ||||||
|  |         .append('\n') | ||||||
|  |         .append("&bVerified: ") | ||||||
|  |         .append(expansion.isVerified() ? "&a&l✔" : "&c&l❌") | ||||||
|  |         .append('\n'); | ||||||
|  |  | ||||||
| 		builder.append("&bExpansion: &f") |     if (params.size() < 2) { | ||||||
| 			   .append(expansion.shouldUpdate() ? "&e" : "&a") |       builder.append("&bLatest Version: &f") | ||||||
| 			   .append(expansion.getName()) |           .append(expansion.getLatestVersion()) | ||||||
| 			   .append('\n') |           .append('\n') | ||||||
| 			   .append("&bAuthor: &f") |           .append("&bReleased: &f") | ||||||
| 			   .append(expansion.getAuthor()) |           .append(expansion.getTimeSinceLastUpdate()) | ||||||
| 			   .append('\n') |           .append(" ago") | ||||||
| 			   .append("&bVerified: ") |           .append('\n') | ||||||
| 			   .append(expansion.isVerified() ? "&a&l✔" : "&c&l❌") |           .append("&bRelease Notes: &f") | ||||||
| 			   .append('\n'); |           .append(expansion.getVersion().getReleaseNotes()) | ||||||
|  |           .append('\n'); | ||||||
|  |     } else { | ||||||
|  |       final CloudExpansion.Version version = expansion.getVersion(params.get(1)); | ||||||
|  |       if (version == null) { | ||||||
|  |         Msg.msg(sender, | ||||||
|  |             "&cCould not find specified version: &f" + params.get(1), | ||||||
|  |             "&aVersions: &f" + expansion.getAvailableVersions()); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |  | ||||||
| 		if (params.size() < 2) |       builder.append("&bVersion: &f") | ||||||
| 		{ |           .append(version.getVersion()) | ||||||
| 			builder.append("&bLatest Version: &f") |           .append('\n') | ||||||
| 				   .append(expansion.getLatestVersion()) |           .append("&bRelease Notes: &f") | ||||||
| 				   .append('\n') |           .append(version.getReleaseNotes()) | ||||||
| 				   .append("&bReleased: &f") |           .append('\n') | ||||||
| 				   .append(expansion.getTimeSinceLastUpdate()) |           .append("&bDownload URL: &f") | ||||||
| 				   .append(" ago") |           .append(version.getUrl()) | ||||||
| 				   .append('\n') |           .append('\n'); | ||||||
| 				   .append("&bRelease Notes: &f") |     } | ||||||
| 				   .append(expansion.getVersion().getReleaseNotes()) |  | ||||||
| 				   .append('\n'); |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			final CloudExpansion.Version version = expansion.getVersion(params.get(1)); |  | ||||||
| 			if (version == null) |  | ||||||
| 			{ |  | ||||||
| 				Msg.msg(sender, |  | ||||||
| 						"&cCould not find specified version: &f" + params.get(1), |  | ||||||
| 						"&aVersions: &f" + expansion.getAvailableVersions()); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			builder.append("&bVersion: &f") |     Msg.msg(sender, builder.toString()); | ||||||
| 				   .append(version.getVersion()) |   } | ||||||
| 				   .append('\n') |  | ||||||
| 				   .append("&bRelease Notes: &f") |  | ||||||
| 				   .append(version.getReleaseNotes()) |  | ||||||
| 				   .append('\n') |  | ||||||
| 				   .append("&bDownload URL: &f") |  | ||||||
| 				   .append(version.getUrl()) |  | ||||||
| 				   .append('\n'); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		Msg.msg(sender, builder.toString()); |   @Override | ||||||
| 	} |   public void complete(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
|  |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) { | ||||||
|  |     if (params.size() > 2) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 	@Override |     if (params.size() <= 1) { | ||||||
| 	public void complete(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) |       final Stream<String> names = plugin.getCloudExpansionManager().getCloudExpansions().values() | ||||||
| 	{ |           .stream().map(CloudExpansion::getName).map(name -> name.replace(' ', '_')); | ||||||
| 		if (params.size() > 2) |       suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); | ||||||
| 		{ |       return; | ||||||
| 			return; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (params.size() <= 1) |     final Optional<CloudExpansion> expansion = plugin.getCloudExpansionManager() | ||||||
| 		{ |         .findCloudExpansionByName(params.get(0)); | ||||||
| 			final Stream<String> names = plugin.getCloudExpansionManager().getCloudExpansions().values().stream().map(CloudExpansion::getName).map(name -> name.replace(' ', '_')); |     if (!expansion.isPresent()) { | ||||||
| 			suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); |       return; | ||||||
| 			return; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final Optional<CloudExpansion> expansion = plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)); |     suggestByParameter(expansion.get().getAvailableVersions().stream(), suggestions, params.get(1)); | ||||||
| 		if (!expansion.isPresent()) |   } | ||||||
| 		{ |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		suggestByParameter(expansion.get().getAvailableVersions().stream(), suggestions, params.get(1)); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -25,6 +25,19 @@ import com.google.common.collect.ImmutableSet; | |||||||
| import com.google.common.collect.Lists; | import com.google.common.collect.Lists; | ||||||
| import com.google.common.collect.Sets; | import com.google.common.collect.Sets; | ||||||
| import com.google.common.primitives.Ints; | import com.google.common.primitives.Ints; | ||||||
|  | import java.text.SimpleDateFormat; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.LinkedHashMap; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.Objects; | ||||||
|  | import java.util.Set; | ||||||
|  | import java.util.concurrent.atomic.AtomicInteger; | ||||||
|  | import java.util.function.Function; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | import java.util.stream.IntStream; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import me.clip.placeholderapi.configuration.ExpansionSort; | import me.clip.placeholderapi.configuration.ExpansionSort; | ||||||
| @@ -39,322 +52,297 @@ import org.bukkit.entity.Player; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.text.SimpleDateFormat; | public final class CommandECloudExpansionList extends PlaceholderCommand { | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.Collection; |  | ||||||
| import java.util.Collections; |  | ||||||
| import java.util.LinkedHashMap; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.Objects; |  | ||||||
| import java.util.Set; |  | ||||||
| import java.util.concurrent.atomic.AtomicInteger; |  | ||||||
| import java.util.function.Function; |  | ||||||
| import java.util.stream.Collectors; |  | ||||||
| import java.util.stream.IntStream; |  | ||||||
|  |  | ||||||
| public final class CommandECloudExpansionList extends PlaceholderCommand |   private static final int PAGE_SIZE = 10; | ||||||
| { |  | ||||||
|  |  | ||||||
| 	private static final int PAGE_SIZE = 10; |   @NotNull | ||||||
|  |   private static final Function<CloudExpansion, Object> EXPANSION_NAME = | ||||||
| 	@NotNull |       expansion -> (expansion.shouldUpdate() ? "&6" : expansion.hasExpansion() ? "&a" : "&7") | ||||||
| 	private static final Function<CloudExpansion, Object> EXPANSION_NAME            = |           + expansion.getName(); | ||||||
| 			expansion -> (expansion.shouldUpdate() ? "&6" : expansion.hasExpansion() ? "&a" : "&7") + expansion.getName(); |   @NotNull | ||||||
| 	@NotNull |   private static final Function<CloudExpansion, Object> EXPANSION_AUTHOR = | ||||||
| 	private static final Function<CloudExpansion, Object> EXPANSION_AUTHOR          = |       expansion -> "&f" + expansion.getAuthor(); | ||||||
| 			expansion -> "&f" + expansion.getAuthor(); |   @NotNull | ||||||
| 	@NotNull |   private static final Function<CloudExpansion, Object> EXPANSION_VERIFIED = | ||||||
| 	private static final Function<CloudExpansion, Object> EXPANSION_VERIFIED        = |       expansion -> expansion.isVerified() ? "&aY" : "&cN"; | ||||||
| 			expansion -> expansion.isVerified() ? "&aY" : "&cN"; |   @NotNull | ||||||
| 	@NotNull |   private static final Function<CloudExpansion, Object> EXPANSION_LATEST_VERSION = | ||||||
| 	private static final Function<CloudExpansion, Object> EXPANSION_LATEST_VERSION  = |       expansion -> "&f" + expansion.getLatestVersion(); | ||||||
| 			expansion -> "&f" + expansion.getLatestVersion(); |   @NotNull | ||||||
| 	@NotNull |   private static final Function<CloudExpansion, Object> EXPANSION_CURRENT_VERSION = | ||||||
| 	private static final Function<CloudExpansion, Object> EXPANSION_CURRENT_VERSION = |       expansion -> "&f" + PlaceholderAPIPlugin.getInstance().getLocalExpansionManager() | ||||||
| 			expansion -> "&f" + PlaceholderAPIPlugin.getInstance().getLocalExpansionManager().findExpansionByName(expansion.getName()).map(PlaceholderExpansion::getVersion).orElse("Unknown"); |           .findExpansionByName(expansion.getName()).map(PlaceholderExpansion::getVersion) | ||||||
|  |           .orElse("Unknown"); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@Unmodifiable |   @Unmodifiable | ||||||
| 	private static final Set<String> OPTIONS = ImmutableSet.of("all", "installed"); |   private static final Set<String> OPTIONS = ImmutableSet.of("all", "installed"); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public CommandECloudExpansionList() |   public CommandECloudExpansionList() { | ||||||
| 	{ |     super("list"); | ||||||
| 		super("list"); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Override |   @NotNull | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |   private static Collection<CloudExpansion> getExpansions(@NotNull final String target, | ||||||
| 	{ |       @NotNull final PlaceholderAPIPlugin plugin) { | ||||||
| 		if (params.isEmpty()) |     switch (target.toLowerCase()) { | ||||||
| 		{ |       case "all": | ||||||
| 			Msg.msg(sender, |         return plugin.getCloudExpansionManager().getCloudExpansions().values(); | ||||||
| 					"&cYou must specify an option. [all, {author}, installed]"); |       case "installed": | ||||||
| 			return; |         return plugin.getCloudExpansionManager().getCloudExpansionsInstalled().values(); | ||||||
| 		} |       default: | ||||||
|  |         return plugin.getCloudExpansionManager().getCloudExpansionsByAuthor(target).values(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
|  |   private static List<CloudExpansion> getPage(@NotNull final List<CloudExpansion> expansions, | ||||||
|  |       final int page) { | ||||||
|  |     final int head = (page * PAGE_SIZE); | ||||||
|  |     final int tail = Math.min(expansions.size(), head + PAGE_SIZE); | ||||||
|  |  | ||||||
| 		final boolean              installed  = params.get(0).equalsIgnoreCase("installed"); |     if (expansions.size() < head) { | ||||||
| 		final List<CloudExpansion> expansions = Lists.newArrayList(getExpansions(params.get(0), plugin)); |       return Collections.emptyList(); | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		if (expansions.isEmpty()) |     return expansions.subList(head, tail); | ||||||
| 		{ |   } | ||||||
| 			Msg.msg(sender, |  | ||||||
| 					"&cNo expansions available to list."); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		expansions.sort(plugin.getPlaceholderAPIConfig().getExpansionSort().orElse(ExpansionSort.LATEST)); |   public static void addExpansionTitle(@NotNull final StringBuilder builder, | ||||||
|  |       @NotNull final String target, final int page) { | ||||||
|  |     switch (target.toLowerCase()) { | ||||||
|  |       case "all": | ||||||
|  |         builder.append("&bAll Expansions"); | ||||||
|  |         break; | ||||||
|  |       case "installed": | ||||||
|  |         builder.append("&bInstalled Expansions"); | ||||||
|  |         break; | ||||||
|  |       default: | ||||||
|  |         builder.append("&bExpansions by &f") | ||||||
|  |             .append(target); | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		if (!(sender instanceof Player) && params.size() < 2) |     if (page == -1) { | ||||||
| 		{ |       builder.append('\n'); | ||||||
| 			final StringBuilder builder = new StringBuilder(); |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 			addExpansionTitle(builder, params.get(0), -1); |     builder.append(" &bPage&7: &a") | ||||||
| 			addExpansionTable(expansions, |         .append(page) | ||||||
| 							  builder, |         .append("&r") | ||||||
| 							  1, |         .append('\n'); | ||||||
| 							  installed ? "&9Version" : "&9Latest Version", |   } | ||||||
| 							  installed ? EXPANSION_CURRENT_VERSION : EXPANSION_LATEST_VERSION); |  | ||||||
|  |  | ||||||
| 			Msg.msg(sender, builder.toString()); |   @NotNull | ||||||
| 			return; |   private static JSONMessage getMessage(@NotNull final List<CloudExpansion> expansions, | ||||||
| 		} |       final int page, final int limit, @NotNull final String target) { | ||||||
|  |     final SimpleDateFormat format = PlaceholderAPIPlugin.getDateFormat(); | ||||||
|  |  | ||||||
| 		final int page; |     final StringBuilder tooltip = new StringBuilder(); | ||||||
|  |     final JSONMessage message = JSONMessage.create(); | ||||||
|  |  | ||||||
| 		if (params.size() < 2) |     for (int index = 0; index < expansions.size(); index++) { | ||||||
| 		{ |       final CloudExpansion expansion = expansions.get(index); | ||||||
| 			page = 1; |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			//noinspection UnstableApiUsage |  | ||||||
| 			final Integer parsed = Ints.tryParse(params.get(1)); |  | ||||||
| 			if (parsed == null) |  | ||||||
| 			{ |  | ||||||
| 				Msg.msg(sender, |  | ||||||
| 						"&cPage number must be an integer."); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			final int limit = (int) Math.ceil((double) expansions.size() / PAGE_SIZE); |       tooltip.append("&bClick to download this expansion!") | ||||||
|  |           .append('\n') | ||||||
|  |           .append('\n') | ||||||
|  |           .append("&bAuthor: &f") | ||||||
|  |           .append(expansion.getAuthor()) | ||||||
|  |           .append('\n') | ||||||
|  |           .append("&bVerified: ") | ||||||
|  |           .append(expansion.isVerified() ? "&a&l✔&r" : "&c&l❌&r") | ||||||
|  |           .append('\n') | ||||||
|  |           .append("&bLatest Version: &f") | ||||||
|  |           .append(expansion.getLatestVersion()) | ||||||
|  |           .append('\n') | ||||||
|  |           .append("&bReleased: &f") | ||||||
|  |           .append(format.format(expansion.getLastUpdate())); | ||||||
|  |  | ||||||
| 			if (parsed < 1 || parsed > limit) |       final String description = expansion.getDescription(); | ||||||
| 			{ |       if (description != null && !description.isEmpty()) { | ||||||
| 				Msg.msg(sender, |         tooltip.append('\n') | ||||||
| 						"&cPage number must be in the range &8[&a1&7..&a" + limit + "&8]"); |             .append('\n') | ||||||
| 				return; |             .append("&f") | ||||||
| 			} |             .append(description.replace("\r", "").trim()); | ||||||
|  |       } | ||||||
|  |  | ||||||
| 			page = parsed; |       message.then(Msg.color( | ||||||
| 		} |           "&8" + (index + ((page - 1) * PAGE_SIZE) + 1) + ".&r " + (expansion.shouldUpdate() ? "&6" | ||||||
|  |               : expansion.hasExpansion() ? "&a" : "&7") + expansion.getName())); | ||||||
|  |  | ||||||
| 		final StringBuilder        builder = new StringBuilder(); |       message.tooltip(Msg.color(tooltip.toString())); | ||||||
| 		final List<CloudExpansion> values  = getPage(expansions, page - 1); |       message.suggestCommand("/papi ecloud download " + expansion.getName()); | ||||||
|  |  | ||||||
| 		addExpansionTitle(builder, params.get(0), page); |       if (index < expansions.size() - 1) { | ||||||
|  |         message.newline(); | ||||||
|  |       } | ||||||
|  |  | ||||||
| 		if (!(sender instanceof Player)) |       tooltip.setLength(0); | ||||||
| 		{ |     } | ||||||
| 			addExpansionTable(values, |  | ||||||
| 							  builder, |  | ||||||
| 							  ((page - 1) * PAGE_SIZE) + 1, |  | ||||||
| 							  installed ? "&9Version" : "&9Latest Version", |  | ||||||
| 							  installed ? EXPANSION_CURRENT_VERSION : EXPANSION_LATEST_VERSION); |  | ||||||
|  |  | ||||||
| 			Msg.msg(sender, builder.toString()); |     if (limit > 1) { | ||||||
|  |       message.newline(); | ||||||
|  |  | ||||||
| 			return; |       message.then("◀") | ||||||
| 		} |           .color(page > 1 ? ChatColor.GRAY : ChatColor.DARK_GRAY); | ||||||
|  |       if (page > 1) { | ||||||
|  |         message.runCommand("/papi ecloud list " + target + " " + (page - 1)); | ||||||
|  |       } | ||||||
|  |  | ||||||
| 		Msg.msg(sender, builder.toString()); |       message.then(" " + page + " ").color(ChatColor.GREEN); | ||||||
|  |  | ||||||
| 		final int limit = (int) Math.ceil((double) expansions.size() / PAGE_SIZE); |       message.then("▶") | ||||||
|  |           .color(page < limit ? ChatColor.GRAY : ChatColor.DARK_GRAY); | ||||||
|  |       if (page < limit) { | ||||||
|  |         message.runCommand("/papi ecloud list " + target + " " + (page + 1)); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		final JSONMessage message = getMessage(values, page, limit, params.get(0)); |     return message; | ||||||
| 		message.send(((Player) sender)); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Override |   private static void addExpansionTable(@NotNull final List<CloudExpansion> expansions, | ||||||
| 	public void complete(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) |       @NotNull final StringBuilder message, final int startIndex, | ||||||
| 	{ |       @NotNull final String versionTitle, | ||||||
| 		if (params.size() > 2) |       @NotNull final Function<CloudExpansion, Object> versionFunction) { | ||||||
| 		{ |     final Map<String, Function<CloudExpansion, Object>> functions = new LinkedHashMap<>(); | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (params.size() <= 1) |     final AtomicInteger counter = new AtomicInteger(startIndex); | ||||||
| 		{ |     functions.put("&f", expansion -> "&8" + counter.getAndIncrement() + "."); | ||||||
| 			suggestByParameter(Sets.union(OPTIONS, plugin.getCloudExpansionManager().getCloudExpansionAuthors()).stream(), suggestions, params.isEmpty() ? null : params.get(0)); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		suggestByParameter(IntStream.rangeClosed(1, (int) Math.ceil((double) getExpansions(params.get(0), plugin).size() / PAGE_SIZE)).mapToObj(Objects::toString), suggestions, params.get(1)); |     functions.put("&9Name", EXPANSION_NAME); | ||||||
| 	} |     functions.put("&9Author", EXPANSION_AUTHOR); | ||||||
|  |     functions.put("&9Verified", EXPANSION_VERIFIED); | ||||||
|  |     functions.put(versionTitle, versionFunction); | ||||||
|  |  | ||||||
|  |     final List<List<String>> rows = new ArrayList<>(); | ||||||
|  |  | ||||||
| 	@NotNull |     rows.add(0, new ArrayList<>(functions.keySet())); | ||||||
| 	private static Collection<CloudExpansion> getExpansions(@NotNull final String target, @NotNull final PlaceholderAPIPlugin plugin) |  | ||||||
| 	{ |  | ||||||
| 		switch (target.toLowerCase()) |  | ||||||
| 		{ |  | ||||||
| 			case "all": |  | ||||||
| 				return plugin.getCloudExpansionManager().getCloudExpansions().values(); |  | ||||||
| 			case "installed": |  | ||||||
| 				return plugin.getCloudExpansionManager().getCloudExpansionsInstalled().values(); |  | ||||||
| 			default: |  | ||||||
| 				return plugin.getCloudExpansionManager().getCloudExpansionsByAuthor(target).values(); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |     for (final CloudExpansion expansion : expansions) { | ||||||
| 	private static List<CloudExpansion> getPage(@NotNull final List<CloudExpansion> expansions, final int page) |       rows.add(functions.values().stream().map(function -> function.apply(expansion)) | ||||||
| 	{ |           .map(Objects::toString).collect(Collectors.toList())); | ||||||
| 		final int head = (page * PAGE_SIZE); |     } | ||||||
| 		final int tail = Math.min(expansions.size(), head + PAGE_SIZE); |  | ||||||
|  |  | ||||||
| 		if (expansions.size() < head) |     final List<String> table = Format.tablify(Format.Align.LEFT, rows) | ||||||
| 		{ |         .orElse(Collections.emptyList()); | ||||||
| 			return Collections.emptyList(); |     if (table.isEmpty()) { | ||||||
| 		} |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		return expansions.subList(head, tail); |     table.add(1, "&8" + Strings.repeat("-", table.get(0).length() - (rows.get(0).size() * 2))); | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public static void addExpansionTitle(@NotNull final StringBuilder builder, @NotNull final String target, final int page) |     message.append(String.join("\n", table)); | ||||||
| 	{ |   } | ||||||
| 		switch (target.toLowerCase()) |  | ||||||
| 		{ |  | ||||||
| 			case "all": |  | ||||||
| 				builder.append("&bAll Expansions"); |  | ||||||
| 				break; |  | ||||||
| 			case "installed": |  | ||||||
| 				builder.append("&bInstalled Expansions"); |  | ||||||
| 				break; |  | ||||||
| 			default: |  | ||||||
| 				builder.append("&bExpansions by &f") |  | ||||||
| 					   .append(target); |  | ||||||
| 				break; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (page == -1) |   @Override | ||||||
| 		{ |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 			builder.append('\n'); |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 			return; |       @NotNull @Unmodifiable final List<String> params) { | ||||||
| 		} |     if (params.isEmpty()) { | ||||||
|  |       Msg.msg(sender, | ||||||
|  |           "&cYou must specify an option. [all, {author}, installed]"); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		builder.append(" &bPage&7: &a") |     final boolean installed = params.get(0).equalsIgnoreCase("installed"); | ||||||
| 			   .append(page) |     final List<CloudExpansion> expansions = Lists | ||||||
| 			   .append("&r") |         .newArrayList(getExpansions(params.get(0), plugin)); | ||||||
| 			   .append('\n'); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |     if (expansions.isEmpty()) { | ||||||
|  |       Msg.msg(sender, | ||||||
|  |           "&cNo expansions available to list."); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 	@NotNull |     expansions | ||||||
| 	private static JSONMessage getMessage(@NotNull final List<CloudExpansion> expansions, final int page, final int limit, @NotNull final String target) |         .sort(plugin.getPlaceholderAPIConfig().getExpansionSort().orElse(ExpansionSort.LATEST)); | ||||||
| 	{ |  | ||||||
| 		final SimpleDateFormat format = PlaceholderAPIPlugin.getDateFormat(); |  | ||||||
|  |  | ||||||
| 		final StringBuilder tooltip = new StringBuilder(); |     if (!(sender instanceof Player) && params.size() < 2) { | ||||||
| 		final JSONMessage   message = JSONMessage.create(); |       final StringBuilder builder = new StringBuilder(); | ||||||
|  |  | ||||||
| 		for (int index = 0; index < expansions.size(); index++) |       addExpansionTitle(builder, params.get(0), -1); | ||||||
| 		{ |       addExpansionTable(expansions, | ||||||
| 			final CloudExpansion expansion = expansions.get(index); |           builder, | ||||||
|  |           1, | ||||||
|  |           installed ? "&9Version" : "&9Latest Version", | ||||||
|  |           installed ? EXPANSION_CURRENT_VERSION : EXPANSION_LATEST_VERSION); | ||||||
|  |  | ||||||
| 			tooltip.append("&bClick to download this expansion!") |       Msg.msg(sender, builder.toString()); | ||||||
| 				   .append('\n') |       return; | ||||||
| 				   .append('\n') |     } | ||||||
| 				   .append("&bAuthor: &f") |  | ||||||
| 				   .append(expansion.getAuthor()) |  | ||||||
| 				   .append('\n') |  | ||||||
| 				   .append("&bVerified: ") |  | ||||||
| 				   .append(expansion.isVerified() ? "&a&l✔&r" : "&c&l❌&r") |  | ||||||
| 				   .append('\n') |  | ||||||
| 				   .append("&bLatest Version: &f") |  | ||||||
| 				   .append(expansion.getLatestVersion()) |  | ||||||
| 				   .append('\n') |  | ||||||
| 				   .append("&bReleased: &f") |  | ||||||
| 				   .append(format.format(expansion.getLastUpdate())); |  | ||||||
|  |  | ||||||
| 			final String description = expansion.getDescription(); |     final int page; | ||||||
| 			if (description != null && !description.isEmpty()) |  | ||||||
| 			{ |  | ||||||
| 				tooltip.append('\n') |  | ||||||
| 					   .append('\n') |  | ||||||
| 					   .append("&f") |  | ||||||
| 					   .append(description.replace("\r", "").trim()); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			message.then(Msg.color("&8" + (index + ((page - 1) * PAGE_SIZE) + 1) + ".&r " + (expansion.shouldUpdate() ? "&6" : expansion.hasExpansion() ? "&a" : "&7") + expansion.getName())); |     if (params.size() < 2) { | ||||||
|  |       page = 1; | ||||||
|  |     } else { | ||||||
|  |       //noinspection UnstableApiUsage | ||||||
|  |       final Integer parsed = Ints.tryParse(params.get(1)); | ||||||
|  |       if (parsed == null) { | ||||||
|  |         Msg.msg(sender, | ||||||
|  |             "&cPage number must be an integer."); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |  | ||||||
| 			message.tooltip(Msg.color(tooltip.toString())); |       final int limit = (int) Math.ceil((double) expansions.size() / PAGE_SIZE); | ||||||
| 			message.suggestCommand("/papi ecloud download " + expansion.getName()); |  | ||||||
|  |  | ||||||
| 			if (index < expansions.size() - 1) |       if (parsed < 1 || parsed > limit) { | ||||||
| 			{ |         Msg.msg(sender, | ||||||
| 				message.newline(); |             "&cPage number must be in the range &8[&a1&7..&a" + limit + "&8]"); | ||||||
| 			} |         return; | ||||||
|  |       } | ||||||
|  |  | ||||||
| 			tooltip.setLength(0); |       page = parsed; | ||||||
| 		} |     } | ||||||
|  |  | ||||||
| 		if (limit > 1) |     final StringBuilder builder = new StringBuilder(); | ||||||
| 		{ |     final List<CloudExpansion> values = getPage(expansions, page - 1); | ||||||
| 			message.newline(); |  | ||||||
|  |  | ||||||
| 			message.then("◀") |     addExpansionTitle(builder, params.get(0), page); | ||||||
| 				   .color(page > 1 ? ChatColor.GRAY : ChatColor.DARK_GRAY); |  | ||||||
| 			if (page > 1) |  | ||||||
| 			{ |  | ||||||
| 				message.runCommand("/papi ecloud list " + target + " " + (page - 1)); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			message.then(" " + page + " ").color(ChatColor.GREEN); |     if (!(sender instanceof Player)) { | ||||||
|  |       addExpansionTable(values, | ||||||
|  |           builder, | ||||||
|  |           ((page - 1) * PAGE_SIZE) + 1, | ||||||
|  |           installed ? "&9Version" : "&9Latest Version", | ||||||
|  |           installed ? EXPANSION_CURRENT_VERSION : EXPANSION_LATEST_VERSION); | ||||||
|  |  | ||||||
| 			message.then("▶") |       Msg.msg(sender, builder.toString()); | ||||||
| 				   .color(page < limit ? ChatColor.GRAY : ChatColor.DARK_GRAY); |  | ||||||
| 			if (page < limit) |  | ||||||
| 			{ |  | ||||||
| 				message.runCommand("/papi ecloud list " + target + " " + (page + 1)); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return message; |       return; | ||||||
| 	} |     } | ||||||
|  |  | ||||||
| 	private static void addExpansionTable(@NotNull final List<CloudExpansion> expansions, @NotNull final StringBuilder message, final int startIndex, @NotNull final String versionTitle, @NotNull final Function<CloudExpansion, Object> versionFunction) |     Msg.msg(sender, builder.toString()); | ||||||
| 	{ |  | ||||||
| 		final Map<String, Function<CloudExpansion, Object>> functions = new LinkedHashMap<>(); |  | ||||||
|  |  | ||||||
| 		final AtomicInteger counter = new AtomicInteger(startIndex); |     final int limit = (int) Math.ceil((double) expansions.size() / PAGE_SIZE); | ||||||
| 		functions.put("&f", expansion -> "&8" + counter.getAndIncrement() + "."); |  | ||||||
|  |  | ||||||
| 		functions.put("&9Name", EXPANSION_NAME); |     final JSONMessage message = getMessage(values, page, limit, params.get(0)); | ||||||
| 		functions.put("&9Author", EXPANSION_AUTHOR); |     message.send(((Player) sender)); | ||||||
| 		functions.put("&9Verified", EXPANSION_VERIFIED); |   } | ||||||
| 		functions.put(versionTitle, versionFunction); |  | ||||||
|  |  | ||||||
| 		final List<List<String>> rows = new ArrayList<>(); |   @Override | ||||||
|  |   public void complete(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
|  |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) { | ||||||
|  |     if (params.size() > 2) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		rows.add(0, new ArrayList<>(functions.keySet())); |     if (params.size() <= 1) { | ||||||
|  |       suggestByParameter( | ||||||
|  |           Sets.union(OPTIONS, plugin.getCloudExpansionManager().getCloudExpansionAuthors()) | ||||||
|  |               .stream(), suggestions, params.isEmpty() ? null : params.get(0)); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		for (final CloudExpansion expansion : expansions) |     suggestByParameter(IntStream.rangeClosed(1, | ||||||
| 		{ |         (int) Math.ceil((double) getExpansions(params.get(0), plugin).size() / PAGE_SIZE)) | ||||||
| 			rows.add(functions.values().stream().map(function -> function.apply(expansion)).map(Objects::toString).collect(Collectors.toList())); |         .mapToObj(Objects::toString), suggestions, params.get(1)); | ||||||
| 		} |   } | ||||||
|  |  | ||||||
| 		final List<String> table = Format.tablify(Format.Align.LEFT, rows).orElse(Collections.emptyList()); |  | ||||||
| 		if (table.isEmpty()) |  | ||||||
| 		{ |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		table.add(1, "&8" + Strings.repeat("-", table.get(0).length() - (rows.get(0).size() * 2))); |  | ||||||
|  |  | ||||||
| 		message.append(String.join("\n", table)); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,6 +21,9 @@ | |||||||
| package me.clip.placeholderapi.commands.impl.cloud; | package me.clip.placeholderapi.commands.impl.cloud; | ||||||
|  |  | ||||||
| import com.google.common.collect.Lists; | import com.google.common.collect.Lists; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | import java.util.stream.Stream; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import me.clip.placeholderapi.expansion.cloud.CloudExpansion; | import me.clip.placeholderapi.expansion.cloud.CloudExpansion; | ||||||
| @@ -29,68 +32,63 @@ import org.bukkit.command.CommandSender; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.List; | public final class CommandECloudExpansionPlaceholders extends PlaceholderCommand { | ||||||
| import java.util.stream.Collectors; |  | ||||||
| import java.util.stream.Stream; |  | ||||||
|  |  | ||||||
| public final class CommandECloudExpansionPlaceholders extends PlaceholderCommand |   public CommandECloudExpansionPlaceholders() { | ||||||
| { |     super("placeholders"); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	public CommandECloudExpansionPlaceholders() |   @Override | ||||||
| 	{ |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 		super("placeholders"); |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 	} |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|  |     if (params.isEmpty()) { | ||||||
|  |       Msg.msg(sender, | ||||||
|  |           "&cYou must specify the name of the expansion."); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 	@Override |     final CloudExpansion expansion = plugin.getCloudExpansionManager() | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |         .findCloudExpansionByName(params.get(0)).orElse(null); | ||||||
| 	{ |     if (expansion == null) { | ||||||
| 		if (params.isEmpty()) |       Msg.msg(sender, | ||||||
| 		{ |           "&cThere is no expansion with the name: &f" + params.get(0)); | ||||||
| 			Msg.msg(sender, |       return; | ||||||
| 					"&cYou must specify the name of the expansion."); |     } | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final CloudExpansion expansion = plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)).orElse(null); |     final List<String> placeholders = expansion.getPlaceholders(); | ||||||
| 		if (expansion == null) |     if (placeholders == null || placeholders.isEmpty()) { | ||||||
| 		{ |       Msg.msg(sender, | ||||||
| 			Msg.msg(sender, |           "&cThe expansion specified does not have placeholders listed."); | ||||||
| 					"&cThere is no expansion with the name: &f" + params.get(0)); |       return; | ||||||
| 			return; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final List<String> placeholders = expansion.getPlaceholders(); |     final List<List<String>> partitions = Lists | ||||||
| 		if (placeholders == null || placeholders.isEmpty()) |         .partition(placeholders.stream().sorted().collect(Collectors.toList()), 10); | ||||||
| 		{ |  | ||||||
| 			Msg.msg(sender, |  | ||||||
| 					"&cThe expansion specified does not have placeholders listed."); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final List<List<String>> partitions = Lists.partition(placeholders.stream().sorted().collect(Collectors.toList()), 10); |     Msg.msg(sender, | ||||||
|  |         "&6" + placeholders.size() + "&7 placeholders: &a", | ||||||
|  |         partitions.stream().map(partition -> String.join(", ", partition)) | ||||||
|  |             .collect(Collectors.joining("\n"))); | ||||||
|  |  | ||||||
| 		Msg.msg(sender, |   } | ||||||
| 				"&6" + placeholders.size() + "&7 placeholders: &a", |  | ||||||
| 				partitions.stream().map(partition -> "  " + String.join(", ", partition)).collect(Collectors.joining("\n"))); |  | ||||||
|  |  | ||||||
| 	} |   @Override | ||||||
|  |   public void complete(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
|  |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) { | ||||||
|  |     if (params.size() > 1) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 	@Override |     final Stream<String> names = plugin.getCloudExpansionManager() | ||||||
| 	public void complete(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) |         .getCloudExpansions() | ||||||
| 	{ |         .values() | ||||||
| 		if (params.size() > 1) |         .stream() | ||||||
| 		{ |         .map(CloudExpansion::getName) | ||||||
| 			return; |         .map(name -> name.replace(' ', '_')); | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final Stream<String> names = plugin.getCloudExpansionManager() |     suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); | ||||||
| 										   .getCloudExpansions() |   } | ||||||
| 										   .values() |  | ||||||
| 										   .stream() |  | ||||||
| 										   .map(CloudExpansion::getName) |  | ||||||
| 										   .map(name -> name.replace(' ', '_')); |  | ||||||
|  |  | ||||||
| 		suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.commands.impl.cloud; | package me.clip.placeholderapi.commands.impl.cloud; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import me.clip.placeholderapi.util.Msg; | import me.clip.placeholderapi.util.Msg; | ||||||
| @@ -27,24 +28,22 @@ import org.bukkit.command.CommandSender; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.List; | public final class CommandECloudRefresh extends PlaceholderCommand { | ||||||
|  |  | ||||||
| public final class CommandECloudRefresh extends PlaceholderCommand |   public CommandECloudRefresh() { | ||||||
| { |     super("refresh"); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	public CommandECloudRefresh() |   @Override | ||||||
| 	{ |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 		super("refresh"); |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 	} |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|  |     plugin.getCloudExpansionManager().clean(); | ||||||
|  |     plugin.getCloudExpansionManager() | ||||||
|  |         .fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); | ||||||
|  |  | ||||||
| 	@Override |     Msg.msg(sender, | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |         "&aThe eCloud manager has been refreshed!"); | ||||||
| 	{ |   } | ||||||
| 		plugin.getCloudExpansionManager().clean(); |  | ||||||
| 		plugin.getCloudExpansionManager().fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); |  | ||||||
|  |  | ||||||
| 		Msg.msg(sender, |  | ||||||
| 				"&aThe eCloud Manager has been refreshed!"); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.commands.impl.cloud; | package me.clip.placeholderapi.commands.impl.cloud; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import me.clip.placeholderapi.expansion.manager.CloudExpansionManager; | import me.clip.placeholderapi.expansion.manager.CloudExpansionManager; | ||||||
| @@ -28,36 +29,36 @@ import org.bukkit.command.CommandSender; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.List; | public final class CommandECloudStatus extends PlaceholderCommand { | ||||||
|  |  | ||||||
| public final class CommandECloudStatus extends PlaceholderCommand |   public CommandECloudStatus() { | ||||||
| { |     super("status"); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	public CommandECloudStatus() |   @Override | ||||||
| 	{ |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 		super("status"); |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 	} |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|  |     final CloudExpansionManager manager = plugin.getCloudExpansionManager(); | ||||||
|  |  | ||||||
| 	@Override |     final int updateCount = manager.getCloudUpdateCount(); | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |     final int authorCount = manager.getCloudExpansionAuthorCount(); | ||||||
| 	{ |     final int expansionCount = manager.getCloudExpansions().size(); | ||||||
| 		final CloudExpansionManager manager = plugin.getCloudExpansionManager(); |  | ||||||
|  |  | ||||||
| 		final int updateCount    = manager.getCloudUpdateCount(); |     final StringBuilder builder = new StringBuilder(); | ||||||
| 		final int authorCount    = manager.getCloudExpansionAuthorCount(); |  | ||||||
| 		final int expansionCount = manager.getCloudExpansions().size(); |  | ||||||
|  |  | ||||||
| 		final StringBuilder builder = new StringBuilder(); |     builder.append("&bThere are &a").append(expansionCount) | ||||||
|  |         .append("&b expansions available on the eCloud.").append('\n'); | ||||||
|  |     builder.append("&7A total of &f").append(authorCount) | ||||||
|  |         .append("&7 authors have contributed to the eCloud.").append('\n'); | ||||||
|  |  | ||||||
| 		builder.append("&bThere are &a").append(expansionCount).append("&b expansions available on the eCloud.").append('\n'); |     if (updateCount > 0) { | ||||||
| 		builder.append("&7A total of &f").append(authorCount).append("&7 authors have contributed to the eCloud.").append('\n'); |       builder.append("&eYou have &f").append(updateCount) | ||||||
|  |           .append(updateCount > 1 ? "&e expansions" : "&e expansion").append("installed that ") | ||||||
|  |           .append(updateCount > 1 ? "have an" : "has an").append(" update available."); | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		if (updateCount > 0) |     Msg.msg(sender, builder.toString()); | ||||||
| 		{ |   } | ||||||
| 			builder.append("&eYou have &a").append(updateCount).append("&e expansions installed that have updates available."); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		Msg.msg(sender,builder.toString()); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.commands.impl.cloud; | package me.clip.placeholderapi.commands.impl.cloud; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import me.clip.placeholderapi.util.Msg; | import me.clip.placeholderapi.util.Msg; | ||||||
| @@ -27,53 +28,45 @@ import org.bukkit.command.CommandSender; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.List; | public final class CommandECloudToggle extends PlaceholderCommand { | ||||||
|  |  | ||||||
| public final class CommandECloudToggle extends PlaceholderCommand |   public CommandECloudToggle() { | ||||||
| { |     super("toggle", "enable", "disable"); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	public CommandECloudToggle() |   @Override | ||||||
| 	{ |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 		super("toggle", "enable", "disable"); |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 	} |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|  |     final boolean desiredState; | ||||||
|  |     final boolean currentState = plugin.getPlaceholderAPIConfig().isCloudEnabled(); | ||||||
|  |  | ||||||
| 	@Override |     switch (alias.toLowerCase()) { | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |       case "enable": | ||||||
| 	{ |         desiredState = true; | ||||||
| 		final boolean desiredState; |         break; | ||||||
| 		final boolean currentState = plugin.getPlaceholderAPIConfig().isCloudEnabled(); |       case "disable": | ||||||
|  |         desiredState = false; | ||||||
|  |         break; | ||||||
|  |       default: | ||||||
|  |         desiredState = !currentState; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		switch (alias.toLowerCase()) |     if (desiredState == currentState) { | ||||||
| 		{ |       Msg.msg(sender, "&7The eCloud Manager is already " + (desiredState ? "enabled" : "disabled")); | ||||||
| 			case "enable": |       return; | ||||||
| 				desiredState = true; |     } | ||||||
| 				break; |  | ||||||
| 			case "disable": |  | ||||||
| 				desiredState = false; |  | ||||||
| 				break; |  | ||||||
| 			default: |  | ||||||
| 				desiredState = !currentState; |  | ||||||
| 				break; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (desiredState == currentState) |     plugin.getPlaceholderAPIConfig().setCloudEnabled(desiredState); | ||||||
| 		{ |  | ||||||
| 			Msg.msg(sender, "&7The eCloud Manager is already " + (desiredState ? "enabled" : "disabled")); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		plugin.getPlaceholderAPIConfig().setCloudEnabled(desiredState); |     if (desiredState) { | ||||||
|  |       plugin.getCloudExpansionManager().load(); | ||||||
|  |     } else { | ||||||
|  |       plugin.getCloudExpansionManager().kill(); | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		if (desiredState) |     Msg.msg(sender, "&aThe eCloud Manager has been " + (desiredState ? "enabled" : "disabled")); | ||||||
| 		{ |   } | ||||||
| 			plugin.getCloudExpansionManager().load(); |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			plugin.getCloudExpansionManager().kill(); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		Msg.msg(sender, "&aThe eCloud Manager has been " + (desiredState ? "enabled" : "disabled")); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,6 +21,12 @@ | |||||||
| package me.clip.placeholderapi.commands.impl.cloud; | package me.clip.placeholderapi.commands.impl.cloud; | ||||||
|  |  | ||||||
| import com.google.common.collect.Lists; | import com.google.common.collect.Lists; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Objects; | ||||||
|  | import java.util.Optional; | ||||||
|  | import java.util.concurrent.CompletableFuture; | ||||||
|  | import java.util.stream.Collectors; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import me.clip.placeholderapi.expansion.PlaceholderExpansion; | import me.clip.placeholderapi.expansion.PlaceholderExpansion; | ||||||
| @@ -32,114 +38,103 @@ import org.jetbrains.annotations.NotNull; | |||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Objects; |  | ||||||
| import java.util.Optional; |  | ||||||
| import java.util.concurrent.CompletableFuture; |  | ||||||
| import java.util.stream.Collectors; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * please don't flame me for this code, I will fix this shit later. |  * please don't flame me for this code, I will fix this shit later. | ||||||
|  */ |  */ | ||||||
| public final class CommandECloudUpdate extends PlaceholderCommand | public final class CommandECloudUpdate extends PlaceholderCommand { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	public CommandECloudUpdate() |   public CommandECloudUpdate() { | ||||||
| 	{ |     super("update"); | ||||||
| 		super("update"); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   private static CompletableFuture<List<@Nullable Class<? extends PlaceholderExpansion>>> downloadAndDiscover( | ||||||
|  |       @NotNull final List<CloudExpansion> expansions, @NotNull final PlaceholderAPIPlugin plugin) { | ||||||
|  |     return expansions.stream() | ||||||
|  |         .map(expansion -> plugin.getCloudExpansionManager() | ||||||
|  |             .downloadExpansion(expansion, expansion.getVersion())) | ||||||
|  |         .map(future -> future.thenCompose(plugin.getLocalExpansionManager()::findExpansionInFile)) | ||||||
|  |         .collect(Futures.collector()); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	@Override |   @Override | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 	{ |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 		if (params.isEmpty()) |       @NotNull @Unmodifiable final List<String> params) { | ||||||
| 		{ |     if (params.isEmpty()) { | ||||||
| 			Msg.msg(sender, |       Msg.msg(sender, | ||||||
| 					"&cYou must define 'all' or the name of an expansion to update."); |           "&cYou must define 'all' or the name of an expansion to update."); | ||||||
| 			return; |       return; | ||||||
| 		} |     } | ||||||
|  |  | ||||||
| 		final boolean              multiple   = params.get(0).equalsIgnoreCase("all"); |     final boolean multiple = params.get(0).equalsIgnoreCase("all"); | ||||||
| 		final List<CloudExpansion> expansions = new ArrayList<>(); |     final List<CloudExpansion> expansions = new ArrayList<>(); | ||||||
|  |  | ||||||
| 		// gather target expansions |     // gather target expansions | ||||||
| 		if (multiple) |     if (multiple) { | ||||||
| 		{ |       expansions.addAll(plugin.getCloudExpansionManager().getCloudExpansionsInstalled().values()); | ||||||
| 			expansions.addAll(plugin.getCloudExpansionManager().getCloudExpansionsInstalled().values()); |     } else { | ||||||
| 		} |       plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)) | ||||||
| 		else |           .ifPresent(expansions::add); | ||||||
| 		{ |     } | ||||||
| 			plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)).ifPresent(expansions::add); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// remove the ones that are the latest version |     // remove the ones that are the latest version | ||||||
| 		expansions.removeIf(expansion -> !expansion.shouldUpdate()); |     expansions.removeIf(expansion -> !expansion.shouldUpdate()); | ||||||
|  |  | ||||||
| 		if (expansions.isEmpty()) |     if (expansions.isEmpty()) { | ||||||
| 		{ |       Msg.msg(sender, | ||||||
| 			Msg.msg(sender, |           "&cNo updates available for " + (!multiple ? "this expansion." | ||||||
| 					"&cNo updates available for " + (!multiple ? "this expansion." : "your active expansions.")); |               : "your active expansions.")); | ||||||
| 			return; |       return; | ||||||
| 		} |     } | ||||||
|  |  | ||||||
| 		Msg.msg(sender, |     Msg.msg(sender, | ||||||
| 				"&aUpdating expansions: " + expansions.stream().map(CloudExpansion::getName).collect(Collectors.joining("&7, &6", "&8[&6", "&8]&r"))); |         "&aUpdating expansions: " + expansions.stream().map(CloudExpansion::getName) | ||||||
|  |             .collect(Collectors.joining("&7, &6", "&8[&6", "&8]&r"))); | ||||||
|  |  | ||||||
|  |     Futures.onMainThread(plugin, downloadAndDiscover(expansions, plugin), (classes, exception) -> { | ||||||
|  |       if (exception != null) { | ||||||
|  |         Msg.msg(sender, | ||||||
|  |             "&cFailed to update expansions: &e" + exception.getMessage()); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |  | ||||||
| 		Futures.onMainThread(plugin, downloadAndDiscover(expansions, plugin), (classes, exception) -> { |       Msg.msg(sender, | ||||||
| 			if (exception != null) |           "&aSuccessfully downloaded updates, registering new versions."); | ||||||
| 			{ |  | ||||||
| 				Msg.msg(sender, |  | ||||||
| 						"&cFailed to update expansions: &e" + exception.getMessage()); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			Msg.msg(sender, |       final String message = classes.stream() | ||||||
| 					"&aSuccessfully downloaded updates, registering new versions."); |           .filter(Objects::nonNull) | ||||||
|  |           .map(plugin.getLocalExpansionManager()::register) | ||||||
|  |           .filter(Optional::isPresent) | ||||||
|  |           .map(Optional::get) | ||||||
|  |           .map(expansion -> "  &a" + expansion.getName() + " &f" + expansion.getVersion()) | ||||||
|  |           .collect(Collectors.joining("\n")); | ||||||
|  |  | ||||||
|  |       Msg.msg(sender, | ||||||
|  |           "&7Registered expansions:", message); | ||||||
|  |  | ||||||
| 			final String message = classes.stream() |     }); | ||||||
| 										  .filter(Objects::nonNull) |   } | ||||||
| 										  .map(plugin.getLocalExpansionManager()::register) |  | ||||||
| 										  .filter(Optional::isPresent) |  | ||||||
| 										  .map(Optional::get) |  | ||||||
| 										  .map(expansion -> "  &a" + expansion.getName() + " &f" + expansion.getVersion()) |  | ||||||
| 										  .collect(Collectors.joining("\n")); |  | ||||||
|  |  | ||||||
| 			Msg.msg(sender, |   @Override | ||||||
| 					"&7Registered expansions:", message); |   public void complete(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
|  |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) { | ||||||
|  |     if (params.size() > 1) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		}); |     final List<CloudExpansion> installed = Lists | ||||||
| 	} |         .newArrayList(plugin.getCloudExpansionManager().getCloudExpansionsInstalled().values()); | ||||||
|  |     installed.removeIf(expansion -> !expansion.shouldUpdate()); | ||||||
|  |  | ||||||
| 	@Override |     if (!installed.isEmpty() && (params.isEmpty() || "all" | ||||||
| 	public void complete(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) |         .startsWith(params.get(0).toLowerCase()))) { | ||||||
| 	{ |       suggestions.add("all"); | ||||||
| 		if (params.size() > 1) |     } | ||||||
| 		{ |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final List<CloudExpansion> installed = Lists.newArrayList(plugin.getCloudExpansionManager().getCloudExpansionsInstalled().values()); |     suggestByParameter( | ||||||
| 		installed.removeIf(expansion -> !expansion.shouldUpdate()); |         installed.stream().map(CloudExpansion::getName).map(name -> name.replace(" ", "_")), | ||||||
|  |         suggestions, params.isEmpty() ? null : params.get(0)); | ||||||
| 		if (!installed.isEmpty() && (params.isEmpty() || "all".startsWith(params.get(0).toLowerCase()))) |   } | ||||||
| 		{ |  | ||||||
| 			suggestions.add("all"); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		suggestByParameter(installed.stream().map(CloudExpansion::getName).map(name -> name.replace(" ", "_")), suggestions, params.isEmpty() ? null : params.get(0)); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	private static CompletableFuture<List<@Nullable Class<? extends PlaceholderExpansion>>> downloadAndDiscover(@NotNull final List<CloudExpansion> expansions, @NotNull final PlaceholderAPIPlugin plugin) |  | ||||||
| 	{ |  | ||||||
| 		return expansions.stream() |  | ||||||
| 						 .map(expansion -> plugin.getCloudExpansionManager().downloadExpansion(expansion, expansion.getVersion())) |  | ||||||
| 						 .map(future -> future.thenCompose(plugin.getLocalExpansionManager()::findExpansionInFile)) |  | ||||||
| 						 .collect(Futures.collector()); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,15 +22,6 @@ package me.clip.placeholderapi.commands.impl.local; | |||||||
|  |  | ||||||
| import com.google.common.io.CharStreams; | import com.google.common.io.CharStreams; | ||||||
| import com.google.gson.JsonParser; | import com.google.gson.JsonParser; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; |  | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; |  | ||||||
| import me.clip.placeholderapi.expansion.PlaceholderExpansion; |  | ||||||
| import me.clip.placeholderapi.util.Msg; |  | ||||||
| import org.bukkit.command.CommandSender; |  | ||||||
| import org.bukkit.plugin.Plugin; |  | ||||||
| import org.jetbrains.annotations.NotNull; |  | ||||||
| import org.jetbrains.annotations.Unmodifiable; |  | ||||||
|  |  | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.io.InputStream; | import java.io.InputStream; | ||||||
| import java.io.InputStreamReader; | import java.io.InputStreamReader; | ||||||
| @@ -42,158 +33,173 @@ import java.time.Instant; | |||||||
| import java.time.ZoneId; | import java.time.ZoneId; | ||||||
| import java.time.format.DateTimeFormatter; | import java.time.format.DateTimeFormatter; | ||||||
| import java.time.format.FormatStyle; | import java.time.format.FormatStyle; | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.Comparator; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Locale; | import java.util.Locale; | ||||||
| import java.util.Map; |  | ||||||
| import java.util.concurrent.CompletableFuture; | import java.util.concurrent.CompletableFuture; | ||||||
| import java.util.concurrent.CompletionException; | import java.util.concurrent.CompletionException; | ||||||
| import java.util.logging.Level; | import java.util.logging.Level; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
|  | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
|  | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
|  | import me.clip.placeholderapi.expansion.PlaceholderExpansion; | ||||||
|  | import me.clip.placeholderapi.util.Msg; | ||||||
|  | import org.bukkit.command.CommandSender; | ||||||
|  | import org.bukkit.plugin.Plugin; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| public final class CommandDump extends PlaceholderCommand | public final class CommandDump extends PlaceholderCommand { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private static final String URL = "https://paste.helpch.at/"; |   private static final String URL = "https://paste.helpch.at/"; | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG) |   private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter | ||||||
| 																		  .withLocale(Locale.US) |       .ofLocalizedDateTime(FormatStyle.LONG) | ||||||
| 																		  .withZone(ZoneId.of("UTC")); |       .withLocale(Locale.US) | ||||||
|  |       .withZone(ZoneId.of("UTC")); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public CommandDump() |   public CommandDump() { | ||||||
| 	{ |     super("dump"); | ||||||
| 		super("dump"); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Override |   @Override | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 	{ |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 		postDump(makeDump(plugin)).whenComplete((key, exception) -> { |       @NotNull @Unmodifiable final List<String> params) { | ||||||
| 			if (exception != null) |     postDump(makeDump(plugin)).whenComplete((key, exception) -> { | ||||||
| 			{ |       if (exception != null) { | ||||||
| 				plugin.getLogger().log(Level.WARNING, "failed to post dump details", exception); |         plugin.getLogger().log(Level.WARNING, "failed to post dump details", exception); | ||||||
|  |  | ||||||
| 				Msg.msg(sender, |         Msg.msg(sender, | ||||||
| 						"&cFailed to post dump details, check console."); |             "&cFailed to post dump details, check console."); | ||||||
| 				return; |         return; | ||||||
| 			} |       } | ||||||
|  |  | ||||||
| 			Msg.msg(sender, |       Msg.msg(sender, | ||||||
| 					"&aSuccessfully posted dump: " + URL + key); |           "&aSuccessfully posted dump: " + URL + key); | ||||||
| 		}); |     }); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private CompletableFuture<String> postDump(@NotNull final String dump) |   private CompletableFuture<String> postDump(@NotNull final String dump) { | ||||||
| 	{ |     return CompletableFuture.supplyAsync(() -> { | ||||||
| 		return CompletableFuture.supplyAsync(() -> { |       try { | ||||||
| 			try |         final HttpURLConnection connection = ((HttpURLConnection) new URL(URL + "documents") | ||||||
| 			{ |             .openConnection()); | ||||||
| 				final HttpURLConnection connection = ((HttpURLConnection) new URL(URL + "documents").openConnection()); |         connection.setRequestMethod("POST"); | ||||||
| 				connection.setRequestMethod("POST"); |         connection.setRequestProperty("Content-Type", "text/plain; charset=utf-8"); | ||||||
| 				connection.setRequestProperty("Content-Type", "text/plain; charset=utf-8"); |         connection.setDoOutput(true); | ||||||
| 				connection.setDoOutput(true); |  | ||||||
|  |  | ||||||
| 				connection.connect(); |         connection.connect(); | ||||||
|  |  | ||||||
| 				try (final OutputStream stream = connection.getOutputStream()) |         try (final OutputStream stream = connection.getOutputStream()) { | ||||||
| 				{ |           stream.write(dump.getBytes(StandardCharsets.UTF_8)); | ||||||
| 					stream.write(dump.getBytes(StandardCharsets.UTF_8)); |         } | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				try (final InputStream stream = connection.getInputStream()) |         try (final InputStream stream = connection.getInputStream()) { | ||||||
| 				{ |           //noinspection UnstableApiUsage | ||||||
| 					//noinspection UnstableApiUsage |           final String json = CharStreams | ||||||
| 					final String json = CharStreams.toString(new InputStreamReader(stream, StandardCharsets.UTF_8)); |               .toString(new InputStreamReader(stream, StandardCharsets.UTF_8)); | ||||||
| 					return JsonParser.parseString(json).getAsJsonObject().get("key").getAsString(); |           return JsonParser.parseString(json).getAsJsonObject().get("key").getAsString(); | ||||||
| 				} |         } | ||||||
| 			} |       } catch (final IOException ex) { | ||||||
| 			catch (final IOException ex) |         throw new CompletionException(ex); | ||||||
| 			{ |       } | ||||||
| 				throw new CompletionException(ex); |     }); | ||||||
| 			} |   } | ||||||
| 		}); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private String makeDump(@NotNull final PlaceholderAPIPlugin plugin) |   private String makeDump(@NotNull final PlaceholderAPIPlugin plugin) { | ||||||
| 	{ |     final StringBuilder builder = new StringBuilder(); | ||||||
| 		final StringBuilder builder = new StringBuilder(); |  | ||||||
|  |  | ||||||
| 		builder.append("Generated: ") |     builder.append("Generated: ") | ||||||
| 			   .append(DATE_FORMAT.format(Instant.now())) |         .append(DATE_FORMAT.format(Instant.now())) | ||||||
| 			   .append("\n\n"); |         .append("\n\n"); | ||||||
|  |  | ||||||
| 		builder.append("PlaceholderAPI: ") |     builder.append("PlaceholderAPI: ") | ||||||
| 			   .append(plugin.getDescription().getVersion()) |         .append(plugin.getDescription().getVersion()) | ||||||
| 			   .append("\n\n"); |         .append("\n\n"); | ||||||
|  |  | ||||||
| 		builder.append("Expansions Registered:") |     builder.append("Expansions Registered:") | ||||||
| 			   .append('\n'); |         .append('\n'); | ||||||
|  |  | ||||||
|  |     final List<PlaceholderExpansion> expansions = plugin.getLocalExpansionManager() | ||||||
|  |         .getExpansions() | ||||||
|  |         .stream() | ||||||
|  |         .sorted(Comparator.comparing(PlaceholderExpansion::getIdentifier)) | ||||||
|  |         .sorted(Comparator.comparing(PlaceholderExpansion::getAuthor)) | ||||||
|  |         .collect(Collectors.toList()); | ||||||
|  |  | ||||||
| 		final Map<String, List<PlaceholderExpansion>> expansions = plugin.getLocalExpansionManager() |     int size = 0; | ||||||
| 																		 .getExpansions() |  | ||||||
| 																		 .stream() |  | ||||||
| 																		 .collect(Collectors.groupingBy(PlaceholderExpansion::getAuthor)); |  | ||||||
|  |  | ||||||
| 		for (final Map.Entry<String, List<PlaceholderExpansion>> expansionsByAuthor : expansions.entrySet()) |     for (final String name : expansions.stream().map(PlaceholderExpansion::getIdentifier) | ||||||
| 		{ |         .collect(Collectors.toList())) { | ||||||
| 			builder.append("  ") |       if (name.length() > size) { | ||||||
| 				   .append(expansionsByAuthor.getKey()) |         size = name.length(); | ||||||
| 				   .append(": ") |       } | ||||||
| 				   .append('\n'); |     } | ||||||
|  |  | ||||||
| 			for (final PlaceholderExpansion expansion : expansionsByAuthor.getValue()) |     for (final PlaceholderExpansion expansion : expansions) { | ||||||
| 			{ |       builder.append("  ") | ||||||
| 				builder.append("    ") |           .append(String.format("%-" + size + "s", expansion.getIdentifier())) | ||||||
| 					   .append(expansion.getName()) |           .append(" [Author: ") | ||||||
| 					   .append(':') |           .append(expansion.getAuthor()) | ||||||
| 					   .append(expansion.getVersion()) |           .append(", Version: ") | ||||||
| 					   .append('\n'); |           .append(expansion.getVersion()) | ||||||
| 			} |           .append("]\n"); | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		builder.append('\n'); |     } | ||||||
|  |  | ||||||
| 		builder.append("Expansions Directory:") |     builder.append('\n'); | ||||||
| 			   .append('\n'); |  | ||||||
|  |  | ||||||
| 		final String[] jars = plugin.getLocalExpansionManager() |     builder.append("Expansions Directory:") | ||||||
| 									.getExpansionsFolder() |         .append('\n'); | ||||||
| 									.list((dir, name) -> name.toLowerCase().endsWith(".jar")); |  | ||||||
|  |  | ||||||
| 		for (final String jar : jars) |     final String[] jars = plugin.getLocalExpansionManager() | ||||||
| 		{ |         .getExpansionsFolder() | ||||||
| 			builder.append("  ") |         .list((dir, name) -> name.toLowerCase().endsWith(".jar")); | ||||||
| 				   .append(jar) |  | ||||||
| 				   .append('\n'); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		builder.append('\n'); |     for (final String jar : jars) { | ||||||
|  |       builder.append("  ") | ||||||
|  |           .append(jar) | ||||||
|  |           .append('\n'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     builder.append('\n'); | ||||||
|  |  | ||||||
| 		builder.append("Server Info: ") |     builder.append("Server Info: ") | ||||||
| 			   .append(plugin.getServer().getBukkitVersion()) |         .append(plugin.getServer().getBukkitVersion()) | ||||||
| 			   .append('/') |         .append('/') | ||||||
| 			   .append(plugin.getServer().getVersion()) |         .append(plugin.getServer().getVersion()) | ||||||
| 			   .append("\n\n"); |         .append("\n\n"); | ||||||
|  |  | ||||||
| 		builder.append("Plugin Info:") |     builder.append("Plugin Info:") | ||||||
| 			   .append('\n'); |         .append('\n'); | ||||||
|  |  | ||||||
| 		for (final Plugin other : plugin.getServer().getPluginManager().getPlugins()) |     List<Plugin> plugins = Arrays.stream(plugin.getServer().getPluginManager().getPlugins()) | ||||||
| 		{ |         .sorted(Comparator.comparing(Plugin::getName)) | ||||||
| 			builder.append("  ") |         .collect(Collectors.toList()); | ||||||
| 				   .append(other.getName()) |  | ||||||
| 				   .append(": ") |  | ||||||
| 				   .append(other.getDescription().getVersion()) |  | ||||||
| 				   .append('\n'); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return builder.toString(); |     for (final String pluginName : plugins.stream().map(Plugin::getName) | ||||||
| 	} |         .collect(Collectors.toList())) { | ||||||
|  |       if (pluginName.length() > size) { | ||||||
|  |         size = pluginName.length(); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (final Plugin other : plugins) { | ||||||
|  |       builder.append("  ") | ||||||
|  |           .append(String.format("%-" + size + "s", other.getName())) | ||||||
|  |           .append(" [Version: ") | ||||||
|  |           .append(other.getDescription().getVersion()) | ||||||
|  |           .append("]") | ||||||
|  |           .append("\n"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return builder.toString(); | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,11 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.commands.impl.local; | package me.clip.placeholderapi.commands.impl.local; | ||||||
|  |  | ||||||
|  | import java.io.File; | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Optional; | ||||||
|  | import java.util.logging.Level; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import me.clip.placeholderapi.expansion.PlaceholderExpansion; | import me.clip.placeholderapi.expansion.PlaceholderExpansion; | ||||||
| @@ -30,88 +35,76 @@ import org.bukkit.command.CommandSender; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.io.File; | public final class CommandExpansionRegister extends PlaceholderCommand { | ||||||
| import java.util.Arrays; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Optional; |  | ||||||
| import java.util.logging.Level; |  | ||||||
|  |  | ||||||
| public final class CommandExpansionRegister extends PlaceholderCommand |   public CommandExpansionRegister() { | ||||||
| { |     super("register"); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	public CommandExpansionRegister() |   @Override | ||||||
| 	{ |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 		super("register"); |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 	} |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|  |     if (params.size() < 1) { | ||||||
|  |       Msg.msg(sender, | ||||||
|  |           "&cYou must specify the name of an expansion file."); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 	@Override |     final LocalExpansionManager manager = plugin.getLocalExpansionManager(); | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |  | ||||||
| 	{ |  | ||||||
| 		if (params.size() < 1) |  | ||||||
| 		{ |  | ||||||
| 			Msg.msg(sender, |  | ||||||
| 					"&cYou must specify the name of an expansion file."); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
|  |     final File file = new File(manager.getExpansionsFolder(), params.get(0)); | ||||||
|  |     if (!file.exists()) { | ||||||
|  |       Msg.msg(sender, | ||||||
|  |           "&cThe file &f" + file.getName() + "&c doesn't exist!"); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		final LocalExpansionManager manager = plugin.getLocalExpansionManager(); |     Futures.onMainThread(plugin, manager.findExpansionInFile(file), (clazz, exception) -> { | ||||||
|  |       if (exception != null) { | ||||||
|  |         Msg.msg(sender, | ||||||
|  |             "&cFailed to find expansion in file: &f" + file); | ||||||
|  |  | ||||||
| 		final File file = new File(manager.getExpansionsFolder(), params.get(0)); |         plugin.getLogger() | ||||||
| 		if (!file.exists()) |             .log(Level.WARNING, "failed to find expansion in file: " + file, exception); | ||||||
| 		{ |         return; | ||||||
| 			Msg.msg(sender, |       } | ||||||
| 					"&cThe file &f" + file.getName() + "&c doesn't exist!"); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		Futures.onMainThread(plugin, manager.findExpansionInFile(file), (clazz, exception) -> { |       if (clazz == null) { | ||||||
| 			if (exception != null) |         Msg.msg(sender, | ||||||
| 			{ |             "&cNo expansion class found in file: &f" + file); | ||||||
| 				Msg.msg(sender, |         return; | ||||||
| 						"&cFailed to find expansion in file: &f" + file); |       } | ||||||
|  |  | ||||||
| 				plugin.getLogger().log(Level.WARNING, "failed to find expansion in file: " + file, exception); |       final Optional<PlaceholderExpansion> expansion = manager.register(clazz); | ||||||
| 				return; |       if (!expansion.isPresent()) { | ||||||
| 			} |         Msg.msg(sender, | ||||||
|  |             "&cFailed to register expansion from &f" + params.get(0)); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |  | ||||||
| 			if (clazz == null) |       Msg.msg(sender, | ||||||
| 			{ |           "&aSuccessfully registered expansion: &f" + expansion.get().getName()); | ||||||
| 				Msg.msg(sender, |  | ||||||
| 						"&cNo expansion class found in file: &f" + file); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 			final Optional<PlaceholderExpansion> expansion = manager.register(clazz); |   @Override | ||||||
| 			if (!expansion.isPresent()) |   public void complete(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 			{ |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 				Msg.msg(sender, |       @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) { | ||||||
| 						"&cFailed to register expansion from &f" + params.get(0)); |     if (params.size() > 1) { | ||||||
| 				return; |       return; | ||||||
| 			} |     } | ||||||
|  |  | ||||||
| 			Msg.msg(sender, |     final String[] fileNames = plugin.getLocalExpansionManager().getExpansionsFolder() | ||||||
| 					"&aSuccessfully registered expansion: &f" + expansion.get().getName()); |         .list((dir, name) -> name.endsWith(".jar")); | ||||||
|  |     if (fileNames == null || fileNames.length == 0) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		}); |     suggestByParameter(Arrays.stream(fileNames), suggestions, | ||||||
| 	} |         params.isEmpty() ? null : params.get(0)); | ||||||
|  |   } | ||||||
| 	@Override |  | ||||||
| 	public void complete(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) |  | ||||||
| 	{ |  | ||||||
| 		if (params.size() > 1) |  | ||||||
| 		{ |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final String[] fileNames = plugin.getLocalExpansionManager().getExpansionsFolder().list((dir, name) -> name.endsWith(".jar")); |  | ||||||
| 		if (fileNames == null || fileNames.length == 0) |  | ||||||
| 		{ |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		suggestByParameter(Arrays.stream(fileNames), suggestions, params.isEmpty() ? null : params.get(0)); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,8 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.commands.impl.local; | package me.clip.placeholderapi.commands.impl.local; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Optional; | ||||||
| import me.clip.placeholderapi.PlaceholderAPI; | import me.clip.placeholderapi.PlaceholderAPI; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| @@ -29,52 +31,47 @@ import org.bukkit.command.CommandSender; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.List; | public final class CommandExpansionUnregister extends PlaceholderCommand { | ||||||
| import java.util.Optional; |  | ||||||
|  |  | ||||||
| public final class CommandExpansionUnregister extends PlaceholderCommand |   public CommandExpansionUnregister() { | ||||||
| { |     super("unregister"); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	public CommandExpansionUnregister() |   @Override | ||||||
| 	{ |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 		super("unregister"); |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 	} |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|  |     if (params.isEmpty()) { | ||||||
|  |       Msg.msg(sender, | ||||||
|  |           "&cYou must specify the name of the expansion."); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 	@Override |     final Optional<PlaceholderExpansion> expansion = plugin.getLocalExpansionManager() | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |         .findExpansionByName(params.get(0)); | ||||||
| 	{ |     if (!expansion.isPresent()) { | ||||||
| 		if (params.isEmpty()) |       Msg.msg(sender, | ||||||
| 		{ |           "&cThere is no expansion loaded with the identifier: &f" + params.get(0)); | ||||||
| 			Msg.msg(sender, |       return; | ||||||
| 					"&cYou must specify the name of the expansion."); |     } | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final Optional<PlaceholderExpansion> expansion = plugin.getLocalExpansionManager().findExpansionByName(params.get(0)); |     final String message = !expansion.get().unregister() ? | ||||||
| 		if (!expansion.isPresent()) |         "&cFailed to unregister expansion: &f" : | ||||||
| 		{ |         "&aSuccessfully unregistered expansion: &f"; | ||||||
| 			Msg.msg(sender, |  | ||||||
| 					"&cThere is no expansion loaded with the identifier: &f" + params.get(0)); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
|  |     Msg.msg(sender, message + expansion.get().getName()); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 		final String message = !expansion.get().unregister() ? |   @Override | ||||||
| 							   "&cFailed to unregister expansion: &f" : |   public void complete(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 							   "&aSuccessfully unregistered expansion: &f"; |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) { | ||||||
|  |     if (params.size() > 1) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		Msg.msg(sender, message + expansion.get().getName()); |     suggestByParameter(PlaceholderAPI.getRegisteredIdentifiers().stream(), suggestions, | ||||||
| 	} |         params.isEmpty() ? null : params.get(0)); | ||||||
|  |   } | ||||||
| 	@Override |  | ||||||
| 	public void complete(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) |  | ||||||
| 	{ |  | ||||||
| 		if (params.size() > 1) |  | ||||||
| 		{ |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		suggestByParameter(PlaceholderAPI.getRegisteredIdentifiers().stream(), suggestions, params.isEmpty() ? null : params.get(0)); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.commands.impl.local; | package me.clip.placeholderapi.commands.impl.local; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import me.clip.placeholderapi.util.Msg; | import me.clip.placeholderapi.util.Msg; | ||||||
| @@ -28,47 +29,44 @@ import org.bukkit.plugin.PluginDescriptionFile; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.List; | public final class CommandHelp extends PlaceholderCommand { | ||||||
|  |  | ||||||
| public final class CommandHelp extends PlaceholderCommand |   public CommandHelp() { | ||||||
| { |     super("help"); | ||||||
|  |   } | ||||||
| 	public CommandHelp() |  | ||||||
| 	{ |  | ||||||
| 		super("help"); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@Override |   @Override | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 	{ |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 		final PluginDescriptionFile description = plugin.getDescription(); |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|  |     final PluginDescriptionFile description = plugin.getDescription(); | ||||||
|  |  | ||||||
| 		Msg.msg(sender, |     Msg.msg(sender, | ||||||
| 				"&b&lPlaceholderAPI &8- &7Help Menu &8- &7(&f" + description.getVersion() + "&7)", |         "&b&lPlaceholderAPI &8- &7Help Menu &8- &7(&f" + description.getVersion() + "&7)", | ||||||
| 				" ", |         " ", | ||||||
| 				"&b/papi &fversion", |         "&b/papi &fbcparse &9<me/player name> <message>", | ||||||
| 				"  &7&oView plugin info/version", |         "  &7&oParse a message with placeholders and broadcast it", | ||||||
| 				"&b/papi &freload", |         "&b/papi &fcmdparse &9<me/player> <command with placeholders>", | ||||||
| 				"  &7&oReload the config of PAPI", |         "  &7&oParse a message with relational placeholders", | ||||||
| 				"&b/papi &flist", |         "&b/papi &fdump", | ||||||
| 				"  &7&oList active expansions", |         "  &7&oDump all relevant information needed to help debug issues into a paste link.", | ||||||
| 				"&b/papi &finfo &9<placeholder name>", |         "&b/papi &finfo &9<placeholder name>", | ||||||
| 				"  &7&oView information for a specific expansion", |         "  &7&oView information for a specific expansion", | ||||||
| 				"&b/papi &fparse &9<me/player name> <message>", |         "&b/papi &flist", | ||||||
| 				"  &7&oParse a message with placeholders", |         "  &7&oList active expansions", | ||||||
| 				"&b/papi &fbcparse &9<me/player name> <message>", |         "&b/papi &fparse &9<me/player name> <message>", | ||||||
| 				"  &7&oParse a message with placeholders and broadcast it", |         "  &7&oParse a message with placeholders", | ||||||
| 				"&b/papi &fparserel &9<player one> <player two> <message>", |         "&b/papi &fparserel &9<player one> <player two> <message>", | ||||||
| 				"  &7&oParse a message with relational placeholders", |         "  &7&oParse a message with relational placeholders", | ||||||
| 				"&b/papi &fcmdparse &9<me/player> <command with placeholders>", |         "&b/papi &fregister &9<file name>", | ||||||
| 				"  &7&oParse a message with relational placeholders", |         "  &7&oRegister an expansion by the name of the file", | ||||||
| 				"&b/papi &fregister &9<file name>", |         "&b/papi &freload", | ||||||
| 				"  &7&oRegister an expansion by the name of the file", |         "  &7&oReload the config of PAPI", | ||||||
| 				"&b/papi &funregister &9<expansion name>", |         "&b/papi &funregister &9<expansion name>", | ||||||
| 				"  &7&oUnregister an expansion by name", |         "  &7&oUnregister an expansion by name", | ||||||
| 				"&b/papi &fdump", |         "&b/papi &fversion", | ||||||
| 					"  &7&oDump all relevant information needed to help debug issues into a paste link."); |         "  &7&oView plugin info/version"); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.commands.impl.local; | package me.clip.placeholderapi.commands.impl.local; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
| import me.clip.placeholderapi.PlaceholderAPI; | import me.clip.placeholderapi.PlaceholderAPI; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| @@ -29,92 +30,84 @@ import org.bukkit.command.CommandSender; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.List; | public final class CommandInfo extends PlaceholderCommand { | ||||||
|  |  | ||||||
| public final class CommandInfo extends PlaceholderCommand |   public CommandInfo() { | ||||||
| { |     super("info"); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	public CommandInfo() |   @Override | ||||||
| 	{ |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 		super("info"); |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 	} |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|  |     if (params.isEmpty()) { | ||||||
|  |       Msg.msg(sender, | ||||||
|  |           "&cYou must specify the name of the expansion."); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 	@Override |     final PlaceholderExpansion expansion = plugin.getLocalExpansionManager() | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |         .findExpansionByName(params.get(0)).orElse(null); | ||||||
| 	{ |     if (expansion == null) { | ||||||
| 		if (params.isEmpty()) |       Msg.msg(sender, | ||||||
| 		{ |           "&cThere is no expansion loaded with the identifier: &f" + params.get(0)); | ||||||
| 			Msg.msg(sender, |       return; | ||||||
| 					"&cYou must specify the name of the expansion."); |     } | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final PlaceholderExpansion expansion = plugin.getLocalExpansionManager().findExpansionByName(params.get(0)).orElse(null); |     final StringBuilder builder = new StringBuilder(); | ||||||
| 		if (expansion == null) |  | ||||||
| 		{ |  | ||||||
| 			Msg.msg(sender, |  | ||||||
| 					"&cThere is no expansion loaded with the identifier: &f" + params.get(0)); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final StringBuilder builder = new StringBuilder(); |     builder.append("&7Placeholder expansion info for: &r") | ||||||
|  |         .append(expansion.getName()) | ||||||
|  |         .append('\n') | ||||||
|  |         .append("&7Status: &r") | ||||||
|  |         .append(expansion.isRegistered() ? "&aRegistered" : "7cNotRegistered") | ||||||
|  |         .append('\n'); | ||||||
|  |  | ||||||
| 		builder.append("&7Placeholder expansion info for: &r") |     final String author = expansion.getAuthor(); | ||||||
| 			   .append(expansion.getName()) |     if (author != null) { | ||||||
| 			   .append('\n') |       builder.append("&7Author: &r") | ||||||
| 			   .append("&7Status: &r") |           .append(author) | ||||||
| 			   .append(expansion.isRegistered() ? "&aRegistered" : "7cNotRegistered") |           .append('\n'); | ||||||
| 			   .append('\n'); |     } | ||||||
|  |  | ||||||
| 		final String author = expansion.getAuthor(); |     final String version = expansion.getVersion(); | ||||||
| 		if (author != null) |     if (version != null) { | ||||||
| 		{ |       builder.append("&7Version: &r") | ||||||
| 			builder.append("&7Author: &r") |           .append(version) | ||||||
| 				   .append(author) |           .append('\n'); | ||||||
| 				   .append('\n'); |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final String version = expansion.getVersion(); |     final String requiredPlugin = expansion.getRequiredPlugin(); | ||||||
| 		if (version != null) |     if (requiredPlugin != null) { | ||||||
| 		{ |       builder.append("&7Requires plugin: &r") | ||||||
| 			builder.append("&7Version: &r") |           .append(requiredPlugin) | ||||||
| 				   .append(version) |           .append('\n'); | ||||||
| 				   .append('\n'); |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final String requiredPlugin = expansion.getRequiredPlugin(); |     final List<String> placeholders = expansion.getPlaceholders(); | ||||||
| 		if (requiredPlugin != null) |     if (placeholders != null && !placeholders.isEmpty()) { | ||||||
| 		{ |       builder.append("&8&m-- &7Placeholders &8&m--&r") | ||||||
| 			builder.append("&7Requires plugin: &r") |           .append('\n'); | ||||||
| 				   .append(requiredPlugin) |  | ||||||
| 				   .append('\n'); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final List<String> placeholders = expansion.getPlaceholders(); |       for (final String placeholder : placeholders) { | ||||||
| 		if (placeholders != null && !placeholders.isEmpty()) |         builder.append(placeholder) | ||||||
| 		{ |             .append('\n'); | ||||||
| 			builder.append("&8&m-- &7Placeholders &8&m--&r") |       } | ||||||
| 				   .append('\n'); |     } | ||||||
|  |  | ||||||
| 			for (final String placeholder : placeholders) |     Msg.msg(sender, builder.toString()); | ||||||
| 			{ |   } | ||||||
| 				builder.append(placeholder) |  | ||||||
| 					   .append('\n'); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		Msg.msg(sender, builder.toString()); |   @Override | ||||||
| 	} |   public void complete(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
|  |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) { | ||||||
|  |     if (params.size() > 1) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 	@Override |     suggestByParameter(PlaceholderAPI.getRegisteredIdentifiers().stream(), suggestions, | ||||||
| 	public void complete(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) |         params.isEmpty() ? null : params.get(0)); | ||||||
| 	{ |   } | ||||||
| 		if (params.size() > 1) |  | ||||||
| 		{ |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		suggestByParameter(PlaceholderAPI.getRegisteredIdentifiers().stream(), suggestions, params.isEmpty() ? null : params.get(0)); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,6 +21,9 @@ | |||||||
| package me.clip.placeholderapi.commands.impl.local; | package me.clip.placeholderapi.commands.impl.local; | ||||||
|  |  | ||||||
| import com.google.common.collect.Lists; | import com.google.common.collect.Lists; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Set; | ||||||
|  | import java.util.stream.Collectors; | ||||||
| import me.clip.placeholderapi.PlaceholderAPI; | import me.clip.placeholderapi.PlaceholderAPI; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| @@ -29,34 +32,30 @@ import org.bukkit.command.CommandSender; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.List; | public final class CommandList extends PlaceholderCommand { | ||||||
| import java.util.Set; |  | ||||||
| import java.util.stream.Collectors; |  | ||||||
|  |  | ||||||
| public final class CommandList extends PlaceholderCommand |   public CommandList() { | ||||||
| { |     super("list"); | ||||||
|  |   } | ||||||
| 	public CommandList() |  | ||||||
| 	{ |  | ||||||
| 		super("list"); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@Override |   @Override | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 	{ |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 		final Set<String> identifiers = PlaceholderAPI.getRegisteredIdentifiers(); |       @NotNull @Unmodifiable final List<String> params) { | ||||||
| 		if (identifiers.isEmpty()) |     final Set<String> identifiers = PlaceholderAPI.getRegisteredIdentifiers(); | ||||||
| 		{ |     if (identifiers.isEmpty()) { | ||||||
| 			Msg.msg(sender, "&cThere are no placeholder hooks active!"); |       Msg.msg(sender, "&cThere are no placeholder hooks active!"); | ||||||
| 			return; |       return; | ||||||
| 		} |     } | ||||||
|  |  | ||||||
| 		final List<List<String>> partitions = Lists.partition(identifiers.stream().sorted().collect(Collectors.toList()), 10); |     final List<List<String>> partitions = Lists | ||||||
|  |         .partition(identifiers.stream().sorted().collect(Collectors.toList()), 10); | ||||||
|  |  | ||||||
| 		Msg.msg(sender, |     Msg.msg(sender, | ||||||
| 				"&7A total of &f" + identifiers.size() + "&7 placeholder hook(s) are active: &a", |         "&7A total of &f" + identifiers.size() + "&7 placeholder hook(s) are active: &a", | ||||||
| 				partitions.stream().map(partition -> String.join("&7, &a", partition)).collect(Collectors.joining("\n"))); |         partitions.stream().map(partition -> String.join("&7, &a", partition)) | ||||||
| 	} |             .collect(Collectors.joining("\n"))); | ||||||
|  |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,10 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.commands.impl.local; | package me.clip.placeholderapi.commands.impl.local; | ||||||
|  |  | ||||||
|  | import java.util.HashSet; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Set; | ||||||
|  | import java.util.stream.Stream; | ||||||
| import me.clip.placeholderapi.PlaceholderAPI; | import me.clip.placeholderapi.PlaceholderAPI; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| @@ -34,210 +38,187 @@ import org.jetbrains.annotations.NotNull; | |||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.Collection; | public final class CommandParse extends PlaceholderCommand { | ||||||
| import java.util.HashSet; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Optional; |  | ||||||
| import java.util.Set; |  | ||||||
| import java.util.stream.Stream; |  | ||||||
|  |  | ||||||
| public final class CommandParse extends PlaceholderCommand |   public CommandParse() { | ||||||
| { |     super("parse", "bcparse", "parserel", "cmdparse"); | ||||||
|  |   } | ||||||
| 	public CommandParse() |  | ||||||
| 	{ |  | ||||||
| 		super("parse", "bcparse", "parserel", "cmdparse"); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@Override |   @Override | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 	{ |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 		switch (alias.toLowerCase()) |       @NotNull @Unmodifiable final List<String> params) { | ||||||
| 		{ |     switch (alias.toLowerCase()) { | ||||||
| 			case "parserel": |       case "parserel": | ||||||
| 				evaluateParseRelation(sender, params); |         evaluateParseRelation(sender, params); | ||||||
| 				break; |         break; | ||||||
| 			case "parse": |       case "parse": | ||||||
| 				evaluateParseSingular(sender, params, false, false); |         evaluateParseSingular(sender, params, false, false); | ||||||
| 				break; |         break; | ||||||
| 			case "bcparse": |       case "bcparse": | ||||||
| 				evaluateParseSingular(sender, params, true, false); |         evaluateParseSingular(sender, params, true, false); | ||||||
| 				break; |         break; | ||||||
| 			case "cmdparse": |       case "cmdparse": | ||||||
| 				evaluateParseSingular(sender, params, false, true); |         evaluateParseSingular(sender, params, false, true); | ||||||
| 				break; |         break; | ||||||
| 		} |     } | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	@Override |   @Override | ||||||
| 	public void complete(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) |   public void complete(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 	{ |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 		switch (alias.toLowerCase()) |       @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) { | ||||||
| 		{ |     switch (alias.toLowerCase()) { | ||||||
| 			case "parserel": |       case "parserel": | ||||||
| 				completeParseRelation(params, suggestions); |         completeParseRelation(params, suggestions); | ||||||
| 				break; |         break; | ||||||
| 			case "parse": |       case "parse": | ||||||
| 			case "bcparse": |       case "bcparse": | ||||||
| 			case "cmdparse": |       case "cmdparse": | ||||||
| 				completeParseSingular(sender, params, suggestions); |         completeParseSingular(sender, params, suggestions); | ||||||
| 				break; |         break; | ||||||
| 		} |     } | ||||||
| 	} |   } | ||||||
|  |  | ||||||
|  |  | ||||||
| 	private void evaluateParseSingular(@NotNull final CommandSender sender, @NotNull @Unmodifiable final List<String> params, final boolean broadcast, final boolean command) |   private void evaluateParseSingular(@NotNull final CommandSender sender, | ||||||
| 	{ |       @NotNull @Unmodifiable final List<String> params, final boolean broadcast, | ||||||
| 		if (params.size() < 2) |       final boolean command) { | ||||||
| 		{ |     if (params.size() < 2) { | ||||||
| 			Msg.msg(sender, "&cYou must supply a target, and a message: &b/papi " + (broadcast ? "bcparse" : "parse") + " &7{target} &a{message}"); |       Msg.msg(sender, | ||||||
| 			return; |           "&cYou must supply a target, and a message: &b/papi " + (broadcast ? "bcparse" : "parse") | ||||||
| 		} |               + " &7{target} &a{message}"); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		@NotNull final OfflinePlayer player; |     @NotNull final OfflinePlayer player; | ||||||
|  |  | ||||||
| 		if ("me".equalsIgnoreCase(params.get(0))) |     if ("me".equalsIgnoreCase(params.get(0))) { | ||||||
| 		{ |       if (!(sender instanceof Player)) { | ||||||
| 			if (!(sender instanceof Player)) |         Msg.msg(sender, "&cYou must be a player to use &7me&c as a target!"); | ||||||
| 			{ |         return; | ||||||
| 				Msg.msg(sender, "&cYou must be a player to use &7me&c as a target!"); |       } | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			player = ((Player) sender); |       player = ((Player) sender); | ||||||
| 		} |     } else { | ||||||
| 		else |       final OfflinePlayer target = resolvePlayer(params.get(0)); | ||||||
| 		{ |       if (target == null) { | ||||||
| 			final OfflinePlayer target = resolvePlayer(params.get(0)); |         Msg.msg(sender, "&cFailed to find player: &7" + params.get(0)); | ||||||
| 			if (target == null) |         return; | ||||||
| 			{ |       } | ||||||
| 				Msg.msg(sender, "&cFailed to find player: &7" + params.get(0)); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			player = target; |       player = target; | ||||||
| 		} |     } | ||||||
|  |  | ||||||
| 		final String message = PlaceholderAPI.setPlaceholders(player, String.join(" ", params.subList(1, params.size()))); |     final String message = PlaceholderAPI | ||||||
|  |         .setPlaceholders(player, String.join(" ", params.subList(1, params.size()))); | ||||||
|  |  | ||||||
| 		if (command) |     if (command) { | ||||||
| 		{ |       Bukkit.dispatchCommand(sender, message); | ||||||
| 			Bukkit.dispatchCommand(sender, message); |       return; | ||||||
| 			return; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (broadcast) |     if (broadcast) { | ||||||
| 		{ |       Msg.broadcast(message); | ||||||
| 			Msg.broadcast(message); |     } else { | ||||||
| 		} |       if (!(sender instanceof Player)) { | ||||||
| 		else |         Msg.msg(sender, message); | ||||||
| 		{ |       } else { | ||||||
| 			if (!(sender instanceof Player)) |         ((Player) sender).spigot().sendMessage(TextComponent.fromLegacyText(message)); | ||||||
| 			{ |       } | ||||||
| 				Msg.msg(sender, message); |     } | ||||||
| 			} |   } | ||||||
| 			else |  | ||||||
| 			{ |  | ||||||
| 				((Player) sender).spigot().sendMessage(TextComponent.fromLegacyText(message)); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	private void evaluateParseRelation(@NotNull final CommandSender sender, @NotNull @Unmodifiable final List<String> params) |   private void evaluateParseRelation(@NotNull final CommandSender sender, | ||||||
| 	{ |       @NotNull @Unmodifiable final List<String> params) { | ||||||
| 		if (params.size() < 3) |     if (params.size() < 3) { | ||||||
| 		{ |       Msg.msg(sender, | ||||||
| 			Msg.msg(sender, "&cYou must supply two targets, and a message: &b/papi parserel &7{target one} {target two} &a{message}"); |           "&cYou must supply two targets, and a message: &b/papi parserel &7{target one} {target two} &a{message}"); | ||||||
| 			return; |       return; | ||||||
| 		} |     } | ||||||
|  |  | ||||||
| 		final OfflinePlayer targetOne = resolvePlayer(params.get(0)); |     final OfflinePlayer targetOne = resolvePlayer(params.get(0)); | ||||||
| 		if (targetOne == null || !targetOne.isOnline()) |     if (targetOne == null || !targetOne.isOnline()) { | ||||||
| 		{ |       Msg.msg(sender, "&cFailed to find player: &f" + params.get(0)); | ||||||
| 			Msg.msg(sender, "&cFailed to find player: &f" + params.get(0)); |       return; | ||||||
| 			return; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final OfflinePlayer targetTwo = resolvePlayer(params.get(1)); |     final OfflinePlayer targetTwo = resolvePlayer(params.get(1)); | ||||||
| 		if (targetTwo == null || !targetTwo.isOnline()) |     if (targetTwo == null || !targetTwo.isOnline()) { | ||||||
| 		{ |       Msg.msg(sender, "&cFailed to find player: &f" + params.get(1)); | ||||||
| 			Msg.msg(sender, "&cFailed to find player: &f" + params.get(1)); |       return; | ||||||
| 			return; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final String message = PlaceholderAPI.setRelationalPlaceholders(((Player) targetOne), ((Player) targetTwo), String.join(" ", params.subList(2, params.size()))); |     final String message = PlaceholderAPI | ||||||
| 		Msg.msg(sender, message); |         .setRelationalPlaceholders(((Player) targetOne), ((Player) targetTwo), | ||||||
| 	} |             String.join(" ", params.subList(2, params.size()))); | ||||||
|  |     Msg.msg(sender, message); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
| 	private void completeParseSingular(@NotNull final CommandSender sender, @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) |   private void completeParseSingular(@NotNull final CommandSender sender, | ||||||
| 	{ |       @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) { | ||||||
| 		if (params.size() <= 1) |     if (params.size() <= 1) { | ||||||
| 		{ |       if (sender instanceof Player && (params.isEmpty() || "me" | ||||||
| 			if (sender instanceof Player && (params.isEmpty() || "me".startsWith(params.get(0).toLowerCase()))) |           .startsWith(params.get(0).toLowerCase()))) { | ||||||
| 			{ |         suggestions.add("me"); | ||||||
| 				suggestions.add("me"); |       } | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			final Stream<String> names = Bukkit.getOnlinePlayers().stream().map(Player::getName); |       final Stream<String> names = Bukkit.getOnlinePlayers().stream().map(Player::getName); | ||||||
| 			suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); |       suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); | ||||||
|  |  | ||||||
| 			return; |       return; | ||||||
| 		} |     } | ||||||
|  |  | ||||||
| 		final String name = params.get(params.size() - 1); |     final String name = params.get(params.size() - 1); | ||||||
| 		if (!name.startsWith("%") || name.endsWith("%")) |     if (!name.startsWith("%") || name.endsWith("%")) { | ||||||
| 		{ |       return; | ||||||
| 			return; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final int index = name.indexOf('_'); |     final int index = name.indexOf('_'); | ||||||
| 		if (index == -1) |     if (index == -1) { | ||||||
| 		{ |       return; // no arguments supplied yet | ||||||
| 			return; // no arguments supplied yet |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final PlaceholderExpansion expansion = PlaceholderAPIPlugin.getInstance().getLocalExpansionManager().findExpansionByIdentifier(name.substring(1, index)).orElse(null); |     final PlaceholderExpansion expansion = PlaceholderAPIPlugin.getInstance() | ||||||
| 		if (expansion == null) |         .getLocalExpansionManager().findExpansionByIdentifier(name.substring(1, index)) | ||||||
| 		{ |         .orElse(null); | ||||||
| 			return; |     if (expansion == null) { | ||||||
| 		} |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		final Set<String> possible = new HashSet<>(expansion.getPlaceholders()); |     final Set<String> possible = new HashSet<>(expansion.getPlaceholders()); | ||||||
|  |  | ||||||
| 		PlaceholderAPIPlugin.getInstance() |     PlaceholderAPIPlugin.getInstance() | ||||||
| 							.getCloudExpansionManager() |         .getCloudExpansionManager() | ||||||
| 							.findCloudExpansionByName(expansion.getName()) |         .findCloudExpansionByName(expansion.getName()) | ||||||
| 							.ifPresent(cloud -> possible.addAll(cloud.getPlaceholders())); |         .ifPresent(cloud -> possible.addAll(cloud.getPlaceholders())); | ||||||
|  |  | ||||||
| 		suggestByParameter(possible.stream(), suggestions, params.get(params.size() - 1)); |     suggestByParameter(possible.stream(), suggestions, params.get(params.size() - 1)); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	private void completeParseRelation(@NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) |   private void completeParseRelation(@NotNull @Unmodifiable final List<String> params, | ||||||
| 	{ |       @NotNull final List<String> suggestions) { | ||||||
| 		if (params.size() > 2) |     if (params.size() > 2) { | ||||||
| 		{ |       return; | ||||||
| 			return; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final Stream<String> names = Bukkit.getOnlinePlayers().stream().map(Player::getName); |     final Stream<String> names = Bukkit.getOnlinePlayers().stream().map(Player::getName); | ||||||
| 		suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(params.size() - 1)); |     suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(params.size() - 1)); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@Nullable |   @Nullable | ||||||
| 	private OfflinePlayer resolvePlayer(@NotNull final String name) |   private OfflinePlayer resolvePlayer(@NotNull final String name) { | ||||||
| 	{ |     OfflinePlayer target = Bukkit.getPlayer(name); | ||||||
| 		OfflinePlayer target = Bukkit.getPlayer(name); |  | ||||||
|  |  | ||||||
| 		if (target == null) |     if (target == null) { | ||||||
| 		{ |       target = Bukkit.getOfflinePlayer(name); // this is probably not a great idea. | ||||||
| 			target = Bukkit.getOfflinePlayer(name); // this is probably not a great idea. |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return target.hasPlayedBefore() ? target : null; |     return target.hasPlayedBefore() ? target : null; | ||||||
|  |  | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,26 +20,24 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.commands.impl.local; | package me.clip.placeholderapi.commands.impl.local; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.List; | public final class CommandReload extends PlaceholderCommand { | ||||||
|  |  | ||||||
| public final class CommandReload extends PlaceholderCommand |   public CommandReload() { | ||||||
| { |     super("reload"); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	public CommandReload() |   @Override | ||||||
| 	{ |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 		super("reload"); |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 	} |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|  |     plugin.reloadConf(sender); | ||||||
| 	@Override |   } | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |  | ||||||
| 	{ |  | ||||||
| 		plugin.reloadConf(sender); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.commands.impl.local; | package me.clip.placeholderapi.commands.impl.local; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import me.clip.placeholderapi.util.Msg; | import me.clip.placeholderapi.util.Msg; | ||||||
| @@ -28,27 +29,24 @@ import org.bukkit.plugin.PluginDescriptionFile; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.List; | public final class CommandVersion extends PlaceholderCommand { | ||||||
|  |  | ||||||
| public final class CommandVersion extends PlaceholderCommand |   public CommandVersion() { | ||||||
| { |     super("version"); | ||||||
|  |   } | ||||||
| 	public CommandVersion() |  | ||||||
| 	{ |  | ||||||
| 		super("version"); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@Override |   @Override | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |   public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, | ||||||
| 	{ |       @NotNull final CommandSender sender, @NotNull final String alias, | ||||||
| 		final PluginDescriptionFile description = plugin.getDescription(); |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|  |     final PluginDescriptionFile description = plugin.getDescription(); | ||||||
|  |  | ||||||
| 		Msg.msg(sender, |     Msg.msg(sender, | ||||||
| 				"&b&lPlaceholderAPI &7(&f" + description.getVersion() + "&7)", |         "&b&lPlaceholderAPI &7(&f" + description.getVersion() + "&7)", | ||||||
| 				"&7Author: &f" + description.getAuthors(), |         "&7Author: &f" + description.getAuthors(), | ||||||
| 				"&7PAPI Commands: &b/papi &fhelp", |         "&7PAPI Commands: &b/papi &fhelp", | ||||||
| 				"&7eCloud Commands&8: &b/papi &fecloud"); |         "&7eCloud Commands&8: &b/papi &fecloud"); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,32 +20,28 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.configuration; | package me.clip.placeholderapi.configuration; | ||||||
|  |  | ||||||
|  | import java.util.Comparator; | ||||||
| import me.clip.placeholderapi.expansion.cloud.CloudExpansion; | import me.clip.placeholderapi.expansion.cloud.CloudExpansion; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
| import java.util.Comparator; | public enum ExpansionSort implements Comparator<CloudExpansion> { | ||||||
|  |  | ||||||
| public enum ExpansionSort implements Comparator<CloudExpansion> |   NAME(Comparator.comparing(CloudExpansion::getName)), | ||||||
| { |   AUTHOR(Comparator.comparing(CloudExpansion::getAuthor)), | ||||||
|  |   LATEST(Comparator.comparing(CloudExpansion::getLastUpdate).reversed()); | ||||||
| 	NAME(Comparator.comparing(CloudExpansion::getName)), |  | ||||||
| 	AUTHOR(Comparator.comparing(CloudExpansion::getAuthor)), |  | ||||||
| 	LATEST(Comparator.comparing(CloudExpansion::getLastUpdate).reversed()); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private final Comparator<CloudExpansion> comparator; |   private final Comparator<CloudExpansion> comparator; | ||||||
|  |  | ||||||
| 	ExpansionSort(@NotNull final Comparator<CloudExpansion> comparator) |   ExpansionSort(@NotNull final Comparator<CloudExpansion> comparator) { | ||||||
| 	{ |     this.comparator = comparator; | ||||||
| 		this.comparator = comparator; |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@Override |   @Override | ||||||
| 	public final int compare(final CloudExpansion expansion1, final CloudExpansion expansion2) |   public final int compare(final CloudExpansion expansion1, final CloudExpansion expansion2) { | ||||||
| 	{ |     return comparator.compare(expansion1, expansion2); | ||||||
| 		return comparator.compare(expansion1, expansion2); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,88 +20,74 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.configuration; | package me.clip.placeholderapi.configuration; | ||||||
|  |  | ||||||
|  | import java.util.Optional; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
| import java.util.Optional; | public final class PlaceholderAPIConfig { | ||||||
|  |  | ||||||
| public final class PlaceholderAPIConfig |   @NotNull | ||||||
| { |   private final PlaceholderAPIPlugin plugin; | ||||||
|  |  | ||||||
| 	@NotNull |   public PlaceholderAPIConfig(@NotNull final PlaceholderAPIPlugin plugin) { | ||||||
| 	private final PlaceholderAPIPlugin plugin; |     this.plugin = plugin; | ||||||
|  |   } | ||||||
| 	public PlaceholderAPIConfig(@NotNull final PlaceholderAPIPlugin plugin) |  | ||||||
| 	{ |  | ||||||
| 		this.plugin = plugin; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public boolean checkUpdates() |   public boolean checkUpdates() { | ||||||
| 	{ |     return plugin.getConfig().getBoolean("check_updates"); | ||||||
| 		return plugin.getConfig().getBoolean("check_updates"); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public boolean cloudAllowUnverifiedExpansions() |   public boolean cloudAllowUnverifiedExpansions() { | ||||||
| 	{ |     return plugin.getConfig().getBoolean("cloud_allow_unverified_expansions"); | ||||||
| 		return plugin.getConfig().getBoolean("cloud_allow_unverified_expansions"); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public boolean isCloudEnabled() |   public boolean isCloudEnabled() { | ||||||
| 	{ |     return plugin.getConfig().getBoolean("cloud_enabled"); | ||||||
| 		return plugin.getConfig().getBoolean("cloud_enabled"); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public void setCloudEnabled(boolean state) |   public void setCloudEnabled(boolean state) { | ||||||
| 	{ |     plugin.getConfig().set("cloud_enabled", state); | ||||||
| 		plugin.getConfig().set("cloud_enabled", state); |     plugin.saveConfig(); | ||||||
| 		plugin.saveConfig(); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public boolean isDebugMode() |   public boolean isDebugMode() { | ||||||
| 	{ |     return plugin.getConfig().getBoolean("debug", false); | ||||||
| 		return plugin.getConfig().getBoolean("debug", false); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public Optional<ExpansionSort> getExpansionSort() |   public Optional<ExpansionSort> getExpansionSort() { | ||||||
| 	{ |     final String option = plugin.getConfig() | ||||||
| 		final String option = plugin.getConfig().getString("cloud_sorting", ExpansionSort.LATEST.name()); |         .getString("cloud_sorting", ExpansionSort.LATEST.name()); | ||||||
|  |  | ||||||
| 		try |     try { | ||||||
| 		{ |       //noinspection ConstantConditions (bad spigot annotation) | ||||||
| 			//noinspection ConstantConditions (bad spigot annotation) |       return Optional.of(ExpansionSort.valueOf(option.toUpperCase())); | ||||||
| 			return Optional.of(ExpansionSort.valueOf(option.toUpperCase())); |     } catch (final IllegalArgumentException ignored) { | ||||||
| 		} |       return Optional.empty(); | ||||||
| 		catch (final IllegalArgumentException ignored) |     } | ||||||
| 		{ |   } | ||||||
| 			return Optional.empty(); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	public String dateFormat() |   public String dateFormat() { | ||||||
| 	{ |     //noinspection ConstantConditions (bad spigot annotation) | ||||||
| 		//noinspection ConstantConditions (bad spigot annotation) |     return plugin.getConfig().getString("date_format", "MM/dd/yy HH:mm:ss"); | ||||||
| 		return plugin.getConfig().getString("date_format", "MM/dd/yy HH:mm:ss"); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	public String booleanTrue() |   public String booleanTrue() { | ||||||
| 	{ |     //noinspection ConstantConditions (bad spigot annotation) | ||||||
| 		//noinspection ConstantConditions (bad spigot annotation) |     return plugin.getConfig().getString("boolean.true", "true"); | ||||||
| 		return plugin.getConfig().getString("boolean.true", "true"); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	public String booleanFalse() |   public String booleanFalse() { | ||||||
| 	{ |     //noinspection ConstantConditions (bad spigot annotation) | ||||||
| 		//noinspection ConstantConditions (bad spigot annotation) |     return plugin.getConfig().getString("boolean.false", "false"); | ||||||
| 		return plugin.getConfig().getString("boolean.false", "false"); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -26,55 +26,42 @@ import org.bukkit.event.Event; | |||||||
| import org.bukkit.event.HandlerList; | import org.bukkit.event.HandlerList; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
| public final class ExpansionRegisterEvent extends Event implements Cancellable | public final class ExpansionRegisterEvent extends Event implements Cancellable { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private static final HandlerList HANDLERS = new HandlerList(); |   private static final HandlerList HANDLERS = new HandlerList(); | ||||||
|  |   @NotNull | ||||||
|  |   private final PlaceholderExpansion expansion; | ||||||
|  |   private boolean cancelled; | ||||||
|  |  | ||||||
|  |   public ExpansionRegisterEvent(@NotNull final PlaceholderExpansion expansion) { | ||||||
|  |     this.expansion = expansion; | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	private       boolean              cancelled; |   @NotNull | ||||||
| 	@NotNull |   public static HandlerList getHandlerList() { | ||||||
| 	private final PlaceholderExpansion expansion; |     return HANDLERS; | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	public ExpansionRegisterEvent(@NotNull final PlaceholderExpansion expansion) |   @NotNull | ||||||
| 	{ |   public PlaceholderExpansion getExpansion() { | ||||||
| 		this.expansion = expansion; |     return expansion; | ||||||
| 	} |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public boolean isCancelled() { | ||||||
|  |     return cancelled; | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	@NotNull |   @Override | ||||||
| 	public PlaceholderExpansion getExpansion() |   public void setCancelled(boolean cancelled) { | ||||||
| 	{ |     this.cancelled = cancelled; | ||||||
| 		return expansion; |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
| 	@Override |   @Override | ||||||
| 	public boolean isCancelled() |   public HandlerList getHandlers() { | ||||||
| 	{ |     return HANDLERS; | ||||||
| 		return cancelled; |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Override |  | ||||||
| 	public void setCancelled(boolean cancelled) |  | ||||||
| 	{ |  | ||||||
| 		this.cancelled = cancelled; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	@Override |  | ||||||
| 	public HandlerList getHandlers() |  | ||||||
| 	{ |  | ||||||
| 		return HANDLERS; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public static HandlerList getHandlerList() |  | ||||||
| 	{ |  | ||||||
| 		return HANDLERS; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -25,41 +25,33 @@ import org.bukkit.event.Event; | |||||||
| import org.bukkit.event.HandlerList; | import org.bukkit.event.HandlerList; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
| public final class ExpansionUnregisterEvent extends Event | public final class ExpansionUnregisterEvent extends Event { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private static final HandlerList HANDLERS = new HandlerList(); |   private static final HandlerList HANDLERS = new HandlerList(); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private final PlaceholderExpansion expansion; |   private final PlaceholderExpansion expansion; | ||||||
|  |  | ||||||
| 	public ExpansionUnregisterEvent(@NotNull final PlaceholderExpansion expansion) |   public ExpansionUnregisterEvent(@NotNull final PlaceholderExpansion expansion) { | ||||||
| 	{ |     this.expansion = expansion; | ||||||
| 		this.expansion = expansion; |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
|  |   public static HandlerList getHandlerList() { | ||||||
|  |     return HANDLERS; | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	public PlaceholderExpansion getExpansion() |   public PlaceholderExpansion getExpansion() { | ||||||
| 	{ |     return expansion; | ||||||
| 		return expansion; |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
| 	@NotNull |   @Override | ||||||
| 	@Override |   public HandlerList getHandlers() { | ||||||
| 	public HandlerList getHandlers() |     return HANDLERS; | ||||||
| 	{ |   } | ||||||
| 		return HANDLERS; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public static HandlerList getHandlerList() |  | ||||||
| 	{ |  | ||||||
| 		return HANDLERS; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -29,49 +29,42 @@ import org.jetbrains.annotations.NotNull; | |||||||
|  * @deprecated This event is no longer used. |  * @deprecated This event is no longer used. | ||||||
|  */ |  */ | ||||||
| @Deprecated | @Deprecated | ||||||
| public final class PlaceholderHookUnloadEvent extends Event | public final class PlaceholderHookUnloadEvent extends Event { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private static final HandlerList HANDLERS = new HandlerList(); |   private static final HandlerList HANDLERS = new HandlerList(); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private final String          plugin; |   private final String plugin; | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private final PlaceholderHook placeholderHook; |   private final PlaceholderHook placeholderHook; | ||||||
|  |  | ||||||
| 	public PlaceholderHookUnloadEvent(@NotNull final String plugin, @NotNull final PlaceholderHook placeholderHook) |   public PlaceholderHookUnloadEvent(@NotNull final String plugin, | ||||||
| 	{ |       @NotNull final PlaceholderHook placeholderHook) { | ||||||
| 		this.plugin          = plugin; |     this.plugin = plugin; | ||||||
| 		this.placeholderHook = placeholderHook; |     this.placeholderHook = placeholderHook; | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	public String getHookName() |   public static HandlerList getHandlerList() { | ||||||
| 	{ |     return HANDLERS; | ||||||
| 		return plugin; |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	public PlaceholderHook getHook() |   public String getHookName() { | ||||||
| 	{ |     return plugin; | ||||||
| 		return placeholderHook; |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
|  |   public PlaceholderHook getHook() { | ||||||
|  |     return placeholderHook; | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	@Override |   @Override | ||||||
| 	public HandlerList getHandlers() |   public HandlerList getHandlers() { | ||||||
| 	{ |     return HANDLERS; | ||||||
| 		return HANDLERS; |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public static HandlerList getHandlerList() |  | ||||||
| 	{ |  | ||||||
| 		return HANDLERS; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,8 +21,9 @@ | |||||||
| package me.clip.placeholderapi.exceptions; | package me.clip.placeholderapi.exceptions; | ||||||
|  |  | ||||||
| public final class NoDefaultCommandException extends RuntimeException { | public final class NoDefaultCommandException extends RuntimeException { | ||||||
|     public NoDefaultCommandException(final String message) { |  | ||||||
|         super(message); |   public NoDefaultCommandException(final String message) { | ||||||
|     } |     super(message); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -29,8 +29,8 @@ package me.clip.placeholderapi.expansion; | |||||||
|  */ |  */ | ||||||
| public interface Cacheable { | public interface Cacheable { | ||||||
|  |  | ||||||
|     /** |   /** | ||||||
|      * Called when the implementing class is unregistered from PlaceholderAPI |    * Called when the implementing class is unregistered from PlaceholderAPI | ||||||
|      */ |    */ | ||||||
|     void clear(); |   void clear(); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -31,10 +31,10 @@ import org.bukkit.entity.Player; | |||||||
|  */ |  */ | ||||||
| public interface Cleanable { | public interface Cleanable { | ||||||
|  |  | ||||||
|     /** |   /** | ||||||
|      * Called when a player leaves the server |    * Called when a player leaves the server | ||||||
|      * |    * | ||||||
|      * @param p (@link Player} who left the server |    * @param p (@link Player} who left the server | ||||||
|      */ |    */ | ||||||
|     void cleanup(Player p); |   void cleanup(Player p); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -30,14 +30,14 @@ import java.util.Map; | |||||||
|  */ |  */ | ||||||
| public interface Configurable { | public interface Configurable { | ||||||
|  |  | ||||||
|     /** |   /** | ||||||
|      * This method will be called before the implementing class is registered to obtain a map of |    * This method will be called before the implementing class is registered to obtain a map of | ||||||
|      * configuration options that the implementing class needs These paths and values will be added to |    * configuration options that the implementing class needs These paths and values will be added to | ||||||
|      * the PlaceholderAPI config.yml in the configuration section expansions.(placeholder |    * the PlaceholderAPI config.yml in the configuration section expansions.(placeholder | ||||||
|      * identifier).(your key): (your value) |    * identifier).(your key): (your value) | ||||||
|      * |    * | ||||||
|      * @return Map of config path / values which need to be added / removed from the PlaceholderAPI |    * @return Map of config path / values which need to be added / removed from the PlaceholderAPI | ||||||
|      * config.yml file |    * config.yml file | ||||||
|      */ |    */ | ||||||
|     Map<String, Object> getDefaults(); |   Map<String, Object> getDefaults(); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -41,24 +41,24 @@ public enum NMSVersion { | |||||||
|   SPIGOT_1_15_R1("v1_15_R1"), |   SPIGOT_1_15_R1("v1_15_R1"), | ||||||
|   SPIGOT_1_16_R1("v1_16_R1"); |   SPIGOT_1_16_R1("v1_16_R1"); | ||||||
|  |  | ||||||
|     private final String version; |   private final String version; | ||||||
|  |  | ||||||
|     NMSVersion(String version) { |   NMSVersion(String version) { | ||||||
|         this.version = version; |     this.version = version; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public static NMSVersion getVersion(String version) { | ||||||
|  |     for (NMSVersion v : values()) { | ||||||
|  |       if (v.getVersion().equalsIgnoreCase(version)) { | ||||||
|  |         return v; | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static NMSVersion getVersion(String version) { |     return NMSVersion.UNKNOWN; | ||||||
|         for (NMSVersion v : values()) { |   } | ||||||
|             if (v.getVersion().equalsIgnoreCase(version)) { |  | ||||||
|                 return v; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return NMSVersion.UNKNOWN; |   public String getVersion() { | ||||||
|     } |     return version; | ||||||
|  |   } | ||||||
|     public String getVersion() { |  | ||||||
|         return version; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,280 +20,240 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.expansion; | package me.clip.placeholderapi.expansion; | ||||||
|  |  | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Objects; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.PlaceholderHook; | import me.clip.placeholderapi.PlaceholderHook; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.OfflinePlayer; |  | ||||||
| import org.bukkit.configuration.ConfigurationSection; | import org.bukkit.configuration.ConfigurationSection; | ||||||
| import org.jetbrains.annotations.ApiStatus; | import org.jetbrains.annotations.ApiStatus; | ||||||
| import org.jetbrains.annotations.Contract; | import org.jetbrains.annotations.Contract; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
| import java.util.Collections; | public abstract class PlaceholderExpansion extends PlaceholderHook { | ||||||
| import java.util.List; |  | ||||||
| import java.util.Objects; |  | ||||||
|  |  | ||||||
| public abstract class PlaceholderExpansion extends PlaceholderHook |   /** | ||||||
| { |    * The placeholder identifier of this expansion | ||||||
|  |    * | ||||||
|  |    * @return placeholder identifier that is associated with this expansion | ||||||
|  |    */ | ||||||
|  |   @NotNull | ||||||
|  |   public abstract String getIdentifier(); | ||||||
|  |  | ||||||
| 	/** |   /** | ||||||
| 	 * The placeholder identifier of this expansion |    * The author of this expansion | ||||||
| 	 * |    * | ||||||
| 	 * @return placeholder identifier that is associated with this expansion |    * @return name of the author for this expansion | ||||||
| 	 */ |    */ | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	public abstract String getIdentifier(); |   public abstract String getAuthor(); | ||||||
|  |  | ||||||
| 	/** |   /** | ||||||
| 	 * The author of this expansion |    * The version of this expansion | ||||||
| 	 * |    * | ||||||
| 	 * @return name of the author for this expansion |    * @return current version of this expansion | ||||||
| 	 */ |    */ | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	public abstract String getAuthor(); |   public abstract String getVersion(); | ||||||
|  |  | ||||||
| 	/** |   /** | ||||||
| 	 * The version of this expansion |    * The name of this expansion | ||||||
| 	 * |    * | ||||||
| 	 * @return current version of this expansion |    * @return {@link #getIdentifier()} by default, name of this expansion if specified | ||||||
| 	 */ |    */ | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	public abstract String getVersion(); |   public String getName() { | ||||||
|  |     return getIdentifier(); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	@Nullable |   /** | ||||||
| 	@Override /* override for now >:) */ |    * The name of the plugin that this expansion hooks into. by default will null | ||||||
| 	public String onRequest(@Nullable final OfflinePlayer player, @NotNull final String params) |    * | ||||||
| 	{ |    * @return plugin name that this expansion requires to function | ||||||
| 		return super.onRequest(player, params); |    */ | ||||||
| 	} |   @Nullable | ||||||
|  |   public String getRequiredPlugin() { | ||||||
|  |     return getPlugin(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * The placeholders associated with this expansion | ||||||
|  |    * | ||||||
|  |    * @return placeholder list that this expansion provides | ||||||
|  |    */ | ||||||
|  |   @NotNull | ||||||
|  |   public List<String> getPlaceholders() { | ||||||
|  |     return Collections.emptyList(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** |   /** | ||||||
| 	 * The name of this expansion |    * Expansions that do not use the ecloud and instead register from the dependency should set this | ||||||
| 	 * |    * to true to ensure that your placeholder expansion is not unregistered when the papi reload | ||||||
| 	 * @return {@link #getIdentifier()} by default, name of this expansion if specified |    * command is used | ||||||
| 	 */ |    * | ||||||
| 	@NotNull |    * @return if this expansion should persist through placeholder reloads | ||||||
| 	public String getName() |    */ | ||||||
| 	{ |   public boolean persist() { | ||||||
| 		return getIdentifier(); |     return false; | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * The name of the plugin that this expansion hooks into. by default will null |  | ||||||
| 	 * |  | ||||||
| 	 * @return plugin name that this expansion requires to function |  | ||||||
| 	 */ |  | ||||||
| 	@Nullable |  | ||||||
| 	public String getRequiredPlugin() |  | ||||||
| 	{ |  | ||||||
| 		return getPlugin(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * The placeholders associated with this expansion |  | ||||||
| 	 * |  | ||||||
| 	 * @return placeholder list that this expansion provides |  | ||||||
| 	 */ |  | ||||||
| 	@NotNull |  | ||||||
| 	public List<String> getPlaceholders() |  | ||||||
| 	{ |  | ||||||
| 		return Collections.emptyList(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** |   /** | ||||||
| 	 * Expansions that do not use the ecloud and instead register from the dependency should set this |    * Check if this placeholder identifier has already been registered | ||||||
| 	 * to true to ensure that your placeholder expansion is not unregistered when the papi reload |    * | ||||||
| 	 * command is used |    * @return true if the identifier for this expansion is already registered | ||||||
| 	 * |    */ | ||||||
| 	 * @return if this expansion should persist through placeholder reloads |   public final boolean isRegistered() { | ||||||
| 	 */ |     return getPlaceholderAPI().getLocalExpansionManager().findExpansionByIdentifier(getIdentifier()) | ||||||
| 	public boolean persist() |         .map(it -> it.equals(this)).orElse(false); | ||||||
| 	{ |   } | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** |   /** | ||||||
| 	 * Check if this placeholder identifier has already been registered |    * If any requirements need to be checked before this expansion should register, you can check | ||||||
| 	 * |    * them here | ||||||
| 	 * @return true if the identifier for this expansion is already registered |    * | ||||||
| 	 */ |    * @return true if this hook meets all the requirements to register | ||||||
| 	public final boolean isRegistered() |    */ | ||||||
| 	{ |   public boolean canRegister() { | ||||||
| 		return getPlaceholderAPI().getLocalExpansionManager().findExpansionByIdentifier(getIdentifier()).map(it -> it.equals(this)).orElse(false); |     return getRequiredPlugin() == null | ||||||
| 	} |         || Bukkit.getPluginManager().getPlugin(getRequiredPlugin()) != null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Attempt to register this PlaceholderExpansion | ||||||
|  |    * | ||||||
|  |    * @return true if this expansion is now registered with PlaceholderAPI | ||||||
|  |    */ | ||||||
|  |   public boolean register() { | ||||||
|  |     return getPlaceholderAPI().getLocalExpansionManager().register(this); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Attempt to unregister this PlaceholderExpansion | ||||||
|  |    * | ||||||
|  |    * @return true if this expansion is now unregistered with PlaceholderAPI | ||||||
|  |    */ | ||||||
|  |   public final boolean unregister() { | ||||||
|  |     return getPlaceholderAPI().getLocalExpansionManager().unregister(this); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** |   /** | ||||||
| 	 * If any requirements need to be checked before this expansion should register, you can check |    * Quick getter for the {@link PlaceholderAPIPlugin} instance | ||||||
| 	 * them here |    * | ||||||
| 	 * |    * @return {@link PlaceholderAPIPlugin} instance | ||||||
| 	 * @return true if this hook meets all the requirements to register |    */ | ||||||
| 	 */ |   @NotNull | ||||||
| 	public boolean canRegister() |   public final PlaceholderAPIPlugin getPlaceholderAPI() { | ||||||
| 	{ |     return PlaceholderAPIPlugin.getInstance(); | ||||||
| 		return getRequiredPlugin() == null || Bukkit.getPluginManager().getPlugin(getRequiredPlugin()) != null; |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** |   // === Configuration === | ||||||
| 	 * Attempt to register this PlaceholderExpansion |  | ||||||
| 	 * |  | ||||||
| 	 * @return true if this expansion is now registered with PlaceholderAPI |  | ||||||
| 	 */ |  | ||||||
| 	public boolean register() |  | ||||||
| 	{ |  | ||||||
| 		return canRegister() && getPlaceholderAPI().getLocalExpansionManager().register(this); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** |   @Nullable | ||||||
| 	 * Attempt to unregister this PlaceholderExpansion |   public final ConfigurationSection getConfigSection() { | ||||||
| 	 * |     return getPlaceholderAPI().getConfig().getConfigurationSection("expansions." + getIdentifier()); | ||||||
| 	 * @return true if this expansion is now unregistered with PlaceholderAPI |   } | ||||||
| 	 */ |  | ||||||
| 	public final boolean unregister() |  | ||||||
| 	{ |  | ||||||
| 		return getPlaceholderAPI().getLocalExpansionManager().unregister(this); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   @Nullable | ||||||
|  |   public final ConfigurationSection getConfigSection(@NotNull final String path) { | ||||||
|  |     final ConfigurationSection section = getConfigSection(); | ||||||
|  |     return section == null ? null : section.getConfigurationSection(path); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	/** |   @Nullable | ||||||
| 	 * Quick getter for the {@link PlaceholderAPIPlugin} instance |   @Contract("_, !null -> !null") | ||||||
| 	 * |   public final Object get(@NotNull final String path, final Object def) { | ||||||
| 	 * @return {@link PlaceholderAPIPlugin} instance |     final ConfigurationSection section = getConfigSection(); | ||||||
| 	 */ |     return section == null ? def : section.get(path, def); | ||||||
| 	@NotNull |   } | ||||||
| 	public final PlaceholderAPIPlugin getPlaceholderAPI() |  | ||||||
| 	{ |  | ||||||
| 		return PlaceholderAPIPlugin.getInstance(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   public final int getInt(@NotNull final String path, final int def) { | ||||||
|  |     final ConfigurationSection section = getConfigSection(); | ||||||
|  |     return section == null ? def : section.getInt(path, def); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	// === Configuration === |   public final long getLong(@NotNull final String path, final long def) { | ||||||
|  |     final ConfigurationSection section = getConfigSection(); | ||||||
|  |     return section == null ? def : section.getLong(path, def); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	@Nullable |   public final double getDouble(@NotNull final String path, final double def) { | ||||||
| 	public final ConfigurationSection getConfigSection() |     final ConfigurationSection section = getConfigSection(); | ||||||
| 	{ |     return section == null ? def : section.getDouble(path, def); | ||||||
| 		return getPlaceholderAPI().getConfig().getConfigurationSection("expansions." + getIdentifier()); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Nullable |   @Nullable | ||||||
| 	public final ConfigurationSection getConfigSection(@NotNull final String path) |   @Contract("_, !null -> !null") | ||||||
| 	{ |   public final String getString(@NotNull final String path, @Nullable final String def) { | ||||||
| 		final ConfigurationSection section = getConfigSection(); |     final ConfigurationSection section = getConfigSection(); | ||||||
| 		return section == null ? null : section.getConfigurationSection(path); |     return section == null ? def : section.getString(path, def); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	@Nullable |   @NotNull | ||||||
| 	@Contract("_, !null -> !null") |   public final List<String> getStringList(@NotNull final String path) { | ||||||
| 	public final Object get(@NotNull final String path, final Object def) |     final ConfigurationSection section = getConfigSection(); | ||||||
| 	{ |     return section == null ? Collections.emptyList() : section.getStringList(path); | ||||||
| 		final ConfigurationSection section = getConfigSection(); |   } | ||||||
| 		return section == null ? def : section.get(path, def); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public final int getInt(@NotNull final String path, final int def) |   public final boolean configurationContains(@NotNull final String path) { | ||||||
| 	{ |     final ConfigurationSection section = getConfigSection(); | ||||||
| 		final ConfigurationSection section = getConfigSection(); |     return section != null && section.contains(path); | ||||||
| 		return section == null ? def : section.getInt(path, def); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public final long getLong(@NotNull final String path, final long def) |   @Override | ||||||
| 	{ |   public final boolean equals(final Object o) { | ||||||
| 		final ConfigurationSection section = getConfigSection(); |     if (this == o) { | ||||||
| 		return section == null ? def : section.getLong(path, def); |       return true; | ||||||
| 	} |     } | ||||||
|  |     if (!(o instanceof PlaceholderExpansion)) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 	public final double getDouble(@NotNull final String path, final double def) |     final PlaceholderExpansion expansion = (PlaceholderExpansion) o; | ||||||
| 	{ |  | ||||||
| 		final ConfigurationSection section = getConfigSection(); |  | ||||||
| 		return section == null ? def : section.getDouble(path, def); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Nullable |     return getIdentifier().equals(expansion.getIdentifier()) && | ||||||
| 	@Contract("_, !null -> !null") |         getAuthor().equals(expansion.getAuthor()) && | ||||||
| 	public final String getString(@NotNull final String path, @Nullable final String def) |         getVersion().equals(expansion.getVersion()); | ||||||
| 	{ |   } | ||||||
| 		final ConfigurationSection section = getConfigSection(); |  | ||||||
| 		return section == null ? def : section.getString(path, def); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |   @Override | ||||||
| 	public final List<String> getStringList(@NotNull final String path) |   public final String toString() { | ||||||
| 	{ |     return String.format("PlaceholderExpansion[name: '%s', author: '%s', version: '%s']", getName(), | ||||||
| 		final ConfigurationSection section = getConfigSection(); |         getAuthor(), getVersion()); | ||||||
| 		return section == null ? Collections.emptyList() : section.getStringList(path); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public final boolean configurationContains(@NotNull final String path) |   // === Deprecated API === | ||||||
| 	{ |  | ||||||
| 		final ConfigurationSection section = getConfigSection(); |  | ||||||
| 		return section != null && section.contains(path); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Override |   /** | ||||||
| 	public final boolean equals(final Object o) |    * @deprecated As of versions greater than 2.8.7, use {@link #getRequiredPlugin()} | ||||||
| 	{ |    */ | ||||||
| 		if (this == o) |   @Deprecated | ||||||
| 		{ |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
| 			return true; |   public String getPlugin() { | ||||||
| 		} |     return null; | ||||||
| 		if (!(o instanceof PlaceholderExpansion)) |   } | ||||||
| 		{ |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final PlaceholderExpansion expansion = (PlaceholderExpansion) o; |   /** | ||||||
|  |    * @deprecated As of versions greater than 2.8.7, use the expansion cloud to show a description | ||||||
|  |    */ | ||||||
|  |   @Deprecated | ||||||
|  |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
|  |   public String getDescription() { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
| 		return getIdentifier().equals(expansion.getIdentifier()) && |   /** | ||||||
| 			   getAuthor().equals(expansion.getAuthor()) && |    * @deprecated As of versions greater than 2.8.7, use the expansion cloud to display a link | ||||||
| 			   getVersion().equals(expansion.getVersion()); |    */ | ||||||
| 	} |   @Deprecated | ||||||
|  |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
| 	@Override |   public String getLink() { | ||||||
| 	public final int hashCode() |     return null; | ||||||
| 	{ |   } | ||||||
| 		return Objects.hash(getIdentifier(), getAuthor(), getVersion()); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Override |  | ||||||
| 	public final String toString() |  | ||||||
| 	{ |  | ||||||
| 		return String.format("PlaceholderExpansion[name: '%s', author: '%s', version: '%s']", getName(), getAuthor(), getVersion()); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// === Deprecated API === |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * @deprecated As of versions greater than 2.8.7, use {@link #getRequiredPlugin()} |  | ||||||
| 	 */ |  | ||||||
| 	@Deprecated |  | ||||||
| 	@ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |  | ||||||
| 	public String getPlugin() |  | ||||||
| 	{ |  | ||||||
| 		return null; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * @deprecated As of versions greater than 2.8.7, use the expansion cloud to show a description |  | ||||||
| 	 */ |  | ||||||
| 	@Deprecated |  | ||||||
| 	@ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |  | ||||||
| 	public String getDescription() |  | ||||||
| 	{ |  | ||||||
| 		return null; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * @deprecated As of versions greater than 2.8.7, use the expansion cloud to display a link |  | ||||||
| 	 */ |  | ||||||
| 	@Deprecated |  | ||||||
| 	@ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |  | ||||||
| 	public String getLink() |  | ||||||
| 	{ |  | ||||||
| 		return null; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -24,5 +24,5 @@ import org.bukkit.entity.Player; | |||||||
|  |  | ||||||
| public interface Relational { | public interface Relational { | ||||||
|  |  | ||||||
|     String onPlaceholderRequest(Player one, Player two, String identifier); |   String onPlaceholderRequest(Player one, Player two, String identifier); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -23,15 +23,15 @@ package me.clip.placeholderapi.expansion; | |||||||
|  |  | ||||||
| public interface Taskable { | public interface Taskable { | ||||||
|  |  | ||||||
|     /** |   /** | ||||||
|      * Called when the implementing class has successfully been registered to the placeholder map |    * Called when the implementing class has successfully been registered to the placeholder map | ||||||
|      * Tasks that need to be performed when this expansion is registered should go here |    * Tasks that need to be performed when this expansion is registered should go here | ||||||
|      */ |    */ | ||||||
|     void start(); |   void start(); | ||||||
|  |  | ||||||
|     /** |   /** | ||||||
|      * Called when the implementing class has been unregistered from PlaceholderAPI Tasks that need to |    * Called when the implementing class has been unregistered from PlaceholderAPI Tasks that need to | ||||||
|      * be performed when this expansion has unregistered should go here |    * be performed when this expansion has unregistered should go here | ||||||
|      */ |    */ | ||||||
|     void stop(); |   void stop(); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,24 +22,24 @@ package me.clip.placeholderapi.expansion; | |||||||
|  |  | ||||||
| public final class Version { | public final class Version { | ||||||
|  |  | ||||||
|     private final boolean isSpigot; |   private final boolean isSpigot; | ||||||
|     private final String version; |   private final String version; | ||||||
|  |  | ||||||
|     public Version(String version, boolean isSpigot) { |   public Version(String version, boolean isSpigot) { | ||||||
|         this.version = version; |     this.version = version; | ||||||
|         this.isSpigot = isSpigot; |     this.isSpigot = isSpigot; | ||||||
|     } |   } | ||||||
|  |  | ||||||
|     public String getVersion() { |   public String getVersion() { | ||||||
|         return version == null ? "unknown" : version; |     return version == null ? "unknown" : version; | ||||||
|     } |   } | ||||||
|  |  | ||||||
|     public boolean isSpigot() { |   public boolean isSpigot() { | ||||||
|         return isSpigot; |     return isSpigot; | ||||||
|     } |   } | ||||||
|  |  | ||||||
|     public boolean compareTo(String version) { |   public boolean compareTo(String version) { | ||||||
|         return getVersion().equalsIgnoreCase(version); |     return getVersion().equalsIgnoreCase(version); | ||||||
|     } |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -30,11 +30,11 @@ package me.clip.placeholderapi.expansion; | |||||||
|  */ |  */ | ||||||
| public interface VersionSpecific { | public interface VersionSpecific { | ||||||
|  |  | ||||||
|     /** |   /** | ||||||
|      * This method is called before the expansion is attempted to be registered The server version |    * This method is called before the expansion is attempted to be registered The server version | ||||||
|      * will be passed to this method so you know what version the server is currently running. |    * will be passed to this method so you know what version the server is currently running. | ||||||
|      * |    * | ||||||
|      * @return true if your expansion is compatible with the version the server is running. |    * @return true if your expansion is compatible with the version the server is running. | ||||||
|      */ |    */ | ||||||
|     boolean isCompatibleWith(Version v); |   boolean isCompatibleWith(Version v); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,183 +20,183 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.expansion.cloud; | package me.clip.placeholderapi.expansion.cloud; | ||||||
|  |  | ||||||
| import me.clip.placeholderapi.util.TimeUtil; |  | ||||||
|  |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.concurrent.TimeUnit; | import java.util.concurrent.TimeUnit; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
|  | import me.clip.placeholderapi.util.TimeUtil; | ||||||
|  |  | ||||||
|  |  | ||||||
| public class CloudExpansion { | public class CloudExpansion { | ||||||
|  |  | ||||||
|     private String name, |   private String name, | ||||||
|             author, |       author, | ||||||
|             latest_version, |       latest_version, | ||||||
|             description, |       description, | ||||||
|             source_url, |       source_url, | ||||||
|             dependency_url; |       dependency_url; | ||||||
|  |  | ||||||
|     private boolean hasExpansion, |   private boolean hasExpansion, | ||||||
|             shouldUpdate, |       shouldUpdate, | ||||||
|             verified; |       verified; | ||||||
|  |  | ||||||
|     private long last_update, |   private long last_update, | ||||||
|             ratings_count; |       ratings_count; | ||||||
|  |  | ||||||
|     private double average_rating; |   private double average_rating; | ||||||
|  |  | ||||||
|     private List<String> placeholders; |   private List<String> placeholders; | ||||||
|  |  | ||||||
|     private List<Version> versions; |   private List<Version> versions; | ||||||
|  |  | ||||||
|     public CloudExpansion() { |   public CloudExpansion() { | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getTimeSinceLastUpdate() { | ||||||
|  |     int time = (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - getLastUpdate()); | ||||||
|  |     return TimeUtil.getTime(time); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getName() { | ||||||
|  |     return name; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void setName(String name) { | ||||||
|  |     this.name = name; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getAuthor() { | ||||||
|  |     return author; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void setAuthor(String author) { | ||||||
|  |     this.author = author; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public Version getVersion() { | ||||||
|  |     return getLatestVersion() == null ? null : getVersion(getLatestVersion()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public Version getVersion(String version) { | ||||||
|  |     return versions == null ? null : versions.stream() | ||||||
|  |         .filter(v -> v.getVersion().equals(version)) | ||||||
|  |         .findFirst() | ||||||
|  |         .orElse(null); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public List<String> getAvailableVersions() { | ||||||
|  |     return versions.stream().map(Version::getVersion).collect(Collectors.toList()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getLatestVersion() { | ||||||
|  |     return latest_version; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void setLatestVersion(String latest_version) { | ||||||
|  |     this.latest_version = latest_version; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getDescription() { | ||||||
|  |     return description; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void setDescription(String description) { | ||||||
|  |     this.description = description; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getSourceUrl() { | ||||||
|  |     return source_url; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void setSourceUrl(String source_url) { | ||||||
|  |     this.source_url = source_url; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getDependencyUrl() { | ||||||
|  |     return dependency_url; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void setDependencyUrl(String dependency_url) { | ||||||
|  |     this.dependency_url = dependency_url; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public boolean hasExpansion() { | ||||||
|  |     return hasExpansion; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void setHasExpansion(boolean hasExpansion) { | ||||||
|  |     this.hasExpansion = hasExpansion; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public boolean shouldUpdate() { | ||||||
|  |     return shouldUpdate; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void setShouldUpdate(boolean shouldUpdate) { | ||||||
|  |     this.shouldUpdate = shouldUpdate; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public boolean isVerified() { | ||||||
|  |     return verified; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public long getLastUpdate() { | ||||||
|  |     return last_update; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void setLastUpdate(long last_update) { | ||||||
|  |     this.last_update = last_update; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public long getRatingsCount() { | ||||||
|  |     return ratings_count; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public double getAverage_rating() { | ||||||
|  |     return average_rating; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public List<String> getPlaceholders() { | ||||||
|  |     return placeholders; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void setPlaceholders(List<String> placeholders) { | ||||||
|  |     this.placeholders = placeholders; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public List<Version> getVersions() { | ||||||
|  |     return versions; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void setVersions(List<Version> versions) { | ||||||
|  |     this.versions = versions; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public class Version { | ||||||
|  |  | ||||||
|  |     private String url, version, release_notes; | ||||||
|  |  | ||||||
|  |     public String getUrl() { | ||||||
|  |       return url; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public String getTimeSinceLastUpdate() { |     public void setUrl(String url) { | ||||||
|         int time = (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - getLastUpdate()); |       this.url = url; | ||||||
|         return TimeUtil.getTime(time); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public String getName() { |     public String getVersion() { | ||||||
|         return name; |       return version; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void setName(String name) { |     public void setVersion(String version) { | ||||||
|         this.name = name; |       this.version = version; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public String getAuthor() { |     public String getReleaseNotes() { | ||||||
|         return author; |       return release_notes; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void setAuthor(String author) { |     public void setReleaseNotes(String release_notes) { | ||||||
|         this.author = author; |       this.release_notes = release_notes; | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public Version getVersion() { |  | ||||||
|         return getLatestVersion() == null ? null : getVersion(getLatestVersion()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public Version getVersion(String version) { |  | ||||||
|         return versions == null ? null : versions.stream() |  | ||||||
|                 .filter(v -> v.getVersion().equals(version)) |  | ||||||
|                 .findFirst() |  | ||||||
|                 .orElse(null); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public List<String> getAvailableVersions() { |  | ||||||
|         return versions.stream().map(Version::getVersion).collect(Collectors.toList()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public String getLatestVersion() { |  | ||||||
|         return latest_version; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void setLatestVersion(String latest_version) { |  | ||||||
|         this.latest_version = latest_version; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public String getDescription() { |  | ||||||
|         return description; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void setDescription(String description) { |  | ||||||
|         this.description = description; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public String getSourceUrl() { |  | ||||||
|         return source_url; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void setSourceUrl(String source_url) { |  | ||||||
|         this.source_url = source_url; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public String getDependencyUrl() { |  | ||||||
|         return dependency_url; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void setDependencyUrl(String dependency_url) { |  | ||||||
|         this.dependency_url = dependency_url; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public boolean hasExpansion() { |  | ||||||
|         return hasExpansion; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void setHasExpansion(boolean hasExpansion) { |  | ||||||
|         this.hasExpansion = hasExpansion; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public boolean shouldUpdate() { |  | ||||||
|         return shouldUpdate; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void setShouldUpdate(boolean shouldUpdate) { |  | ||||||
|         this.shouldUpdate = shouldUpdate; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public boolean isVerified() { |  | ||||||
|         return verified; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public long getLastUpdate() { |  | ||||||
|         return last_update; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void setLastUpdate(long last_update) { |  | ||||||
|         this.last_update = last_update; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public long getRatingsCount() { |  | ||||||
|         return ratings_count; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public double getAverage_rating() { |  | ||||||
|         return average_rating; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public List<String> getPlaceholders() { |  | ||||||
|         return placeholders; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void setPlaceholders(List<String> placeholders) { |  | ||||||
|         this.placeholders = placeholders; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public List<Version> getVersions() { |  | ||||||
|         return versions; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void setVersions(List<Version> versions) { |  | ||||||
|         this.versions = versions; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public class Version { |  | ||||||
|         private String url, version, release_notes; |  | ||||||
|  |  | ||||||
|         public String getUrl() { |  | ||||||
|             return url; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public void setUrl(String url) { |  | ||||||
|             this.url = url; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public String getVersion() { |  | ||||||
|             return version; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public void setVersion(String version) { |  | ||||||
|             this.version = version; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public String getReleaseNotes() { |  | ||||||
|             return release_notes; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public void setReleaseNotes(String release_notes) { |  | ||||||
|             this.release_notes = release_notes; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,14 +22,9 @@ package me.clip.placeholderapi.expansion.manager; | |||||||
|  |  | ||||||
| import com.google.common.collect.ImmutableMap; | import com.google.common.collect.ImmutableMap; | ||||||
| import com.google.common.io.Resources; | import com.google.common.io.Resources; | ||||||
|  | import com.google.common.util.concurrent.ThreadFactoryBuilder; | ||||||
| import com.google.gson.Gson; | import com.google.gson.Gson; | ||||||
| import com.google.gson.reflect.TypeToken; | import com.google.gson.reflect.TypeToken; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; |  | ||||||
| import me.clip.placeholderapi.expansion.PlaceholderExpansion; |  | ||||||
| import me.clip.placeholderapi.expansion.cloud.CloudExpansion; |  | ||||||
| import org.jetbrains.annotations.NotNull; |  | ||||||
| import org.jetbrains.annotations.Unmodifiable; |  | ||||||
|  |  | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.io.FileOutputStream; | import java.io.FileOutputStream; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| @@ -38,251 +33,248 @@ import java.net.URL; | |||||||
| import java.nio.channels.Channels; | import java.nio.channels.Channels; | ||||||
| import java.nio.channels.ReadableByteChannel; | import java.nio.channels.ReadableByteChannel; | ||||||
| import java.nio.charset.StandardCharsets; | import java.nio.charset.StandardCharsets; | ||||||
| import java.util.*; | import java.util.ArrayList; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.Optional; | ||||||
|  | import java.util.Set; | ||||||
| import java.util.concurrent.CompletableFuture; | import java.util.concurrent.CompletableFuture; | ||||||
| import java.util.concurrent.CompletionException; | import java.util.concurrent.CompletionException; | ||||||
| import java.util.concurrent.ConcurrentHashMap; | import java.util.concurrent.ConcurrentHashMap; | ||||||
|  | import java.util.concurrent.ExecutorService; | ||||||
|  | import java.util.concurrent.Executors; | ||||||
| import java.util.function.Function; | import java.util.function.Function; | ||||||
| import java.util.logging.Level; | import java.util.logging.Level; | ||||||
| import java.util.stream.Collector; | import java.util.stream.Collector; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
|  | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
|  | import me.clip.placeholderapi.expansion.PlaceholderExpansion; | ||||||
|  | import me.clip.placeholderapi.expansion.cloud.CloudExpansion; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| public final class CloudExpansionManager | public final class CloudExpansionManager { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private static final String API_URL = "http://api.extendedclip.com/v2/"; |   private static final String API_URL = "http://api.extendedclip.com/v2/"; | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private static final Gson GSON = new Gson(); |   private static final Gson GSON = new Gson(); | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private static final Type TYPE = new TypeToken<Map<String, CloudExpansion>>() {}.getType(); |   private static final Type TYPE = new TypeToken<Map<String, CloudExpansion>>() {}.getType(); | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private final Collector<CloudExpansion, ?, Map<String, CloudExpansion>> INDEXED_NAME_COLLECTOR = Collectors.toMap(CloudExpansionManager::toIndexName, Function.identity()); |   private final Collector<CloudExpansion, ?, Map<String, CloudExpansion>> INDEXED_NAME_COLLECTOR = Collectors | ||||||
|  |       .toMap(CloudExpansionManager::toIndexName, Function.identity()); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private final PlaceholderAPIPlugin plugin; |   private final PlaceholderAPIPlugin plugin; | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private final Map<String, CloudExpansion>          cache = new HashMap<>(); |   private final Map<String, CloudExpansion> cache = new HashMap<>(); | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private final Map<String, CompletableFuture<File>> await = new ConcurrentHashMap<>(); |   private final Map<String, CompletableFuture<File>> await = new ConcurrentHashMap<>(); | ||||||
|  |  | ||||||
|  |   private final ExecutorService ASYNC_EXECUTOR = | ||||||
|  |       Executors.newCachedThreadPool( | ||||||
|  |           new ThreadFactoryBuilder().setNameFormat("placeholderapi-io-#%1$d").build()); | ||||||
|  |  | ||||||
| 	public CloudExpansionManager(@NotNull final PlaceholderAPIPlugin plugin) |   public CloudExpansionManager(@NotNull final PlaceholderAPIPlugin plugin) { | ||||||
| 	{ |     this.plugin = plugin; | ||||||
| 		this.plugin = plugin; |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
|  |   private static String toIndexName(@NotNull final String name) { | ||||||
|  |     return name.toLowerCase().replace(' ', '_'); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	public void load() |   @NotNull | ||||||
| 	{ |   private static String toIndexName(@NotNull final CloudExpansion expansion) { | ||||||
| 		clean(); |     return toIndexName(expansion.getName()); | ||||||
| 		fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public void kill() |   public void load() { | ||||||
| 	{ |     clean(); | ||||||
| 		clean(); |     fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
|  |   public void kill() { | ||||||
|  |     clean(); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	@Unmodifiable |   @Unmodifiable | ||||||
| 	public Map<String, CloudExpansion> getCloudExpansions() |   public Map<String, CloudExpansion> getCloudExpansions() { | ||||||
| 	{ |     return ImmutableMap.copyOf(cache); | ||||||
| 		return ImmutableMap.copyOf(cache); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	@Unmodifiable |   @Unmodifiable | ||||||
| 	public Map<String, CloudExpansion> getCloudExpansionsInstalled() |   public Map<String, CloudExpansion> getCloudExpansionsInstalled() { | ||||||
| 	{ |     if (cache.isEmpty()) { | ||||||
| 		if (cache.isEmpty()) |       return Collections.emptyMap(); | ||||||
| 		{ |     } | ||||||
| 			return Collections.emptyMap(); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return cache.values() |     return cache.values() | ||||||
| 					.stream() |         .stream() | ||||||
| 					.filter(CloudExpansion::hasExpansion) |         .filter(CloudExpansion::hasExpansion) | ||||||
| 					.collect(INDEXED_NAME_COLLECTOR); |         .collect(INDEXED_NAME_COLLECTOR); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	@Unmodifiable |   @Unmodifiable | ||||||
| 	public Map<String, CloudExpansion> getCloudExpansionsByAuthor(@NotNull final String author) |   public Map<String, CloudExpansion> getCloudExpansionsByAuthor(@NotNull final String author) { | ||||||
| 	{ |     if (cache.isEmpty()) { | ||||||
| 		if (cache.isEmpty()) |       return Collections.emptyMap(); | ||||||
| 		{ |     } | ||||||
| 			return Collections.emptyMap(); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return cache.values() |     return cache.values() | ||||||
| 					.stream() |         .stream() | ||||||
| 					.filter(expansion -> author.equalsIgnoreCase(expansion.getAuthor())) |         .filter(expansion -> author.equalsIgnoreCase(expansion.getAuthor())) | ||||||
| 					.collect(INDEXED_NAME_COLLECTOR); |         .collect(INDEXED_NAME_COLLECTOR); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	@Unmodifiable |   @Unmodifiable | ||||||
| 	public Set<String> getCloudExpansionAuthors() |   public Set<String> getCloudExpansionAuthors() { | ||||||
| 	{ |     return cache.values().stream().map(CloudExpansion::getAuthor).collect(Collectors.toSet()); | ||||||
| 		return cache.values().stream().map(CloudExpansion::getAuthor).collect(Collectors.toSet()); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   public int getCloudExpansionAuthorCount() { | ||||||
|  |     return getCloudExpansionAuthors().size(); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	public int getCloudExpansionAuthorCount() |   public int getCloudUpdateCount() { | ||||||
| 	{ |     return ((int) plugin.getLocalExpansionManager() | ||||||
| 		return getCloudExpansionAuthors().size(); |         .getExpansions() | ||||||
| 	} |         .stream() | ||||||
|  |         .filter(expansion -> findCloudExpansionByName(expansion.getName()) | ||||||
|  |             .map(CloudExpansion::shouldUpdate).orElse(false)) | ||||||
|  |         .count()); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	public int getCloudUpdateCount() |   @NotNull | ||||||
| 	{ |   public Optional<CloudExpansion> findCloudExpansionByName(@NotNull final String name) { | ||||||
| 		return ((int) plugin.getLocalExpansionManager() |     return Optional.ofNullable(cache.get(toIndexName(name))); | ||||||
| 							.getExpansions() |   } | ||||||
| 							.stream() |  | ||||||
| 							.filter(expansion -> findCloudExpansionByName(expansion.getName()).map(CloudExpansion::shouldUpdate).orElse(false)) |  | ||||||
| 							.count()); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   public void clean() { | ||||||
|  |     cache.clear(); | ||||||
|  |  | ||||||
| 	@NotNull |     await.values().forEach(future -> future.cancel(true)); | ||||||
| 	public Optional<CloudExpansion> findCloudExpansionByName(@NotNull final String name) |     await.clear(); | ||||||
| 	{ |   } | ||||||
| 		return Optional.ofNullable(cache.get(toIndexName(name))); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   public void fetch(final boolean allowUnverified) { | ||||||
|  |     plugin.getLogger().info("Fetching available expansion information..."); | ||||||
|  |  | ||||||
| 	public void clean() |     ASYNC_EXECUTOR.submit( | ||||||
| 	{ |         () -> { | ||||||
| 		cache.clear(); |           // a defence tactic! use ConcurrentHashMap instead of normal HashMap | ||||||
|  |           Map<String, CloudExpansion> values = new ConcurrentHashMap<>(); | ||||||
|  |           try { | ||||||
|  |             //noinspection UnstableApiUsage | ||||||
|  |             String json = Resources.toString(new URL(API_URL), StandardCharsets.UTF_8); | ||||||
|  |             values.putAll(GSON.fromJson(json, TYPE)); | ||||||
|  |  | ||||||
| 		await.values().forEach(future -> future.cancel(true)); |             List<String> toRemove = new ArrayList<>(); | ||||||
| 		await.clear(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public void fetch(final boolean allowUnverified) |             for (Map.Entry<String, CloudExpansion> entry : values.entrySet()) { | ||||||
| 	{ |               CloudExpansion expansion = entry.getValue(); | ||||||
| 		plugin.getLogger().info("Fetching available expansion information..."); |               if (expansion.getLatestVersion() == null | ||||||
|  |                   || expansion.getVersion(expansion.getLatestVersion()) == null) { | ||||||
|  |                 toRemove.add(entry.getKey()); | ||||||
|  |               } | ||||||
|  |               if (!allowUnverified && !expansion.isVerified()) { | ||||||
|  |                 toRemove.add(entry.getKey()); | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |  | ||||||
| 		CompletableFuture<Map<String, CloudExpansion>> future = CompletableFuture.supplyAsync(() -> { |             for (String name : toRemove) { | ||||||
| 			final Map<String, CloudExpansion> values = new HashMap<>(); |               values.remove(name); | ||||||
|  |             } | ||||||
|  |           } catch (Throwable e) { | ||||||
|  |             // ugly swallowing of every throwable, but we have to be defensive | ||||||
|  |             plugin.getLogger().log(Level.WARNING, "Failed to download expansion information", e); | ||||||
|  |           } | ||||||
|  |  | ||||||
| 			try |           // loop thru what's left on the main thread | ||||||
| 			{ |           plugin | ||||||
| 				//noinspection UnstableApiUsage |               .getServer() | ||||||
| 				final String json = Resources.toString(new URL(API_URL), StandardCharsets.UTF_8); |               .getScheduler() | ||||||
| 				values.putAll(GSON.fromJson(json, TYPE)); |               .runTask( | ||||||
| 			} |                   plugin, | ||||||
| 			catch (final IOException ex) |                   () -> { | ||||||
| 			{ |                     try { | ||||||
| 				throw new CompletionException(ex); |                       for (Map.Entry<String, CloudExpansion> entry : values.entrySet()) { | ||||||
| 			} |                         String name = entry.getKey(); | ||||||
|  |                         CloudExpansion expansion = entry.getValue(); | ||||||
|  |  | ||||||
| 			values.values().removeIf(value -> value.getLatestVersion() == null || value.getVersion(value.getLatestVersion()) == null); |                         expansion.setName(name); | ||||||
|  |  | ||||||
| 			return values; |                         Optional<PlaceholderExpansion> localOpt = | ||||||
| 		}); |                             plugin.getLocalExpansionManager().findExpansionByName(name); | ||||||
|  |                         if (localOpt.isPresent()) { | ||||||
|  |                           PlaceholderExpansion local = localOpt.get(); | ||||||
|  |                           if (local.isRegistered()) { | ||||||
|  |                             expansion.setHasExpansion(true); | ||||||
|  |                             expansion.setShouldUpdate( | ||||||
|  |                                 !local.getVersion().equalsIgnoreCase(expansion.getLatestVersion())); | ||||||
|  |                           } | ||||||
|  |                         } | ||||||
|  |  | ||||||
|  |                         cache.put(toIndexName(expansion), expansion); | ||||||
|  |                       } | ||||||
|  |                     } catch (Throwable e) { | ||||||
|  |                       // ugly swallowing of every throwable, but we have to be defensive | ||||||
|  |                       plugin | ||||||
|  |                           .getLogger() | ||||||
|  |                           .log(Level.WARNING, "Failed to download expansion information", e); | ||||||
|  |                     } | ||||||
|  |                   }); | ||||||
|  |         }); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 		if (!allowUnverified) |   public boolean isDownloading(@NotNull final CloudExpansion expansion) { | ||||||
| 		{ |     return await.containsKey(toIndexName(expansion)); | ||||||
| 			future = future.thenApplyAsync((values) -> { |   } | ||||||
| 				values.values().removeIf(expansion -> !expansion.isVerified()); |  | ||||||
| 				return values; |  | ||||||
| 			}); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
|  |   public CompletableFuture<File> downloadExpansion(@NotNull final CloudExpansion expansion, | ||||||
|  |       @NotNull final CloudExpansion.Version version) { | ||||||
|  |     final CompletableFuture<File> previous = await.get(toIndexName(expansion)); | ||||||
|  |     if (previous != null) { | ||||||
|  |       return previous; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		future = future.thenApplyAsync((values) -> { |     final File file = new File(plugin.getLocalExpansionManager().getExpansionsFolder(), | ||||||
|  |         "Expansion-" + toIndexName(expansion) + ".jar"); | ||||||
|  |  | ||||||
| 			values.forEach((name, expansion) -> { |     final CompletableFuture<File> download = CompletableFuture.supplyAsync(() -> { | ||||||
| 				expansion.setName(name); |       try (final ReadableByteChannel source = Channels.newChannel(new URL(version.getUrl()) | ||||||
|  |           .openStream()); final FileOutputStream target = new FileOutputStream(file)) { | ||||||
|  |         target.getChannel().transferFrom(source, 0, Long.MAX_VALUE); | ||||||
|  |       } catch (final IOException ex) { | ||||||
|  |         throw new CompletionException(ex); | ||||||
|  |       } | ||||||
|  |       return file; | ||||||
|  |     }, ASYNC_EXECUTOR); | ||||||
|  |  | ||||||
| 				final Optional<PlaceholderExpansion> local = plugin.getLocalExpansionManager().findExpansionByName(name); |     download.whenCompleteAsync((value, exception) -> { | ||||||
| 				if (local.isPresent() && local.get().isRegistered()) |       await.remove(toIndexName(expansion)); | ||||||
| 				{ |  | ||||||
| 					expansion.setHasExpansion(true); |  | ||||||
| 					expansion.setShouldUpdate(!local.get().getVersion().equals(expansion.getLatestVersion())); |  | ||||||
| 				} |  | ||||||
| 			}); |  | ||||||
|  |  | ||||||
| 			return values; |       if (exception != null) { | ||||||
| 		}); |         plugin.getLogger().log(Level.SEVERE, | ||||||
|  |             "failed to download " + expansion.getName() + ":" + version.getVersion(), exception); | ||||||
|  |       } | ||||||
|  |     }, ASYNC_EXECUTOR); | ||||||
|  |  | ||||||
| 		future.whenComplete((expansions, exception) -> { |     await.put(toIndexName(expansion), download); | ||||||
|  |  | ||||||
| 			if (exception != null) |     return download; | ||||||
| 			{ |   } | ||||||
| 				plugin.getLogger().log(Level.WARNING, "failed to download expansion information", exception); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			for (final CloudExpansion expansion : expansions.values()) |  | ||||||
| 			{ |  | ||||||
| 				this.cache.put(toIndexName(expansion), expansion); |  | ||||||
| 			} |  | ||||||
| 		}); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public boolean isDownloading(@NotNull final CloudExpansion expansion) |  | ||||||
| 	{ |  | ||||||
| 		return await.containsKey(toIndexName(expansion)); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public CompletableFuture<File> downloadExpansion(@NotNull final CloudExpansion expansion, @NotNull final CloudExpansion.Version version) |  | ||||||
| 	{ |  | ||||||
| 		final CompletableFuture<File> previous = await.get(toIndexName(expansion)); |  | ||||||
| 		if (previous != null) |  | ||||||
| 		{ |  | ||||||
| 			return previous; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final File file = new File(plugin.getLocalExpansionManager().getExpansionsFolder(), "Expansion-" + toIndexName(expansion) + ".jar"); |  | ||||||
|  |  | ||||||
| 		final CompletableFuture<File> download = CompletableFuture.supplyAsync(() -> { |  | ||||||
| 			try (final ReadableByteChannel source = Channels.newChannel(new URL(version.getUrl()).openStream()); final FileOutputStream target = new FileOutputStream(file)) |  | ||||||
| 			{ |  | ||||||
| 				target.getChannel().transferFrom(source, 0, Long.MAX_VALUE); |  | ||||||
| 			} |  | ||||||
| 			catch (final IOException ex) |  | ||||||
| 			{ |  | ||||||
| 				throw new CompletionException(ex); |  | ||||||
| 			} |  | ||||||
| 			return file; |  | ||||||
| 		}); |  | ||||||
|  |  | ||||||
| 		download.whenCompleteAsync((value, exception) -> { |  | ||||||
| 			await.remove(toIndexName(expansion)); |  | ||||||
|  |  | ||||||
| 			if (exception != null) |  | ||||||
| 			{ |  | ||||||
| 				plugin.getLogger().log(Level.SEVERE, "failed to download " + expansion.getName() + ":" + version.getVersion(), exception); |  | ||||||
| 			} |  | ||||||
| 		}); |  | ||||||
|  |  | ||||||
| 		await.put(toIndexName(expansion), download); |  | ||||||
|  |  | ||||||
| 		return download; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	private static String toIndexName(@NotNull final String name) |  | ||||||
| 	{ |  | ||||||
| 		return name.toLowerCase().replace(' ', '_'); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	private static String toIndexName(@NotNull final CloudExpansion expansion) |  | ||||||
| 	{ |  | ||||||
| 		return toIndexName(expansion.getName()); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,10 +22,26 @@ package me.clip.placeholderapi.expansion.manager; | |||||||
|  |  | ||||||
| import com.google.common.collect.ImmutableSet; | import com.google.common.collect.ImmutableSet; | ||||||
| import com.google.common.collect.Sets; | import com.google.common.collect.Sets; | ||||||
|  | import java.io.File; | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.Optional; | ||||||
|  | import java.util.concurrent.CompletableFuture; | ||||||
|  | import java.util.concurrent.CompletionException; | ||||||
|  | import java.util.concurrent.ConcurrentHashMap; | ||||||
|  | import java.util.concurrent.locks.ReentrantLock; | ||||||
|  | import java.util.logging.Level; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.events.ExpansionRegisterEvent; | import me.clip.placeholderapi.events.ExpansionRegisterEvent; | ||||||
| import me.clip.placeholderapi.events.ExpansionUnregisterEvent; | import me.clip.placeholderapi.events.ExpansionUnregisterEvent; | ||||||
| import me.clip.placeholderapi.expansion.*; | import me.clip.placeholderapi.expansion.Cacheable; | ||||||
|  | import me.clip.placeholderapi.expansion.Cleanable; | ||||||
|  | import me.clip.placeholderapi.expansion.Configurable; | ||||||
|  | import me.clip.placeholderapi.expansion.PlaceholderExpansion; | ||||||
|  | import me.clip.placeholderapi.expansion.Taskable; | ||||||
|  | import me.clip.placeholderapi.expansion.VersionSpecific; | ||||||
| import me.clip.placeholderapi.expansion.cloud.CloudExpansion; | import me.clip.placeholderapi.expansion.cloud.CloudExpansion; | ||||||
| import me.clip.placeholderapi.util.FileUtil; | import me.clip.placeholderapi.util.FileUtil; | ||||||
| import me.clip.placeholderapi.util.Futures; | import me.clip.placeholderapi.util.Futures; | ||||||
| @@ -44,381 +60,349 @@ import org.jetbrains.annotations.NotNull; | |||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.io.File; | public final class LocalExpansionManager implements Listener { | ||||||
| import java.util.Arrays; |  | ||||||
| import java.util.Collection; |   @NotNull | ||||||
| import java.util.HashMap; |   private static final String EXPANSIONS_FOLDER_NAME = "expansions"; | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.Optional; |   @NotNull | ||||||
| import java.util.concurrent.CompletableFuture; |   private final File folder; | ||||||
| import java.util.concurrent.CompletionException; |   @NotNull | ||||||
| import java.util.logging.Level; |   private final PlaceholderAPIPlugin plugin; | ||||||
|  |  | ||||||
| public final class LocalExpansionManager implements Listener |   @NotNull | ||||||
| { |   private final Map<String, PlaceholderExpansion> expansions = new ConcurrentHashMap<>(); | ||||||
|  |   private final ReentrantLock expansionsLock = new ReentrantLock(); | ||||||
| 	@NotNull |  | ||||||
| 	private static final String EXPANSIONS_FOLDER_NAME = "expansions"; |  | ||||||
|  |   public LocalExpansionManager(@NotNull final PlaceholderAPIPlugin plugin) { | ||||||
|  |     this.plugin = plugin; | ||||||
| 	@NotNull |     this.folder = new File(plugin.getDataFolder(), EXPANSIONS_FOLDER_NAME); | ||||||
| 	private final File                 folder; |  | ||||||
| 	@NotNull |     if (!this.folder.exists() && !folder.mkdirs()) { | ||||||
| 	private final PlaceholderAPIPlugin plugin; |       plugin.getLogger().log(Level.WARNING, "failed to create expansions folder!"); | ||||||
|  |     } | ||||||
| 	@NotNull |   } | ||||||
| 	private final Map<String, PlaceholderExpansion> expansions = new HashMap<>(); |  | ||||||
|  |   public void load(@NotNull final CommandSender sender) { | ||||||
|  |     registerAll(sender); | ||||||
| 	public LocalExpansionManager(@NotNull final PlaceholderAPIPlugin plugin) |   } | ||||||
| 	{ |  | ||||||
| 		this.plugin = plugin; |   public void kill() { | ||||||
| 		this.folder = new File(plugin.getDataFolder(), EXPANSIONS_FOLDER_NAME); |     unregisterAll(); | ||||||
|  |   } | ||||||
| 		if (!this.folder.exists() && !folder.mkdirs()) |  | ||||||
| 		{ |  | ||||||
| 			plugin.getLogger().log(Level.WARNING, "failed to create expansions folder!"); |   @NotNull | ||||||
| 		} |   public File getExpansionsFolder() { | ||||||
| 	} |     return folder; | ||||||
|  |   } | ||||||
| 	public void load(@NotNull final CommandSender sender) |  | ||||||
| 	{ |   @NotNull | ||||||
| 		registerAll(sender); |   @Unmodifiable | ||||||
| 	} |   public Collection<String> getIdentifiers() { | ||||||
|  |     expansionsLock.lock(); | ||||||
| 	public void kill() |     try { | ||||||
| 	{ |       return ImmutableSet.copyOf(expansions.keySet()); | ||||||
| 		unregisterAll(); |     } finally { | ||||||
| 	} |       expansionsLock.unlock(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
| 	@NotNull |  | ||||||
| 	public File getExpansionsFolder() |   @NotNull | ||||||
| 	{ |   @Unmodifiable | ||||||
| 		return folder; |   public Collection<PlaceholderExpansion> getExpansions() { | ||||||
| 	} |     expansionsLock.lock(); | ||||||
|  |     try { | ||||||
| 	public int getExpansionsCount() |       return ImmutableSet.copyOf(expansions.values()); | ||||||
| 	{ |     } finally { | ||||||
| 		return expansions.size(); |       expansionsLock.unlock(); | ||||||
| 	} |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	@NotNull |   @Nullable | ||||||
| 	@Unmodifiable |   public PlaceholderExpansion getExpansion(@NotNull final String identifier) { | ||||||
| 	public Collection<String> getIdentifiers() |     expansionsLock.lock(); | ||||||
| 	{ |     try { | ||||||
| 		return ImmutableSet.copyOf(expansions.keySet()); |       return expansions.get(identifier.toLowerCase()); | ||||||
| 	} |     } finally { | ||||||
|  |       expansionsLock.unlock(); | ||||||
| 	@NotNull |     } | ||||||
| 	@Unmodifiable |   } | ||||||
| 	public Collection<PlaceholderExpansion> getExpansions() |  | ||||||
| 	{ |   @NotNull | ||||||
| 		return ImmutableSet.copyOf(expansions.values()); |   public Optional<PlaceholderExpansion> findExpansionByName(@NotNull final String name) { | ||||||
| 	} |     expansionsLock.lock(); | ||||||
|  |     try { | ||||||
|  |       PlaceholderExpansion bestMatch = null; | ||||||
| 	@Nullable |       for (Map.Entry<String, PlaceholderExpansion> entry : expansions.entrySet()) { | ||||||
| 	public PlaceholderExpansion getExpansion(@NotNull final String identifier) |         PlaceholderExpansion expansion = entry.getValue(); | ||||||
| 	{ |         if (expansion.getName().equalsIgnoreCase(name)) { | ||||||
| 		return expansions.get(identifier.toLowerCase()); |           bestMatch = expansion; | ||||||
| 	} |           break; | ||||||
|  |         } | ||||||
|  |       } | ||||||
| 	@NotNull |       return Optional.ofNullable(bestMatch); | ||||||
| 	public Optional<PlaceholderExpansion> findExpansionByName(@NotNull final String name) |     } finally { | ||||||
| 	{ |       expansionsLock.unlock(); | ||||||
| 		return expansions.values().stream().filter(expansion -> name.equalsIgnoreCase(expansion.getName())).findFirst(); |     } | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	public Optional<PlaceholderExpansion> findExpansionByIdentifier(@NotNull final String identifier) |   public Optional<PlaceholderExpansion> findExpansionByIdentifier( | ||||||
| 	{ |       @NotNull final String identifier) { | ||||||
| 		return Optional.ofNullable(getExpansion(identifier)); |     return Optional.ofNullable(getExpansion(identifier)); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public Optional<PlaceholderExpansion> register(@NotNull final Class<? extends PlaceholderExpansion> clazz) |   public Optional<PlaceholderExpansion> register( | ||||||
| 	{ |       @NotNull final Class<? extends PlaceholderExpansion> clazz) { | ||||||
| 		try |     try { | ||||||
| 		{ |       final PlaceholderExpansion expansion = createExpansionInstance(clazz); | ||||||
| 			final PlaceholderExpansion expansion = createExpansionInstance(clazz); |       if (expansion == null || !expansion.register()) { | ||||||
| 			if (expansion == null || !expansion.register()) |         return Optional.empty(); | ||||||
| 			{ |       } | ||||||
| 				return Optional.empty(); |  | ||||||
| 			} |       return Optional.of(expansion); | ||||||
|  |     } catch (final LinkageError ex) { | ||||||
| 			return Optional.of(expansion); |       plugin.getLogger().severe("expansion class " + clazz.getSimpleName() + " is outdated: \n" + | ||||||
| 		} |           "Failed to load due to a [" + ex.getClass().getSimpleName() + "], attempted to use " + ex | ||||||
| 		catch (final LinkageError ex) |           .getMessage()); | ||||||
| 		{ |     } | ||||||
| 			plugin.getLogger().severe("expansion class " + clazz.getSimpleName() + " is outdated: \n" + |  | ||||||
| 									  "Failed to load due to a [" + ex.getClass().getSimpleName() + "], attempted to use " + ex.getMessage()); |     return Optional.empty(); | ||||||
| 		} |   } | ||||||
|  |  | ||||||
| 		return Optional.empty(); |   /** | ||||||
| 	} |    * Do not call this method yourself, use {@link PlaceholderExpansion#register()} | ||||||
|  |    */ | ||||||
| 	/** |   @ApiStatus.Internal | ||||||
| 	 * Do not call this method yourself, use {@link PlaceholderExpansion#register()} |   public boolean register(@NotNull final PlaceholderExpansion expansion) { | ||||||
| 	 */ |     final String identifier = expansion.getIdentifier().toLowerCase(); | ||||||
| 	@ApiStatus.Internal |  | ||||||
| 	public boolean register(@NotNull final PlaceholderExpansion expansion) |     if (!expansion.canRegister()) { | ||||||
| 	{ |       return false; | ||||||
| 		final String identifier = expansion.getIdentifier().toLowerCase(); |     } | ||||||
|  |  | ||||||
| 		if (expansion instanceof Configurable) |     if (expansion instanceof Configurable) { | ||||||
| 		{ |       Map<String, Object> defaults = ((Configurable) expansion).getDefaults(); | ||||||
| 			Map<String, Object> defaults = ((Configurable) expansion).getDefaults(); |       String pre = "expansions." + identifier + "."; | ||||||
| 			String              pre      = "expansions." + identifier + "."; |       FileConfiguration cfg = plugin.getConfig(); | ||||||
| 			FileConfiguration   cfg      = plugin.getConfig(); |       boolean save = false; | ||||||
| 			boolean             save     = false; |  | ||||||
|  |       if (defaults != null) { | ||||||
| 			if (defaults != null) |         for (Map.Entry<String, Object> entries : defaults.entrySet()) { | ||||||
| 			{ |           if (entries.getKey() == null || entries.getKey().isEmpty()) { | ||||||
| 				for (Map.Entry<String, Object> entries : defaults.entrySet()) |             continue; | ||||||
| 				{ |           } | ||||||
| 					if (entries.getKey() == null || entries.getKey().isEmpty()) |  | ||||||
| 					{ |           if (entries.getValue() == null) { | ||||||
| 						continue; |             if (cfg.contains(pre + entries.getKey())) { | ||||||
| 					} |               save = true; | ||||||
|  |               cfg.set(pre + entries.getKey(), null); | ||||||
| 					if (entries.getValue() == null) |             } | ||||||
| 					{ |           } else { | ||||||
| 						if (cfg.contains(pre + entries.getKey())) |             if (!cfg.contains(pre + entries.getKey())) { | ||||||
| 						{ |               save = true; | ||||||
| 							save = true; |               cfg.set(pre + entries.getKey(), entries.getValue()); | ||||||
| 							cfg.set(pre + entries.getKey(), null); |             } | ||||||
| 						} |           } | ||||||
| 					} |         } | ||||||
| 					else |       } | ||||||
| 					{ |  | ||||||
| 						if (!cfg.contains(pre + entries.getKey())) |       if (save) { | ||||||
| 						{ |         plugin.saveConfig(); | ||||||
| 							save = true; |         plugin.reloadConfig(); | ||||||
| 							cfg.set(pre + entries.getKey(), entries.getValue()); |       } | ||||||
| 						} |     } | ||||||
| 					} |  | ||||||
| 				} |     if (expansion instanceof VersionSpecific) { | ||||||
| 			} |       VersionSpecific nms = (VersionSpecific) expansion; | ||||||
|  |       if (!nms.isCompatibleWith(PlaceholderAPIPlugin.getServerVersion())) { | ||||||
| 			if (save) |         plugin.getLogger().info( | ||||||
| 			{ |             "Your server version is not compatible with expansion: " + expansion.getIdentifier() | ||||||
| 				plugin.saveConfig(); |                 + " version: " + expansion.getVersion()); | ||||||
| 				plugin.reloadConfig(); |         return false; | ||||||
| 			} |       } | ||||||
| 		} |     } | ||||||
|  |  | ||||||
| 		if (expansion instanceof VersionSpecific) |     final PlaceholderExpansion removed = getExpansion(identifier); | ||||||
| 		{ |     if (removed != null && !removed.unregister()) { | ||||||
| 			VersionSpecific nms = (VersionSpecific) expansion; |       return false; | ||||||
| 			if (!nms.isCompatibleWith(PlaceholderAPIPlugin.getServerVersion())) |     } | ||||||
| 			{ |  | ||||||
| 				plugin.getLogger().info("Your server version is not compatible with expansion: " + expansion.getIdentifier() + " version: " + expansion.getVersion()); |     final ExpansionRegisterEvent event = new ExpansionRegisterEvent(expansion); | ||||||
| 				return false; |     Bukkit.getPluginManager().callEvent(event); | ||||||
| 			} |  | ||||||
| 		} |     if (event.isCancelled()) { | ||||||
|  |       return false; | ||||||
| 		final PlaceholderExpansion removed = expansions.get(identifier); |     } | ||||||
| 		if (removed != null && !removed.unregister()) |  | ||||||
| 		{ |     expansionsLock.lock(); | ||||||
| 			return false; |     try { | ||||||
| 		} |       expansions.put(identifier, expansion); | ||||||
|  |     } finally { | ||||||
| 		final ExpansionRegisterEvent event = new ExpansionRegisterEvent(expansion); |       expansionsLock.unlock(); | ||||||
| 		Bukkit.getPluginManager().callEvent(event); |     } | ||||||
|  |  | ||||||
| 		if (event.isCancelled()) |     if (expansion instanceof Listener) { | ||||||
| 		{ |       Bukkit.getPluginManager().registerEvents(((Listener) expansion), plugin); | ||||||
| 			return false; |     } | ||||||
| 		} |  | ||||||
|  |     plugin.getLogger().info("Successfully registered expansion: " + expansion.getIdentifier()); | ||||||
| 		expansions.put(identifier, expansion); |  | ||||||
|  |     if (expansion instanceof Taskable) { | ||||||
| 		if (expansion instanceof Listener) |       ((Taskable) expansion).start(); | ||||||
| 		{ |     } | ||||||
| 			Bukkit.getPluginManager().registerEvents(((Listener) expansion), plugin); |  | ||||||
| 		} |     if (plugin.getPlaceholderAPIConfig().isCloudEnabled()) { | ||||||
|  |       final Optional<CloudExpansion> cloudExpansionOptional = | ||||||
| 		plugin.getLogger().info("Successfully registered expansion: " + expansion.getIdentifier()); |           plugin.getCloudExpansionManager().findCloudExpansionByName(identifier); | ||||||
|  |       if (cloudExpansionOptional.isPresent()) { | ||||||
| 		if (expansion instanceof Taskable) |         CloudExpansion cloudExpansion = cloudExpansionOptional.get(); | ||||||
| 		{ |         cloudExpansion.setHasExpansion(true); | ||||||
| 			((Taskable) expansion).start(); |         cloudExpansion.setShouldUpdate( | ||||||
| 		} |             !cloudExpansion.getLatestVersion().equals(expansion.getVersion())); | ||||||
|  |       } | ||||||
| 		if (plugin.getPlaceholderAPIConfig().isCloudEnabled()) |     } | ||||||
| 		{ |  | ||||||
| 			final Optional<CloudExpansion> cloudExpansion = plugin.getCloudExpansionManager().findCloudExpansionByName(identifier); |     return true; | ||||||
| 			if (cloudExpansion.isPresent()) |   } | ||||||
| 			{ |  | ||||||
| 				cloudExpansion.get().setHasExpansion(true); |   /** | ||||||
| 				cloudExpansion.get().setShouldUpdate(!cloudExpansion.get().getLatestVersion().equals(expansion.getVersion())); |    * Do not call this method yourself, use {@link PlaceholderExpansion#unregister()} | ||||||
| 			} |    */ | ||||||
| 		} |   @ApiStatus.Internal | ||||||
|  |   public boolean unregister(@NotNull final PlaceholderExpansion expansion) { | ||||||
| 		return true; |     if (expansions.remove(expansion.getIdentifier()) == null) { | ||||||
| 	} |       return false; | ||||||
|  |     } | ||||||
| 	/** |  | ||||||
| 	 * Do not call this method yourself, use {@link PlaceholderExpansion#unregister()} |     Bukkit.getPluginManager().callEvent(new ExpansionUnregisterEvent(expansion)); | ||||||
| 	 */ |  | ||||||
| 	@ApiStatus.Internal |     if (expansion instanceof Listener) { | ||||||
| 	public boolean unregister(@NotNull final PlaceholderExpansion expansion) |       HandlerList.unregisterAll((Listener) expansion); | ||||||
| 	{ |     } | ||||||
| 		if (expansions.remove(expansion.getIdentifier()) == null) |  | ||||||
| 		{ |     if (expansion instanceof Taskable) { | ||||||
| 			return false; |       ((Taskable) expansion).stop(); | ||||||
| 		} |     } | ||||||
|  |  | ||||||
|  |     if (expansion instanceof Cacheable) { | ||||||
| 		Bukkit.getPluginManager().callEvent(new ExpansionUnregisterEvent(expansion)); |       ((Cacheable) expansion).clear(); | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		if (expansion instanceof Listener) |     if (plugin.getPlaceholderAPIConfig().isCloudEnabled()) { | ||||||
| 		{ |       plugin.getCloudExpansionManager().findCloudExpansionByName(expansion.getName()) | ||||||
| 			HandlerList.unregisterAll((Listener) expansion); |           .ifPresent(cloud -> { | ||||||
| 		} |             cloud.setHasExpansion(false); | ||||||
|  |             cloud.setShouldUpdate(false); | ||||||
| 		if (expansion instanceof Taskable) |           }); | ||||||
| 		{ |     } | ||||||
| 			((Taskable) expansion).stop(); |  | ||||||
| 		} |     return true; | ||||||
|  |   } | ||||||
| 		if (expansion instanceof Cacheable) |  | ||||||
| 		{ |  | ||||||
| 			((Cacheable) expansion).clear(); |   private void registerAll(@NotNull final CommandSender sender) { | ||||||
| 		} |     plugin.getLogger().info("Placeholder expansion registration initializing..."); | ||||||
|  |  | ||||||
| 		if (plugin.getPlaceholderAPIConfig().isCloudEnabled()) |     Futures.onMainThread(plugin, findExpansionsOnDisk(), (classes, exception) -> { | ||||||
| 		{ |       if (exception != null) { | ||||||
| 			plugin.getCloudExpansionManager().findCloudExpansionByName(expansion.getName()).ifPresent(cloud -> { |         plugin.getLogger().log(Level.SEVERE, "failed to load class files of expansions", exception); | ||||||
| 				cloud.setHasExpansion(false); |         return; | ||||||
| 				cloud.setShouldUpdate(false); |       } | ||||||
| 			}); |  | ||||||
| 		} |       final long registered = classes.stream().map(this::register).filter(Optional::isPresent) | ||||||
|  |           .count(); | ||||||
| 		return true; |  | ||||||
| 	} |       Msg.msg(sender, | ||||||
|  |           registered == 0 ? "&6No expansions were registered!" | ||||||
|  |               : registered + "&a placeholder hooks successfully registered!"); | ||||||
| 	private void registerAll(@NotNull final CommandSender sender) |     }); | ||||||
| 	{ |   } | ||||||
| 		plugin.getLogger().info("Placeholder expansion registration initializing..."); |  | ||||||
|  |   private void unregisterAll() { | ||||||
| 		Futures.onMainThread(plugin, findExpansionsOnDisk(), (classes, exception) -> { |     for (final PlaceholderExpansion expansion : Sets.newHashSet(expansions.values())) { | ||||||
| 			if (exception != null) |       if (expansion.persist()) { | ||||||
| 			{ |         continue; | ||||||
| 				plugin.getLogger().log(Level.SEVERE, "failed to load class files of expansions", exception); |       } | ||||||
| 				return; |  | ||||||
| 			} |       expansion.unregister(); | ||||||
|  |     } | ||||||
| 			final long registered = classes.stream().map(this::register).filter(Optional::isPresent).count(); |   } | ||||||
|  |  | ||||||
| 			Msg.msg(sender, |  | ||||||
| 					registered == 0 ? "&6No expansions were registered!" : registered + "&a placeholder hooks successfully registered!"); |   @NotNull | ||||||
| 		}); |   public CompletableFuture<@NotNull List<@NotNull Class<? extends PlaceholderExpansion>>> findExpansionsOnDisk() { | ||||||
| 	} |     return Arrays.stream(folder.listFiles((dir, name) -> name.endsWith(".jar"))) | ||||||
|  |         .map(this::findExpansionInFile) | ||||||
| 	private void unregisterAll() |         .collect(Futures.collector()); | ||||||
| 	{ |   } | ||||||
| 		for (final PlaceholderExpansion expansion : Sets.newHashSet(expansions.values())) |  | ||||||
| 		{ |   @NotNull | ||||||
| 			if (expansion.persist()) |   public CompletableFuture<@Nullable Class<? extends PlaceholderExpansion>> findExpansionInFile( | ||||||
| 			{ |       @NotNull final File file) { | ||||||
| 				continue; |     return CompletableFuture.supplyAsync(() -> { | ||||||
| 			} |       try { | ||||||
|  |         return FileUtil.findClass(file, PlaceholderExpansion.class); | ||||||
| 			expansion.unregister(); |       } catch (final VerifyError ex) { | ||||||
| 		} |         plugin.getLogger().severe("expansion file " + file.getName() + " is outdated: \n" + | ||||||
| 	} |             "Failed to load due to a [" + ex.getClass().getSimpleName() + "], attempted to use" + ex | ||||||
|  |             .getMessage().substring(ex.getMessage().lastIndexOf(' '))); | ||||||
|  |         return null; | ||||||
| 	@NotNull |       } catch (final Exception ex) { | ||||||
| 	public CompletableFuture<@NotNull List<@NotNull Class<? extends PlaceholderExpansion>>> findExpansionsOnDisk() |         throw new CompletionException(ex); | ||||||
| 	{ |       } | ||||||
| 		return Arrays.stream(folder.listFiles((dir, name) -> name.endsWith(".jar"))) |     }); | ||||||
| 					 .map(this::findExpansionInFile) |   } | ||||||
| 					 .collect(Futures.collector()); |  | ||||||
| 	} |  | ||||||
|  |   @Nullable | ||||||
| 	@NotNull |   public PlaceholderExpansion createExpansionInstance( | ||||||
| 	public CompletableFuture<@Nullable Class<? extends PlaceholderExpansion>> findExpansionInFile(@NotNull final File file) |       @NotNull final Class<? extends PlaceholderExpansion> clazz) throws LinkageError { | ||||||
| 	{ |     try { | ||||||
| 		return CompletableFuture.supplyAsync(() -> { |       return clazz.getDeclaredConstructor().newInstance(); | ||||||
| 			try |     } catch (final Exception ex) { | ||||||
| 			{ |       if (ex.getCause() instanceof LinkageError) { | ||||||
| 				return FileUtil.findClass(file, PlaceholderExpansion.class); |         throw ((LinkageError) ex.getCause()); | ||||||
| 			} |       } | ||||||
| 			catch (final VerifyError ex) |  | ||||||
| 			{ |       plugin.getLogger() | ||||||
| 				plugin.getLogger().severe("expansion file " + file.getName() + " is outdated: \n" + |           .log(Level.SEVERE, "Failed to load placeholder expansion from class: " + clazz.getName(), | ||||||
| 										  "Failed to load due to a [" + ex.getClass().getSimpleName() + "], attempted to use" + ex.getMessage().substring(ex.getMessage().lastIndexOf(' '))); |               ex); | ||||||
| 				return null; |       return null; | ||||||
| 			} |     } | ||||||
| 			catch (final Exception ex) |   } | ||||||
| 			{ |  | ||||||
| 				throw new CompletionException(ex); |  | ||||||
| 			} |   @EventHandler | ||||||
| 		}); |   public void onQuit(@NotNull final PlayerQuitEvent event) { | ||||||
| 	} |     for (final PlaceholderExpansion expansion : getExpansions()) { | ||||||
|  |       if (!(expansion instanceof Cleanable)) { | ||||||
|  |         continue; | ||||||
| 	@Nullable |       } | ||||||
| 	public PlaceholderExpansion createExpansionInstance(@NotNull final Class<? extends PlaceholderExpansion> clazz) throws LinkageError |  | ||||||
| 	{ |       ((Cleanable) expansion).cleanup(event.getPlayer()); | ||||||
| 		try |     } | ||||||
| 		{ |   } | ||||||
| 			return clazz.getDeclaredConstructor().newInstance(); |  | ||||||
| 		} |   @EventHandler(priority = EventPriority.HIGH) | ||||||
| 		catch (final Exception ex) |   public void onPluginDisable(@NotNull final PluginDisableEvent event) { | ||||||
| 		{ |     final String name = event.getPlugin().getName(); | ||||||
| 			if (ex.getCause() instanceof LinkageError) |     if (name.equals(plugin.getName())) { | ||||||
| 			{ |       return; | ||||||
| 				throw ((LinkageError) ex.getCause()); |     } | ||||||
| 			} |  | ||||||
|  |     for (final PlaceholderExpansion expansion : getExpansions()) { | ||||||
| 			plugin.getLogger().log(Level.SEVERE, "Failed to load placeholder expansion from class: " + clazz.getName(), ex); |       if (!name.equalsIgnoreCase(expansion.getRequiredPlugin())) { | ||||||
| 			return null; |         continue; | ||||||
| 		} |       } | ||||||
| 	} |  | ||||||
|  |       expansion.unregister(); | ||||||
|  |       plugin.getLogger().info("Unregistered placeholder expansion: " + expansion.getName()); | ||||||
| 	@EventHandler |     } | ||||||
| 	public void onQuit(@NotNull final PlayerQuitEvent event) |   } | ||||||
| 	{ |  | ||||||
| 		for (final PlaceholderExpansion expansion : getExpansions()) |  | ||||||
| 		{ |  | ||||||
| 			if (!(expansion instanceof Cleanable)) |  | ||||||
| 			{ |  | ||||||
| 				continue; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			((Cleanable) expansion).cleanup(event.getPlayer()); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@EventHandler(priority = EventPriority.HIGH) |  | ||||||
| 	public void onPluginDisable(@NotNull final PluginDisableEvent event) |  | ||||||
| 	{ |  | ||||||
| 		final String name = event.getPlugin().getName(); |  | ||||||
| 		if (name.equals(plugin.getName())) |  | ||||||
| 		{ |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		for (final PlaceholderExpansion expansion : getExpansions()) |  | ||||||
| 		{ |  | ||||||
| 			if (!name.equalsIgnoreCase(expansion.getRequiredPlugin())) |  | ||||||
| 			{ |  | ||||||
| 				continue; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			expansion.unregister(); |  | ||||||
| 			plugin.getLogger().info("Unregistered placeholder expansion: " + expansion.getName()); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ | |||||||
|  */ |  */ | ||||||
|  |  | ||||||
| package me.clip.placeholderapi.libs; | package me.clip.placeholderapi.libs; | ||||||
|  |  | ||||||
| import com.google.common.base.Strings; | import com.google.common.base.Strings; | ||||||
| import com.google.common.collect.BiMap; | import com.google.common.collect.BiMap; | ||||||
| import com.google.common.collect.ImmutableBiMap; | import com.google.common.collect.ImmutableBiMap; | ||||||
| @@ -16,11 +17,6 @@ import com.google.gson.JsonArray; | |||||||
| import com.google.gson.JsonElement; | import com.google.gson.JsonElement; | ||||||
| import com.google.gson.JsonObject; | import com.google.gson.JsonObject; | ||||||
| import com.google.gson.JsonPrimitive; | import com.google.gson.JsonPrimitive; | ||||||
|  |  | ||||||
| import org.bukkit.Bukkit; |  | ||||||
| import org.bukkit.ChatColor; |  | ||||||
| import org.bukkit.entity.Player; |  | ||||||
|  |  | ||||||
| import java.lang.invoke.MethodHandle; | import java.lang.invoke.MethodHandle; | ||||||
| import java.lang.invoke.MethodHandles; | import java.lang.invoke.MethodHandles; | ||||||
| import java.lang.reflect.Constructor; | import java.lang.reflect.Constructor; | ||||||
| @@ -31,15 +27,19 @@ import java.util.List; | |||||||
| import java.util.Objects; | import java.util.Objects; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
| import java.util.Vector; | import java.util.Vector; | ||||||
|  | import org.bukkit.Bukkit; | ||||||
|  | import org.bukkit.ChatColor; | ||||||
|  | import org.bukkit.entity.Player; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * This is a complete JSON message builder class. To create a new JSONMessage do |  * This is a complete JSON message builder class. To create a new JSONMessage do {@link | ||||||
|  * {@link #create(String)} |  * #create(String)} | ||||||
|  * |  * | ||||||
|  * @author Rayzr |  * @author Rayzr | ||||||
|  */ |  */ | ||||||
| @SuppressWarnings({"WeakerAccess", "unused"}) | @SuppressWarnings({"WeakerAccess", "unused"}) | ||||||
| public class JSONMessage { | public class JSONMessage { | ||||||
|  |  | ||||||
|   private static final BiMap<ChatColor, String> stylesToNames; |   private static final BiMap<ChatColor, String> stylesToNames; | ||||||
|  |  | ||||||
|   static { |   static { | ||||||
| @@ -106,7 +106,8 @@ public class JSONMessage { | |||||||
|    * @param players The players you want to send it to |    * @param players The players you want to send it to | ||||||
|    */ |    */ | ||||||
|   public static void actionbar(String message, Player... players) { |   public static void actionbar(String message, Player... players) { | ||||||
|     ReflectionHelper.sendPacket(ReflectionHelper.createActionbarPacket(ChatColor.translateAlternateColorCodes('&', message)), players); |     ReflectionHelper.sendPacket(ReflectionHelper | ||||||
|  |         .createActionbarPacket(ChatColor.translateAlternateColorCodes('&', message)), players); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
| @@ -142,8 +143,8 @@ public class JSONMessage { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Converts this {@link JSONMessage} object to a String representation of the JSON. |    * Converts this {@link JSONMessage} object to a String representation of the JSON. This is an | ||||||
|    * This is an alias of {@code toJSON().toString()}. |    * alias of {@code toJSON().toString()}. | ||||||
|    */ |    */ | ||||||
|   @Override |   @Override | ||||||
|   public String toString() { |   public String toString() { | ||||||
| @@ -151,8 +152,8 @@ public class JSONMessage { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Converts this {@link JSONMessage} object to the legacy formatting system, which |    * Converts this {@link JSONMessage} object to the legacy formatting system, which uses formatting | ||||||
|    * uses formatting codes (like &6, &l, &4, etc.) |    * codes (like &6, &l, &4, etc.) | ||||||
|    * |    * | ||||||
|    * @return This {@link JSONMessage} instance {@link JSONMessage} in legacy format |    * @return This {@link JSONMessage} instance {@link JSONMessage} in legacy format | ||||||
|    */ |    */ | ||||||
| @@ -183,18 +184,20 @@ public class JSONMessage { | |||||||
|   /** |   /** | ||||||
|    * Sends this as a title to all the players specified |    * Sends this as a title to all the players specified | ||||||
|    * |    * | ||||||
|    * @param fadeIn  How many ticks to fade in |    * @param fadeIn How many ticks to fade in | ||||||
|    * @param stay    How many ticks to stay |    * @param stay How many ticks to stay | ||||||
|    * @param fadeOut How many ticks to fade out |    * @param fadeOut How many ticks to fade out | ||||||
|    * @param players The players to send this to |    * @param players The players to send this to | ||||||
|    */ |    */ | ||||||
|   public void title(int fadeIn, int stay, int fadeOut, Player... players) { |   public void title(int fadeIn, int stay, int fadeOut, Player... players) { | ||||||
|     ReflectionHelper.sendPacket(ReflectionHelper.createTitleTimesPacket(fadeIn, stay, fadeOut), players); |     ReflectionHelper | ||||||
|  |         .sendPacket(ReflectionHelper.createTitleTimesPacket(fadeIn, stay, fadeOut), players); | ||||||
|     ReflectionHelper.sendPacket(ReflectionHelper.createTitlePacket(toString()), players); |     ReflectionHelper.sendPacket(ReflectionHelper.createTitlePacket(toString()), players); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Sends this as a subtitle to all the players specified. Must be used after sending a {@link #title(int, int, int, Player...) title}. |    * Sends this as a subtitle to all the players specified. Must be used after sending a {@link | ||||||
|  |    * #title(int, int, int, Player...) title}. | ||||||
|    * |    * | ||||||
|    * @param players The players to send this to |    * @param players The players to send this to | ||||||
|    */ |    */ | ||||||
| @@ -218,8 +221,9 @@ public class JSONMessage { | |||||||
|    * @return This {@link JSONMessage} instance |    * @return This {@link JSONMessage} instance | ||||||
|    */ |    */ | ||||||
|   public JSONMessage color(ChatColor color) { |   public JSONMessage color(ChatColor color) { | ||||||
|     if (!color.isColor()) |     if (!color.isColor()) { | ||||||
|       throw new IllegalArgumentException(color.name() + " is not a color."); |       throw new IllegalArgumentException(color.name() + " is not a color."); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     last().setColor(color); |     last().setColor(color); | ||||||
|     return this; |     return this; | ||||||
| @@ -227,7 +231,8 @@ public class JSONMessage { | |||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Sets the color of the current message part. |    * Sets the color of the current message part. | ||||||
|    * <br>If the provided color is a hex color ({@code #rrggbb}) but the major version of MC is older than 1.16 will this |    * <br>If the provided color is a hex color ({@code #rrggbb}) but the major version of MC is older | ||||||
|  |    * than 1.16 will this | ||||||
|    * default to the color WHITE. |    * default to the color WHITE. | ||||||
|    * |    * | ||||||
|    * @param color The color to set |    * @param color The color to set | ||||||
| @@ -239,16 +244,18 @@ public class JSONMessage { | |||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Sets the color of the current message part. |    * Sets the color of the current message part. | ||||||
|    * <br>If the provided color is a hex color ({@code #rrggbb}) but the major version of MC is older than 1.16 will the provided |    * <br>If the provided color is a hex color ({@code #rrggbb}) but the major version of MC is older | ||||||
|  |    * than 1.16 will the provided | ||||||
|    * default ChatColor be used instead. |    * default ChatColor be used instead. | ||||||
|    * |    * | ||||||
|    * @param color The color to set |    * @param color The color to set | ||||||
|    * @param def   The default ChatColor to use, when MC version is older than 1.16 |    * @param def The default ChatColor to use, when MC version is older than 1.16 | ||||||
|    * @return This {@link JSONMessage} instance |    * @return This {@link JSONMessage} instance | ||||||
|    */ |    */ | ||||||
|   public JSONMessage color(String color, ChatColor def) { |   public JSONMessage color(String color, ChatColor def) { | ||||||
|     if (color.startsWith("#") && ReflectionHelper.MAJOR_VER < 16) |     if (color.startsWith("#") && ReflectionHelper.MAJOR_VER < 16) { | ||||||
|       return color(def); |       return color(def); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     last().setColor(color); |     last().setColor(color); | ||||||
|     return this; |     return this; | ||||||
| @@ -262,8 +269,9 @@ public class JSONMessage { | |||||||
|    * @return This {@link JSONMessage} instance |    * @return This {@link JSONMessage} instance | ||||||
|    */ |    */ | ||||||
|   public JSONMessage font(String font) { |   public JSONMessage font(String font) { | ||||||
|     if (ReflectionHelper.MAJOR_VER < 16) |     if (ReflectionHelper.MAJOR_VER < 16) { | ||||||
|       return this; |       return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     last().setFont(font); |     last().setFont(font); | ||||||
|     return this; |     return this; | ||||||
| @@ -315,7 +323,8 @@ public class JSONMessage { | |||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Copies the provided text to the Clipboard of the player. |    * Copies the provided text to the Clipboard of the player. | ||||||
|    * <br>When this is used on versions older than 1.15 will this default to {@link #suggestCommand(String) suggestCommand(String)}. |    * <br>When this is used on versions older than 1.15 will this default to {@link | ||||||
|  |    * #suggestCommand(String) suggestCommand(String)}. | ||||||
|    * |    * | ||||||
|    * @param text The text to copy |    * @param text The text to copy | ||||||
|    * @return This {@link JSONMessage} instance |    * @return This {@link JSONMessage} instance | ||||||
| @@ -326,8 +335,8 @@ public class JSONMessage { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Changes the page of a book. Using this in a non-book context is useless |    * Changes the page of a book. Using this in a non-book context is useless and will probably | ||||||
|    * and will probably error. |    * error. | ||||||
|    * |    * | ||||||
|    * @param page The page to change to |    * @param page The page to change to | ||||||
|    * @return This {@link JSONMessage} instance |    * @return This {@link JSONMessage} instance | ||||||
| @@ -398,12 +407,13 @@ public class JSONMessage { | |||||||
|    * @return This {@link JSONMessage} instance |    * @return This {@link JSONMessage} instance | ||||||
|    */ |    */ | ||||||
|   public JSONMessage bar(int length) { |   public JSONMessage bar(int length) { | ||||||
|     return then(Strings.repeat("-", length)).color(ChatColor.DARK_GRAY).style(ChatColor.STRIKETHROUGH); |     return then(Strings.repeat("-", length)).color(ChatColor.DARK_GRAY) | ||||||
|  |         .style(ChatColor.STRIKETHROUGH); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Adds a horizontal bar to the message that's 53 characters long. This is |    * Adds a horizontal bar to the message that's 53 characters long. This is the default width of | ||||||
|    * the default width of the player's chat window. |    * the player's chat window. | ||||||
|    * |    * | ||||||
|    * @return This {@link JSONMessage} instance |    * @return This {@link JSONMessage} instance | ||||||
|    */ |    */ | ||||||
| @@ -450,7 +460,8 @@ public class JSONMessage { | |||||||
|  |  | ||||||
|         if (current >= parts.size() || totalLineLength + rawLength >= 53) { |         if (current >= parts.size() || totalLineLength + rawLength >= 53) { | ||||||
|           int padding = Math.max(0, (53 - totalLineLength) / 2); |           int padding = Math.max(0, (53 - totalLineLength) / 2); | ||||||
|           currentLine.firstElement().setText(Strings.repeat(" ", padding) + currentLine.firstElement().getText()); |           currentLine.firstElement() | ||||||
|  |               .setText(Strings.repeat(" ", padding) + currentLine.firstElement().getText()); | ||||||
|           currentLine.lastElement().setText(currentLine.lastElement().getText() + "\n"); |           currentLine.lastElement().setText(currentLine.lastElement().getText() + "\n"); | ||||||
|           currentLine.clear(); |           currentLine.clear(); | ||||||
|           break; |           break; | ||||||
| @@ -501,7 +512,8 @@ public class JSONMessage { | |||||||
|        * MC 1.16 changed "value" to "contents", but only for Hover events... Don't ask why. |        * MC 1.16 changed "value" to "contents", but only for Hover events... Don't ask why. | ||||||
|        * Since this lib only has tooltip and achievement can we simply check if action starts with "show_" |        * Since this lib only has tooltip and achievement can we simply check if action starts with "show_" | ||||||
|        */ |        */ | ||||||
|       String valueType = (ReflectionHelper.MAJOR_VER >= 16 && action.startsWith("show_")) ? "contents" : "value"; |       String valueType = | ||||||
|  |           (ReflectionHelper.MAJOR_VER >= 16 && action.startsWith("show_")) ? "contents" : "value"; | ||||||
|  |  | ||||||
|       if (value instanceof JsonElement) { |       if (value instanceof JsonElement) { | ||||||
|         obj.add(valueType, (JsonElement) value); |         obj.add(valueType, (JsonElement) value); | ||||||
| @@ -585,14 +597,16 @@ public class JSONMessage { | |||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Copies the provided text to the clipboard of the player. |      * Copies the provided text to the clipboard of the player. | ||||||
|      * <br>When used on versions older than 1.15 will this {@link #suggestCommand(String) suggest the text} instead. |      * <br>When used on versions older than 1.15 will this {@link #suggestCommand(String) suggest | ||||||
|  |      * the text} instead. | ||||||
|      * |      * | ||||||
|      * @param text The text to copy. |      * @param text The text to copy. | ||||||
|      * @return The {@link MessageEvent} |      * @return The {@link MessageEvent} | ||||||
|      */ |      */ | ||||||
|     public static MessageEvent copyText(String text) { |     public static MessageEvent copyText(String text) { | ||||||
|       if (ReflectionHelper.MAJOR_VER < 15) |       if (ReflectionHelper.MAJOR_VER < 15) { | ||||||
|         return suggestCommand(text); |         return suggestCommand(text); | ||||||
|  |       } | ||||||
|  |  | ||||||
|       return new MessageEvent("copy_to_clipboard", text); |       return new MessageEvent("copy_to_clipboard", text); | ||||||
|     } |     } | ||||||
| @@ -681,7 +695,8 @@ public class JSONMessage { | |||||||
|         if (MAJOR_VER < 8) { |         if (MAJOR_VER < 8) { | ||||||
|           stringToChat = getClass("{nms}.ChatSerializer").getMethod("a", String.class); |           stringToChat = getClass("{nms}.ChatSerializer").getMethod("a", String.class); | ||||||
|         } else { |         } else { | ||||||
|           stringToChat = getClass("{nms}.IChatBaseComponent$ChatSerializer").getMethod("a", String.class); |           stringToChat = getClass("{nms}.IChatBaseComponent$ChatSerializer") | ||||||
|  |               .getMethod("a", String.class); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         GET_HANDLE = MethodHandles.lookup().unreflect(getHandle); |         GET_HANDLE = MethodHandles.lookup().unreflect(getHandle); | ||||||
| @@ -697,7 +712,8 @@ public class JSONMessage { | |||||||
|         Class<?> titleAction = getClass("{nms}.PacketPlayOutTitle$EnumTitleAction"); |         Class<?> titleAction = getClass("{nms}.PacketPlayOutTitle$EnumTitleAction"); | ||||||
|  |  | ||||||
|         titlePacketConstructor = packetPlayOutTitle.getConstructor(titleAction, iChatBaseComponent); |         titlePacketConstructor = packetPlayOutTitle.getConstructor(titleAction, iChatBaseComponent); | ||||||
|         titleTimesPacketConstructor = packetPlayOutTitle.getConstructor(int.class, int.class, int.class); |         titleTimesPacketConstructor = packetPlayOutTitle | ||||||
|  |             .getConstructor(int.class, int.class, int.class); | ||||||
|  |  | ||||||
|         enumActionTitle = titleAction.getField("TITLE").get(null); |         enumActionTitle = titleAction.getField("TITLE").get(null); | ||||||
|         enumActionSubtitle = titleAction.getField("SUBTITLE").get(null); |         enumActionSubtitle = titleAction.getField("SUBTITLE").get(null); | ||||||
| @@ -832,7 +848,8 @@ public class JSONMessage { | |||||||
|      * Attempts to convert a String representing a JSON message into a usable object |      * Attempts to convert a String representing a JSON message into a usable object | ||||||
|      * |      * | ||||||
|      * @param json The JSON to attempt to parse |      * @param json The JSON to attempt to parse | ||||||
|      * @return The object representing the text in JSON form, or <code>null</code> if something went wrong converting the String to JSON data |      * @return The object representing the text in JSON form, or <code>null</code> if something went | ||||||
|  |      * wrong converting the String to JSON data | ||||||
|      */ |      */ | ||||||
|     static Object fromJson(String json) { |     static Object fromJson(String json) { | ||||||
|       assertIsSetup(); |       assertIsSetup(); | ||||||
| @@ -856,7 +873,8 @@ public class JSONMessage { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     private static Class<?> getClass(String path) throws ClassNotFoundException { |     private static Class<?> getClass(String path) throws ClassNotFoundException { | ||||||
|       return Class.forName(path.replace("{nms}", "net.minecraft.server." + version).replace("{obc}", "org.bukkit.craftbukkit." + version)); |       return Class.forName(path.replace("{nms}", "net.minecraft.server." + version) | ||||||
|  |           .replace("{obc}", "org.bukkit.craftbukkit." + version)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private static void setFieldValue(Field field, Object instance, Object value) { |     private static void setFieldValue(Field field, Object instance, Object value) { | ||||||
| @@ -889,7 +907,8 @@ public class JSONMessage { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Defines a section of the message, and represents the format that all JSON messages must follow in Minecraft. |    * Defines a section of the message, and represents the format that all JSON messages must follow | ||||||
|  |    * in Minecraft. | ||||||
|    * <br> |    * <br> | ||||||
|    * <br> |    * <br> | ||||||
|    * <a href="http://minecraft.gamepedia.com/Commands#Raw_JSON_text">Reference</a> |    * <a href="http://minecraft.gamepedia.com/Commands#Raw_JSON_text">Reference</a> | ||||||
| @@ -1008,8 +1027,10 @@ public class JSONMessage { | |||||||
|         return legacyColor; |         return legacyColor; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       if (this.color.startsWith("#") && ReflectionHelper.MAJOR_VER < 16) |       if (this.color.startsWith("#") && ReflectionHelper.MAJOR_VER < 16) { | ||||||
|         throw new IllegalStateException("Custom Hex colors can only be used in Minecraft 1.16 or newer!"); |         throw new IllegalStateException( | ||||||
|  |             "Custom Hex colors can only be used in Minecraft 1.16 or newer!"); | ||||||
|  |       } | ||||||
|  |  | ||||||
|       try { |       try { | ||||||
|         return ChatColor.valueOf(this.color.toUpperCase()); |         return ChatColor.valueOf(this.color.toUpperCase()); | ||||||
| @@ -1028,15 +1049,6 @@ public class JSONMessage { | |||||||
|       setLegacyColor(color); |       setLegacyColor(color); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * @param color The legacy ChatColor to set |  | ||||||
|      * @deprecated Use {@link #setColor(String)} instead |  | ||||||
|      */ |  | ||||||
|     @Deprecated |  | ||||||
|     public void setLegacyColor(ChatColor color) { |  | ||||||
|       legacyColor = color; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * @param color The color to set |      * @param color The color to set | ||||||
|      */ |      */ | ||||||
| @@ -1047,6 +1059,15 @@ public class JSONMessage { | |||||||
|       this.color = color; |       this.color = color; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param color The legacy ChatColor to set | ||||||
|  |      * @deprecated Use {@link #setColor(String)} instead | ||||||
|  |      */ | ||||||
|  |     @Deprecated | ||||||
|  |     public void setLegacyColor(ChatColor color) { | ||||||
|  |       legacyColor = color; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * @return The list of styles |      * @return The list of styles | ||||||
|      */ |      */ | ||||||
|   | |||||||
| @@ -28,34 +28,31 @@ import org.bukkit.event.Listener; | |||||||
| import org.bukkit.event.server.ServerLoadEvent; | import org.bukkit.event.server.ServerLoadEvent; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
| public final class ServerLoadEventListener implements Listener | public final class ServerLoadEventListener implements Listener { | ||||||
| { |  | ||||||
|  |  | ||||||
|     @NotNull |   @NotNull | ||||||
| 	private final PlaceholderAPIPlugin plugin; |   private final PlaceholderAPIPlugin plugin; | ||||||
|  |  | ||||||
| 	public ServerLoadEventListener(@NotNull final PlaceholderAPIPlugin plugin) |   public ServerLoadEventListener(@NotNull final PlaceholderAPIPlugin plugin) { | ||||||
| 	{ |     this.plugin = plugin; | ||||||
|         this.plugin = plugin; |  | ||||||
|  |  | ||||||
| 		Bukkit.getPluginManager().registerEvents(this, plugin); |     Bukkit.getPluginManager().registerEvents(this, plugin); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	/** |   /** | ||||||
| 	 * This method will be called when the server is first loaded |    * This method will be called when the server is first loaded | ||||||
| 	 * <p> |    * <p> | ||||||
| 	 * The goal of the method is to register all the expansions as soon as possible |    * The goal of the method is to register all the expansions as soon as possible especially before | ||||||
| 	 * especially before players can join |    * players can join | ||||||
| 	 * <p> |    * <p> | ||||||
| 	 * This will ensure no issues with expansions and hooks. |    * This will ensure no issues with expansions and hooks. | ||||||
| 	 * |    * | ||||||
| 	 * @param event the server load event |    * @param event the server load event | ||||||
| 	 */ |    */ | ||||||
| 	@EventHandler |   @EventHandler | ||||||
| 	public void onServerLoad(@NotNull final ServerLoadEvent event) |   public void onServerLoad(@NotNull final ServerLoadEvent event) { | ||||||
| 	{ |     HandlerList.unregisterAll(this); | ||||||
|         HandlerList.unregisterAll(this); |     plugin.getLocalExpansionManager().load(Bukkit.getConsoleSender()); | ||||||
|         plugin.getLocalExpansionManager().load(Bukkit.getConsoleSender()); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,181 +20,159 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.replacer; | package me.clip.placeholderapi.replacer; | ||||||
|  |  | ||||||
|  | import java.util.function.Function; | ||||||
| import me.clip.placeholderapi.expansion.PlaceholderExpansion; | import me.clip.placeholderapi.expansion.PlaceholderExpansion; | ||||||
| import org.bukkit.ChatColor; | import org.bukkit.ChatColor; | ||||||
| import org.bukkit.OfflinePlayer; | import org.bukkit.OfflinePlayer; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
| import java.util.function.Function; | public final class CharsReplacer implements Replacer { | ||||||
|  |  | ||||||
| public final class CharsReplacer implements Replacer |   @NotNull | ||||||
| { |   private final Closure closure; | ||||||
|  |  | ||||||
| 	@NotNull |   public CharsReplacer(@NotNull final Closure closure) { | ||||||
| 	private final Closure closure; |     this.closure = closure; | ||||||
|  |   } | ||||||
| 	public CharsReplacer(@NotNull final Closure closure) |  | ||||||
| 	{ |  | ||||||
| 		this.closure = closure; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	@Override |   @Override | ||||||
| 	public String apply(@NotNull final String text, @Nullable final OfflinePlayer player, @NotNull final Function<String, @Nullable PlaceholderExpansion> lookup) |   public String apply(@NotNull final String text, @Nullable final OfflinePlayer player, | ||||||
| 	{ |       @NotNull final Function<String, @Nullable PlaceholderExpansion> lookup) { | ||||||
| 		final char[]        chars   = text.toCharArray(); |     final char[] chars = text.toCharArray(); | ||||||
| 		final StringBuilder builder = new StringBuilder(text.length()); |     final StringBuilder builder = new StringBuilder(text.length()); | ||||||
|  |  | ||||||
| 		final StringBuilder identifier = new StringBuilder(); |     final StringBuilder identifier = new StringBuilder(); | ||||||
| 		final StringBuilder parameters = new StringBuilder(); |     final StringBuilder parameters = new StringBuilder(); | ||||||
|  |  | ||||||
| 		for (int i = 0; i < chars.length; i++) |     for (int i = 0; i < chars.length; i++) { | ||||||
| 		{ |       final char l = chars[i]; | ||||||
| 			final char l = chars[i]; |  | ||||||
|  |  | ||||||
| 			if (l == '&' && ++i < chars.length) |       if (l == '&' && ++i < chars.length) { | ||||||
| 			{ |         final char c = Character.toLowerCase(chars[i]); | ||||||
| 				final char c = Character.toLowerCase(chars[i]); |  | ||||||
|  |  | ||||||
| 				if (c != '0' && c != '1' && c != '2' && c != '3' && c != '4' && c != '5' && c != '6' && c != '7' && c != '8' && c != '9' && c != 'a' && c != 'b' && c != 'c' && c != 'd' && c != 'e' && c != 'f' && c != 'k' && c != 'l' && c != 'm' && c != 'o' && c != 'r' && c != 'x') |         if (c != '0' && c != '1' && c != '2' && c != '3' && c != '4' && c != '5' && c != '6' | ||||||
| 				{ |             && c != '7' && c != '8' && c != '9' && c != 'a' && c != 'b' && c != 'c' && c != 'd' | ||||||
| 					builder.append(l).append(chars[i]); |             && c != 'e' && c != 'f' && c != 'k' && c != 'l' && c != 'm' && c != 'n' && c != 'o' && c != 'r' | ||||||
| 				} |             && c != 'x') { | ||||||
| 				else |           builder.append(l).append(chars[i]); | ||||||
| 				{ |         } else { | ||||||
| 					builder.append(ChatColor.COLOR_CHAR); |           builder.append(ChatColor.COLOR_CHAR); | ||||||
|  |  | ||||||
| 					if (c != 'x') |           if (c != 'x') { | ||||||
| 					{ |             builder.append(chars[i]); | ||||||
| 						builder.append(chars[i]); |             continue; | ||||||
| 						continue; |           } | ||||||
| 					} |  | ||||||
|  |  | ||||||
| 					if ((i > 1 && chars[i - 2] == '\\') /*allow escaping &x*/) |           if ((i > 1 && chars[i - 2] == '\\') /*allow escaping &x*/) { | ||||||
| 					{ |             builder.setLength(builder.length() - 2); | ||||||
| 						builder.setLength(builder.length() - 2); |             builder.append('&').append(chars[i]); | ||||||
| 						builder.append('&').append(chars[i]); |             continue; | ||||||
| 						continue; |           } | ||||||
| 					} |  | ||||||
|  |  | ||||||
| 					builder.append(c); |           builder.append(c); | ||||||
|  |  | ||||||
| 					int j = 0; |           int j = 0; | ||||||
| 					while (++j <= 6) |           while (++j <= 6) { | ||||||
| 					{ |             if (i + j >= chars.length) { | ||||||
| 						if (i + j >= chars.length) |               break; | ||||||
| 						{ |             } | ||||||
| 							break; |  | ||||||
| 						} |  | ||||||
|  |  | ||||||
| 						final char x = chars[i + j]; |             final char x = chars[i + j]; | ||||||
| 						builder.append(ChatColor.COLOR_CHAR).append(x); |             builder.append(ChatColor.COLOR_CHAR).append(x); | ||||||
| 					} |           } | ||||||
|  |  | ||||||
| 					if (j == 7) |           if (j == 7) { | ||||||
| 					{ |             i += 6; | ||||||
| 						i += 6; |           } else { | ||||||
| 					} |             builder.setLength(builder.length() - (j * 2)); // undo &x parsing | ||||||
| 					else |           } | ||||||
| 					{ |         } | ||||||
| 						builder.setLength(builder.length() - (j * 2)); // undo &x parsing |         continue; | ||||||
| 					} |       } | ||||||
| 				} |  | ||||||
| 				continue; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if (l != closure.head || i + 1 >= chars.length) |       if (l != closure.head || i + 1 >= chars.length) { | ||||||
| 			{ |         builder.append(l); | ||||||
| 				builder.append(l); |         continue; | ||||||
| 				continue; |       } | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			boolean identified = false; |       boolean identified = false; | ||||||
| 			boolean oopsitsbad = true; |       boolean oopsitsbad = true; | ||||||
|  |       boolean hadSpace = false; | ||||||
|  |  | ||||||
| 			while (++i < chars.length) |       while (++i < chars.length) { | ||||||
| 			{ |         final char p = chars[i]; | ||||||
| 				final char p = chars[i]; |  | ||||||
|  |  | ||||||
| 				if (p == ' ' && !identified) |         if (p == ' ' && !identified) { | ||||||
| 				{ |           hadSpace = true; | ||||||
| 					break; |           break; | ||||||
| 				} |         } | ||||||
| 				if (p == closure.tail) |         if (p == closure.tail) { | ||||||
| 				{ |           oopsitsbad = false; | ||||||
| 					oopsitsbad = false; |           break; | ||||||
| 					break; |         } | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				if (p == '_' && !identified) |         if (p == '_' && !identified) { | ||||||
| 				{ |           identified = true; | ||||||
| 					identified = true; |           continue; | ||||||
| 					continue; |         } | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				if (identified) |         if (identified) { | ||||||
| 				{ |           parameters.append(p); | ||||||
| 					parameters.append(p); |         } else { | ||||||
| 				} |           identifier.append(p); | ||||||
| 				else |         } | ||||||
| 				{ |       } | ||||||
| 					identifier.append(p); |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			final String identifierString = identifier.toString().toLowerCase(); |       final String identifierString = identifier.toString().toLowerCase(); | ||||||
| 			final String parametersString = parameters.toString(); |       final String parametersString = parameters.toString(); | ||||||
|  |  | ||||||
| 			identifier.setLength(0); |       identifier.setLength(0); | ||||||
| 			parameters.setLength(0); |       parameters.setLength(0); | ||||||
|  |  | ||||||
| 			if (oopsitsbad) |       if (oopsitsbad) { | ||||||
| 			{ |         builder.append(closure.head).append(identifierString); | ||||||
| 				builder.append(closure.head).append(identifierString); |  | ||||||
|  |  | ||||||
| 				if (identified) |         if (identified) { | ||||||
| 				{ |           builder.append('_').append(parametersString); | ||||||
| 					builder.append('_').append(parametersString); |         } | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				builder.append(' '); |         if (hadSpace) { | ||||||
| 				continue; |           builder.append(' '); | ||||||
| 			} |         } | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  |  | ||||||
| 			final PlaceholderExpansion placeholder = lookup.apply(identifierString); |       final PlaceholderExpansion placeholder = lookup.apply(identifierString); | ||||||
| 			if (placeholder == null) |       if (placeholder == null) { | ||||||
| 			{ |         builder.append(closure.head).append(identifierString); | ||||||
| 				builder.append(closure.head).append(identifierString); |  | ||||||
|  |  | ||||||
| 				if (identified) |         if (identified) { | ||||||
| 				{ |           builder.append('_'); | ||||||
| 					builder.append('_'); |         } | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				builder.append(parametersString).append(closure.tail); |         builder.append(parametersString).append(closure.tail); | ||||||
| 				continue; |         continue; | ||||||
| 			} |       } | ||||||
|  |  | ||||||
| 			final String replacement = placeholder.onRequest(player, parametersString); |       final String replacement = placeholder.onRequest(player, parametersString); | ||||||
| 			if (replacement == null) |       if (replacement == null) { | ||||||
| 			{ |         builder.append(closure.head).append(identifierString); | ||||||
| 				builder.append(closure.head).append(identifierString); |  | ||||||
|  |  | ||||||
| 				if (identified) |         if (identified) { | ||||||
| 				{ |           builder.append('_'); | ||||||
| 					builder.append('_'); |         } | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				builder.append(parametersString).append(closure.tail); |         builder.append(parametersString).append(closure.tail); | ||||||
| 				continue; |         continue; | ||||||
| 			} |       } | ||||||
|  |  | ||||||
| 			builder.append(ChatColor.translateAlternateColorCodes('&', replacement)); |       builder.append(ChatColor.translateAlternateColorCodes('&', replacement)); | ||||||
| 		} |     } | ||||||
|  |  | ||||||
| 		return builder.toString(); |     return builder.toString(); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,57 +20,53 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.replacer; | package me.clip.placeholderapi.replacer; | ||||||
|  |  | ||||||
|  | import java.util.function.Function; | ||||||
|  | import java.util.regex.Matcher; | ||||||
|  | import java.util.regex.Pattern; | ||||||
| import me.clip.placeholderapi.expansion.PlaceholderExpansion; | import me.clip.placeholderapi.expansion.PlaceholderExpansion; | ||||||
| import org.bukkit.ChatColor; | import org.bukkit.ChatColor; | ||||||
| import org.bukkit.OfflinePlayer; | import org.bukkit.OfflinePlayer; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
| import java.util.function.Function; | public final class RegexReplacer implements Replacer { | ||||||
| import java.util.regex.Matcher; |  | ||||||
| import java.util.regex.Pattern; |  | ||||||
|  |  | ||||||
| public final class RegexReplacer implements Replacer |   @NotNull | ||||||
| { |   private final Pattern pattern; | ||||||
|  |  | ||||||
| 	@NotNull |   public RegexReplacer(@NotNull final Closure closure) { | ||||||
| 	private final Pattern pattern; |     this.pattern = Pattern.compile(String | ||||||
|  |         .format("\\%s((?<identifier>[a-zA-Z0-9]+)_)(?<parameters>[^%s%s]+)\\%s", closure.head, | ||||||
| 	public RegexReplacer(@NotNull final Closure closure) |             closure.head, closure.tail, closure.tail)); | ||||||
| 	{ |   } | ||||||
| 		this.pattern = Pattern.compile(String.format("\\%s((?<identifier>[a-zA-Z0-9]+)_)(?<parameters>[^%s%s]+)\\%s", closure.head, closure.head, closure.tail, closure.tail)); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	@Override |   @Override | ||||||
| 	public String apply(@NotNull final String text, @Nullable final OfflinePlayer player, @NotNull final Function<String, @Nullable PlaceholderExpansion> lookup) |   public String apply(@NotNull final String text, @Nullable final OfflinePlayer player, | ||||||
| 	{ |       @NotNull final Function<String, @Nullable PlaceholderExpansion> lookup) { | ||||||
| 		final Matcher matcher = pattern.matcher(text); |     final Matcher matcher = pattern.matcher(text); | ||||||
| 		if (!matcher.find()) |     if (!matcher.find()) { | ||||||
| 		{ |       return text; | ||||||
| 			return text; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final StringBuffer builder = new StringBuffer(); |     final StringBuffer builder = new StringBuffer(); | ||||||
|  |  | ||||||
| 		do |     do { | ||||||
| 		{ |       final String identifier = matcher.group("identifier"); | ||||||
| 			final String identifier = matcher.group("identifier"); |       final String parameters = matcher.group("parameters"); | ||||||
| 			final String parameters = matcher.group("parameters"); |  | ||||||
|  |  | ||||||
| 			final PlaceholderExpansion expansion = lookup.apply(identifier); |       final PlaceholderExpansion expansion = lookup.apply(identifier); | ||||||
| 			if (expansion == null) |       if (expansion == null) { | ||||||
| 			{ |         continue; | ||||||
| 				continue; |       } | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			final String requested = expansion.onRequest(player, parameters); |       final String requested = expansion.onRequest(player, parameters); | ||||||
| 			matcher.appendReplacement(builder, requested != null ? requested : matcher.group(0)); |       matcher.appendReplacement(builder, requested != null ? requested : matcher.group(0)); | ||||||
| 		} |     } | ||||||
| 		while (matcher.find()); |     while (matcher.find()); | ||||||
|  |  | ||||||
| 		return ChatColor.translateAlternateColorCodes('&', matcher.appendTail(builder).toString()); |     return ChatColor.translateAlternateColorCodes('&', matcher.appendTail(builder).toString()); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,33 +20,30 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.replacer; | package me.clip.placeholderapi.replacer; | ||||||
|  |  | ||||||
|  | import java.util.function.Function; | ||||||
| import me.clip.placeholderapi.expansion.PlaceholderExpansion; | import me.clip.placeholderapi.expansion.PlaceholderExpansion; | ||||||
| import org.bukkit.OfflinePlayer; | import org.bukkit.OfflinePlayer; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
| import java.util.function.Function; | public interface Replacer { | ||||||
|  |  | ||||||
| public interface Replacer |   @NotNull | ||||||
| { |   String apply(@NotNull final String text, @Nullable final OfflinePlayer player, | ||||||
|  |       @NotNull final Function<String, @Nullable PlaceholderExpansion> lookup); | ||||||
| 	@NotNull |  | ||||||
| 	String apply(@NotNull final String text, @Nullable final OfflinePlayer player, @NotNull final Function<String, @Nullable PlaceholderExpansion> lookup); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	enum Closure |   enum Closure { | ||||||
| 	{ |     BRACKET('{', '}'), | ||||||
| 		BRACKET('{', '}'), |     PERCENT('%', '%'); | ||||||
| 		PERCENT('%', '%'); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 		public final char head, tail; |     public final char head, tail; | ||||||
|  |  | ||||||
| 		Closure(final char head, final char tail) |     Closure(final char head, final char tail) { | ||||||
| 		{ |       this.head = head; | ||||||
| 			this.head = head; |       this.tail = tail; | ||||||
| 			this.tail = tail; |     } | ||||||
| 		} |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,10 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.updatechecker; | package me.clip.placeholderapi.updatechecker; | ||||||
|  |  | ||||||
|  | import java.io.BufferedReader; | ||||||
|  | import java.io.InputStreamReader; | ||||||
|  | import java.net.URL; | ||||||
|  | import javax.net.ssl.HttpsURLConnection; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.util.Msg; | import me.clip.placeholderapi.util.Msg; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| @@ -28,90 +32,85 @@ import org.bukkit.event.EventPriority; | |||||||
| import org.bukkit.event.Listener; | import org.bukkit.event.Listener; | ||||||
| import org.bukkit.event.player.PlayerJoinEvent; | import org.bukkit.event.player.PlayerJoinEvent; | ||||||
|  |  | ||||||
| import javax.net.ssl.HttpsURLConnection; |  | ||||||
| import java.io.BufferedReader; |  | ||||||
| import java.io.InputStreamReader; |  | ||||||
| import java.net.URL; |  | ||||||
|  |  | ||||||
| public class UpdateChecker implements Listener { | public class UpdateChecker implements Listener { | ||||||
|  |  | ||||||
|     private final int RESOURCE_ID = 6245; |   private final int RESOURCE_ID = 6245; | ||||||
|     private final PlaceholderAPIPlugin plugin; |   private final PlaceholderAPIPlugin plugin; | ||||||
|     private final String pluginVersion; |   private final String pluginVersion; | ||||||
|     private String spigotVersion; |   private String spigotVersion; | ||||||
|     private boolean updateAvailable; |   private boolean updateAvailable; | ||||||
|  |  | ||||||
|     public UpdateChecker(PlaceholderAPIPlugin i) { |   public UpdateChecker(PlaceholderAPIPlugin i) { | ||||||
|         plugin = i; |     plugin = i; | ||||||
|         pluginVersion = i.getDescription().getVersion(); |     pluginVersion = i.getDescription().getVersion(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public boolean hasUpdateAvailable() { | ||||||
|  |     return updateAvailable; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getSpigotVersion() { | ||||||
|  |     return spigotVersion; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void fetch() { | ||||||
|  |     Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { | ||||||
|  |       try { | ||||||
|  |         HttpsURLConnection con = (HttpsURLConnection) new URL( | ||||||
|  |             "https://api.spigotmc.org/legacy/update.php?resource=" + RESOURCE_ID).openConnection(); | ||||||
|  |         con.setRequestMethod("GET"); | ||||||
|  |         spigotVersion = new BufferedReader(new InputStreamReader(con.getInputStream())).readLine(); | ||||||
|  |       } catch (Exception ex) { | ||||||
|  |         plugin.getLogger().info("Failed to check for updates on spigot."); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if (spigotVersion == null || spigotVersion.isEmpty()) { | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       updateAvailable = spigotIsNewer(); | ||||||
|  |  | ||||||
|  |       if (!updateAvailable) { | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       Bukkit.getScheduler().runTask(plugin, () -> { | ||||||
|  |         plugin.getLogger() | ||||||
|  |             .info("An update for PlaceholderAPI (v" + getSpigotVersion() + ") is available at:"); | ||||||
|  |         plugin.getLogger() | ||||||
|  |             .info("https://www.spigotmc.org/resources/placeholderapi." + RESOURCE_ID + "/"); | ||||||
|  |         Bukkit.getPluginManager().registerEvents(this, plugin); | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private boolean spigotIsNewer() { | ||||||
|  |     if (spigotVersion == null || spigotVersion.isEmpty()) { | ||||||
|  |       return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public boolean hasUpdateAvailable() { |     String plV = toReadable(pluginVersion); | ||||||
|         return updateAvailable; |     String spV = toReadable(spigotVersion); | ||||||
|  |     return plV.compareTo(spV) < 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private String toReadable(String version) { | ||||||
|  |     if (version.contains("-DEV-")) { | ||||||
|  |       version = version.split("-DEV-")[0]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public String getSpigotVersion() { |     return version.replaceAll("\\.", ""); | ||||||
|         return spigotVersion; |   } | ||||||
|     } |  | ||||||
|  |   @EventHandler(priority = EventPriority.MONITOR) | ||||||
|     public void fetch() { |   public void onJoin(PlayerJoinEvent e) { | ||||||
|         Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { |     if (e.getPlayer().hasPermission("placeholderapi.updatenotify")) { | ||||||
|             try { |       Msg.msg(e.getPlayer(), | ||||||
|                 HttpsURLConnection con = (HttpsURLConnection) new URL( |           "&bAn update for &fPlaceholder&7API &e(&fPlaceholder&7API &fv" + getSpigotVersion() | ||||||
|                         "https://api.spigotmc.org/legacy/update.php?resource=" + RESOURCE_ID).openConnection(); |               + "&e)" | ||||||
|                 con.setRequestMethod("GET"); |           , "&bis available at &ehttps://www.spigotmc.org/resources/placeholderapi." + RESOURCE_ID | ||||||
|                 spigotVersion = new BufferedReader(new InputStreamReader(con.getInputStream())).readLine(); |               + "/"); | ||||||
|             } catch (Exception ex) { |  | ||||||
|                 plugin.getLogger().info("Failed to check for updates on spigot."); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (spigotVersion == null || spigotVersion.isEmpty()) { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             updateAvailable = spigotIsNewer(); |  | ||||||
|  |  | ||||||
|             if (!updateAvailable) { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             Bukkit.getScheduler().runTask(plugin, () -> { |  | ||||||
|                 plugin.getLogger() |  | ||||||
|                         .info("An update for PlaceholderAPI (v" + getSpigotVersion() + ") is available at:"); |  | ||||||
|                 plugin.getLogger() |  | ||||||
|                         .info("https://www.spigotmc.org/resources/placeholderapi." + RESOURCE_ID + "/"); |  | ||||||
|                 Bukkit.getPluginManager().registerEvents(this, plugin); |  | ||||||
|             }); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private boolean spigotIsNewer() { |  | ||||||
|         if (spigotVersion == null || spigotVersion.isEmpty()) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         String plV = toReadable(pluginVersion); |  | ||||||
|         String spV = toReadable(spigotVersion); |  | ||||||
|         return plV.compareTo(spV) < 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private String toReadable(String version) { |  | ||||||
|         if (version.contains("-DEV-")) { |  | ||||||
|             version = version.split("-DEV-")[0]; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return version.replaceAll("\\.", ""); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @EventHandler(priority = EventPriority.MONITOR) |  | ||||||
|     public void onJoin(PlayerJoinEvent e) { |  | ||||||
|         if (e.getPlayer().hasPermission("placeholderapi.updatenotify")) { |  | ||||||
|             Msg.msg(e.getPlayer(), |  | ||||||
|                     "&bAn update for &fPlaceholder&7API &e(&fPlaceholder&7API &fv" + getSpigotVersion() |  | ||||||
|                             + "&e)" |  | ||||||
|                     , "&bis available at &ehttps://www.spigotmc.org/resources/placeholderapi." + RESOURCE_ID |  | ||||||
|                             + "/"); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,9 +20,6 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.util; | package me.clip.placeholderapi.util; | ||||||
|  |  | ||||||
| import org.jetbrains.annotations.NotNull; |  | ||||||
| import org.jetbrains.annotations.Nullable; |  | ||||||
|  |  | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.net.URL; | import java.net.URL; | ||||||
| @@ -31,54 +28,48 @@ import java.util.ArrayList; | |||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.jar.JarEntry; | import java.util.jar.JarEntry; | ||||||
| import java.util.jar.JarInputStream; | import java.util.jar.JarInputStream; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
| public class FileUtil | public class FileUtil { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	@Nullable |   @Nullable | ||||||
| 	public static <T> Class<? extends T> findClass(@NotNull final File file, @NotNull final Class<T> clazz) throws IOException, ClassNotFoundException |   public static <T> Class<? extends T> findClass(@NotNull final File file, | ||||||
| 	{ |       @NotNull final Class<T> clazz) throws IOException, ClassNotFoundException { | ||||||
| 		if (!file.exists()) |     if (!file.exists()) { | ||||||
| 		{ |       return null; | ||||||
| 			return null; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final URL jar = file.toURI().toURL(); |     final URL jar = file.toURI().toURL(); | ||||||
|  |  | ||||||
| 		final List<String>             matches = new ArrayList<>(); |     final List<String> matches = new ArrayList<>(); | ||||||
| 		final List<Class<? extends T>> classes = new ArrayList<>(); |     final List<Class<? extends T>> classes = new ArrayList<>(); | ||||||
|  |  | ||||||
|  |     try (final JarInputStream stream = new JarInputStream( | ||||||
|  |         jar.openStream()); final URLClassLoader loader = new URLClassLoader(new URL[]{jar}, | ||||||
|  |         clazz.getClassLoader())) { | ||||||
|  |       JarEntry entry; | ||||||
|  |       while ((entry = stream.getNextJarEntry()) != null) { | ||||||
|  |         final String name = entry.getName(); | ||||||
|  |         if (name == null || name.isEmpty() || !name.endsWith(".class")) { | ||||||
|  |           continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
| 		try (final JarInputStream stream = new JarInputStream(jar.openStream()); final URLClassLoader loader = new URLClassLoader(new URL[]{jar}, clazz.getClassLoader())) |         matches.add(name.substring(0, name.lastIndexOf('.')).replace('/', '.')); | ||||||
| 		{ |       } | ||||||
| 			JarEntry entry; |  | ||||||
| 			while ((entry = stream.getNextJarEntry()) != null) |  | ||||||
| 			{ |  | ||||||
| 				final String name = entry.getName(); |  | ||||||
| 				if (name == null || name.isEmpty() || !name.endsWith(".class")) |  | ||||||
| 				{ |  | ||||||
| 					continue; |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				matches.add(name.substring(0, name.lastIndexOf('.')).replace('/', '.')); |       for (final String match : matches) { | ||||||
| 			} |         try { | ||||||
|  |           final Class<?> loaded = loader.loadClass(match); | ||||||
|  |           if (clazz.isAssignableFrom(loaded)) { | ||||||
|  |             classes.add(loaded.asSubclass(clazz)); | ||||||
|  |           } | ||||||
|  |         } catch (final NoClassDefFoundError ignored) { | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
| 			for (final String match : matches) |     return classes.isEmpty() ? null : classes.get(0); | ||||||
| 			{ |   } | ||||||
| 				try |  | ||||||
| 				{ |  | ||||||
| 					final Class<?> loaded = loader.loadClass(match); |  | ||||||
| 					if (clazz.isAssignableFrom(loaded)) |  | ||||||
| 					{ |  | ||||||
| 						classes.add(loaded.asSubclass(clazz)); |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 				catch (final NoClassDefFoundError ignored) |  | ||||||
| 				{ } |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return classes.isEmpty() ? null : classes.get(0); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,11 +20,6 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.util; | package me.clip.placeholderapi.util; | ||||||
|  |  | ||||||
| import org.jetbrains.annotations.NotNull; |  | ||||||
|  |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Optional; |  | ||||||
|  |  | ||||||
| import static java.lang.Math.max; | import static java.lang.Math.max; | ||||||
| import static java.lang.Math.min; | import static java.lang.Math.min; | ||||||
| import static java.util.Arrays.stream; | import static java.util.Arrays.stream; | ||||||
| @@ -32,47 +27,44 @@ import static java.util.stream.Collectors.joining; | |||||||
| import static java.util.stream.Collectors.toList; | import static java.util.stream.Collectors.toList; | ||||||
| import static java.util.stream.IntStream.range; | import static java.util.stream.IntStream.range; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Optional; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * For the record, I am not sorry. |  * For the record, I am not sorry. | ||||||
|  */ |  */ | ||||||
| public final class Format | public final class Format { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	private Format() |   private Format() {} | ||||||
| 	{} |  | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
|  |   public static Optional<List<String>> tablify(@NotNull final Align align, | ||||||
|  |       @NotNull final List<List<String>> rows) { | ||||||
|  |     return findSpacing(rows) | ||||||
|  |         .map(spacing -> buildFormat(align, spacing)) | ||||||
|  |         .map(format -> rows.stream() | ||||||
|  |             .map( | ||||||
|  |                 row -> String.format(format, row.toArray()).substring(align == Align.RIGHT ? 2 : 0)) | ||||||
|  |             .collect(toList())); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	public enum Align |   @NotNull | ||||||
| 	{ |   private static String buildFormat(@NotNull final Align align, @NotNull final int[] spacing) { | ||||||
| 		LEFT, RIGHT |     return stream(spacing) | ||||||
| 	} |         .mapToObj(space -> "%" + (align == Align.LEFT ? "-" : "") + (space + 2) + "s") | ||||||
|  |         .collect(joining()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
|  |   private static Optional<int[]> findSpacing(@NotNull final List<List<String>> rows) { | ||||||
|  |     return rows.stream() | ||||||
|  |         .map(row -> row.stream().mapToInt(String::length).toArray()) | ||||||
|  |         .reduce((l, r) -> range(0, min(l.length, r.length)).map(i -> max(l[i], r[i])).toArray()); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	@NotNull |   public enum Align { | ||||||
| 	public static Optional<List<String>> tablify(@NotNull final Align align, @NotNull final List<List<String>> rows) |     LEFT, RIGHT | ||||||
| 	{ |   } | ||||||
| 		return findSpacing(rows) |  | ||||||
| 				.map(spacing -> buildFormat(align, spacing)) |  | ||||||
| 				.map(format -> rows.stream() |  | ||||||
| 								   .map(row -> String.format(format, row.toArray()).substring(align == Align.RIGHT ? 2 : 0)) |  | ||||||
| 								   .collect(toList())); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	private static String buildFormat(@NotNull final Align align, @NotNull final int[] spacing) |  | ||||||
| 	{ |  | ||||||
| 		return stream(spacing) |  | ||||||
| 				.mapToObj(space -> "%" + (align == Align.LEFT ? "-" : "") + (space + 2) + "s") |  | ||||||
| 				.collect(joining()); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	private static Optional<int[]> findSpacing(@NotNull final List<List<String>> rows) |  | ||||||
| 	{ |  | ||||||
| 		return rows.stream() |  | ||||||
| 				   .map(row -> row.stream().mapToInt(String::length).toArray()) |  | ||||||
| 				   .reduce((l, r) -> range(0, min(l.length, r.length)).map(i -> max(l[i], r[i])).toArray()); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,10 +20,6 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.util; | package me.clip.placeholderapi.util; | ||||||
|  |  | ||||||
| import org.bukkit.Bukkit; |  | ||||||
| import org.bukkit.plugin.Plugin; |  | ||||||
| import org.jetbrains.annotations.NotNull; |  | ||||||
|  |  | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.concurrent.CompletableFuture; | import java.util.concurrent.CompletableFuture; | ||||||
| @@ -31,53 +27,51 @@ import java.util.function.BiConsumer; | |||||||
| import java.util.stream.Collector; | import java.util.stream.Collector; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
| import java.util.stream.Stream; | import java.util.stream.Stream; | ||||||
|  | import org.bukkit.Bukkit; | ||||||
|  | import org.bukkit.plugin.Plugin; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
| public final class Futures | public final class Futures { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	private Futures() |   private Futures() {} | ||||||
| 	{} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public static <T> void onMainThread(@NotNull final Plugin plugin, @NotNull final CompletableFuture<T> future, @NotNull final BiConsumer<T, Throwable> consumer) |   public static <T> void onMainThread(@NotNull final Plugin plugin, | ||||||
| 	{ |       @NotNull final CompletableFuture<T> future, | ||||||
| 		future.whenComplete((value, exception) -> { |       @NotNull final BiConsumer<T, Throwable> consumer) { | ||||||
| 			if (Bukkit.isPrimaryThread()) |     future.whenComplete((value, exception) -> { | ||||||
| 			{ |       if (Bukkit.isPrimaryThread()) { | ||||||
| 				consumer.accept(value, exception); |         consumer.accept(value, exception); | ||||||
| 			} |       } else { | ||||||
| 			else |         Bukkit.getScheduler().runTask(plugin, () -> consumer.accept(value, exception)); | ||||||
| 			{ |       } | ||||||
| 				Bukkit.getScheduler().runTask(plugin, () -> consumer.accept(value, exception)); |     }); | ||||||
| 			} |   } | ||||||
| 		}); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	public static <T> Collector<CompletableFuture<T>, ?, CompletableFuture<List<T>>> collector() |   public static <T> Collector<CompletableFuture<T>, ?, CompletableFuture<List<T>>> collector() { | ||||||
| 	{ |     return Collectors.collectingAndThen(Collectors.toList(), Futures::of); | ||||||
| 		return Collectors.collectingAndThen(Collectors.toList(), Futures::of); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	public static <T> CompletableFuture<List<T>> of(@NotNull final Stream<CompletableFuture<T>> futures) |   public static <T> CompletableFuture<List<T>> of( | ||||||
| 	{ |       @NotNull final Stream<CompletableFuture<T>> futures) { | ||||||
| 		return of(futures.collect(Collectors.toList())); |     return of(futures.collect(Collectors.toList())); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	public static <T> CompletableFuture<List<T>> of(@NotNull final Collection<CompletableFuture<T>> futures) |   public static <T> CompletableFuture<List<T>> of( | ||||||
| 	{ |       @NotNull final Collection<CompletableFuture<T>> futures) { | ||||||
| 		return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) |     return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) | ||||||
| 								.thenApplyAsync($ -> awaitCompletion(futures)); |         .thenApplyAsync($ -> awaitCompletion(futures)); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	@NotNull |   @NotNull | ||||||
| 	private static <T> List<T> awaitCompletion(@NotNull final Collection<CompletableFuture<T>> futures) |   private static <T> List<T> awaitCompletion( | ||||||
| 	{ |       @NotNull final Collection<CompletableFuture<T>> futures) { | ||||||
| 		return futures.stream().map(CompletableFuture::join).collect(Collectors.toList()); |     return futures.stream().map(CompletableFuture::join).collect(Collectors.toList()); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,40 +20,34 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.util; | package me.clip.placeholderapi.util; | ||||||
|  |  | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.stream.Collectors; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.ChatColor; | import org.bukkit.ChatColor; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
| import java.util.Arrays; | public final class Msg { | ||||||
| import java.util.stream.Collectors; |  | ||||||
|  |  | ||||||
| public final class Msg |   public static void msg(@NotNull final CommandSender sender, @NotNull final String... messages) { | ||||||
| { |     if (messages.length == 0) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 	public static void msg(@NotNull final CommandSender sender, @NotNull final String... messages) |     sender.sendMessage(Arrays.stream(messages).map(Msg::color).collect(Collectors.joining("\n"))); | ||||||
| 	{ |   } | ||||||
| 		if (messages.length == 0) |  | ||||||
| 		{ |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		sender.sendMessage(Arrays.stream(messages).map(Msg::color).collect(Collectors.joining("\n"))); |   public static void broadcast(@NotNull final String... messages) { | ||||||
| 	} |     if (messages.length == 0) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 	public static void broadcast(@NotNull final String... messages) |     Bukkit.broadcastMessage( | ||||||
| 	{ |         Arrays.stream(messages).map(Msg::color).collect(Collectors.joining("\n"))); | ||||||
| 		if (messages.length == 0) |   } | ||||||
| 		{ |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		Bukkit.broadcastMessage(Arrays.stream(messages).map(Msg::color).collect(Collectors.joining("\n"))); |   public static String color(@NotNull final String text) { | ||||||
| 	} |     return ChatColor.translateAlternateColorCodes('&', text); | ||||||
|  |   } | ||||||
| 	public static String color(@NotNull final String text) |  | ||||||
| 	{ |  | ||||||
| 		return ChatColor.translateAlternateColorCodes('&', text); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,8 +21,8 @@ | |||||||
| package me.clip.placeholderapi.util; | package me.clip.placeholderapi.util; | ||||||
|  |  | ||||||
| public enum TimeFormat { | public enum TimeFormat { | ||||||
|     DAYS, |   DAYS, | ||||||
|     HOURS, |   HOURS, | ||||||
|     MINUTES, |   MINUTES, | ||||||
|     SECONDS |   SECONDS | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,149 +22,75 @@ package me.clip.placeholderapi.util; | |||||||
|  |  | ||||||
| import java.time.Duration; | import java.time.Duration; | ||||||
| import java.time.temporal.ChronoUnit; | import java.time.temporal.ChronoUnit; | ||||||
|  | import java.util.StringJoiner; | ||||||
|  |  | ||||||
| public class TimeUtil { | public class TimeUtil { | ||||||
|  |  | ||||||
|     public static String getRemaining(int seconds, TimeFormat type) { |   public static String getRemaining(final int seconds, final TimeFormat type) { | ||||||
|         if (seconds < 60) { |     return getRemaining((long) seconds, type); | ||||||
|             switch (type) { |   } | ||||||
|                 case DAYS: |  | ||||||
|                 case HOURS: |  | ||||||
|                 case MINUTES: |  | ||||||
|                     return "0"; |  | ||||||
|                 case SECONDS: |  | ||||||
|                     return String.valueOf(seconds); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return String.valueOf(seconds); |   public static String getRemaining(final long seconds, final TimeFormat type) { | ||||||
|         } |     switch (type) { | ||||||
|  |       default: | ||||||
|  |         return String.valueOf(seconds); | ||||||
|  |  | ||||||
|         int minutes = seconds / 60; |       case SECONDS: | ||||||
|         int s = 60 * minutes; |         return String.valueOf(seconds % 60); | ||||||
|         int secondsLeft = seconds - s; |  | ||||||
|  |  | ||||||
|         if (minutes < 60) { |       case MINUTES: | ||||||
|             switch (type) { |         return String.valueOf((seconds / 60) % 60); | ||||||
|                 case DAYS: |  | ||||||
|                 case HOURS: |  | ||||||
|                     return "0"; |  | ||||||
|                 case MINUTES: |  | ||||||
|                     return String.valueOf(minutes); |  | ||||||
|                 case SECONDS: |  | ||||||
|                     return String.valueOf(secondsLeft); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return String.valueOf(seconds); |       case HOURS: | ||||||
|         } |         return String.valueOf((seconds / 3600) % 24); | ||||||
|  |  | ||||||
|         if (minutes < 1440) { |       case DAYS: | ||||||
|             int hours = minutes / 60; |         return String.valueOf(seconds / 86400); | ||||||
|             int inMins = 60 * hours; |     } | ||||||
|             int leftOver = minutes - inMins; |   } | ||||||
|  |  | ||||||
|             switch (type) { |   /** | ||||||
|                 case DAYS: |    * Format the given value with s, m, h and d (seconds, minutes, hours and days) | ||||||
|                     return "0"; |    * | ||||||
|                 case HOURS: |    * @param duration {@link Duration} (eg, Duration.of(20, {@link ChronoUnit#SECONDS}) for 20 | ||||||
|                     return String.valueOf(hours); |    *                 seconds) | ||||||
|                 case MINUTES: |    * @return formatted time | ||||||
|                     return String.valueOf(leftOver); |    */ | ||||||
|                 case SECONDS: |   public static String getTime(final Duration duration) { | ||||||
|                     return String.valueOf(secondsLeft); |     return getTime(duration.getSeconds()); | ||||||
|             } |   } | ||||||
|  |  | ||||||
|             return String.valueOf(seconds); |   public static String getTime(final int seconds) { | ||||||
|         } |     return getTime((long) seconds); | ||||||
|  |   } | ||||||
|  |  | ||||||
|         int days = minutes / 1440; |   public static String getTime(long seconds) { | ||||||
|         int inMins = 1440 * days; |     final StringJoiner joiner = new StringJoiner(" "); | ||||||
|         int leftOver = minutes - inMins; |  | ||||||
|  |  | ||||||
|         if (leftOver < 60) { |     long minutes = seconds / 60; | ||||||
|             switch (type) { |     long hours = minutes / 60; | ||||||
|                 case DAYS: |     final long days = hours / 24; | ||||||
|                     return String.valueOf(days); |  | ||||||
|                 case HOURS: |  | ||||||
|                     return String.valueOf(0); |  | ||||||
|                 case MINUTES: |  | ||||||
|                     return String.valueOf(leftOver); |  | ||||||
|                 case SECONDS: |  | ||||||
|                     return String.valueOf(secondsLeft); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return String.valueOf(seconds); |     seconds %= 60; | ||||||
|  |     minutes %= 60; | ||||||
|  |     hours %= 24; | ||||||
|  |  | ||||||
|         } else { |     if (days > 0) { | ||||||
|             int hours = leftOver / 60; |       joiner.add(days + "d"); | ||||||
|             int hoursInMins = 60 * hours; |  | ||||||
|             int minsLeft = leftOver - hoursInMins; |  | ||||||
|  |  | ||||||
|             switch (type) { |  | ||||||
|                 case DAYS: |  | ||||||
|                     return String.valueOf(days); |  | ||||||
|                 case HOURS: |  | ||||||
|                     return String.valueOf(hours); |  | ||||||
|                 case MINUTES: |  | ||||||
|                     return String.valueOf(minsLeft); |  | ||||||
|                 case SECONDS: |  | ||||||
|                     return String.valueOf(secondsLeft); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return String.valueOf(seconds); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static String getTime(int seconds) { |     if (hours > 0) { | ||||||
|         return getTime(Duration.ofSeconds(seconds)); |       joiner.add(hours + "h"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     if (minutes > 0) { | ||||||
|      * Format the given value with s, m, h and d (seconds, minutes, hours and days) |       joiner.add(minutes + "m"); | ||||||
|      * |  | ||||||
|      * @param duration {@link Duration} (eg, Duration.of(20, {@link ChronoUnit#SECONDS}) for 20 seconds) |  | ||||||
|      * @return formatted time |  | ||||||
|      */ |  | ||||||
|     public static String getTime(final Duration duration) { |  | ||||||
|         final StringBuilder builder = new StringBuilder(); |  | ||||||
|  |  | ||||||
|         long seconds = duration.getSeconds(); |  | ||||||
|         long minutes = seconds / 60; |  | ||||||
|         long hours = minutes / 60; |  | ||||||
|         long days = hours / 24; |  | ||||||
|  |  | ||||||
|         seconds %= 60; |  | ||||||
|         minutes %= 60; |  | ||||||
|         hours %= 60; |  | ||||||
|         days %= 24; |  | ||||||
|  |  | ||||||
|         if (seconds > 0) { |  | ||||||
|             builder.insert(0, seconds + "s"); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (minutes > 0) { |  | ||||||
|             if (builder.length() > 0) { |  | ||||||
|                 builder.insert(0, ' '); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             builder.insert(0, minutes + "m"); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (hours > 0) { |  | ||||||
|             if (builder.length() > 0) { |  | ||||||
|                 builder.insert(0, ' '); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             builder.insert(0, hours + "h"); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (days > 0) { |  | ||||||
|             if (builder.length() > 0) { |  | ||||||
|                 builder.insert(0, ' '); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             builder.insert(0, days + "d"); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return builder.toString(); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (seconds > 0) { | ||||||
|  |       joiner.add(seconds + "s"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return joiner.toString(); | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,681 +1,4 @@ | |||||||
| # | name: "@name@" | ||||||
| #                     GNU GENERAL PUBLIC LICENSE |  | ||||||
| #                        Version 3, 29 June 2007 |  | ||||||
| # |  | ||||||
| #  Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |  | ||||||
| #  Everyone is permitted to copy and distribute verbatim copies |  | ||||||
| #  of this license document, but changing it is not allowed. |  | ||||||
| # |  | ||||||
| #                             Preamble |  | ||||||
| # |  | ||||||
| #   The GNU General Public License is a free, copyleft license for |  | ||||||
| # software and other kinds of works. |  | ||||||
| # |  | ||||||
| #   The licenses for most software and other practical works are designed |  | ||||||
| # to take away your freedom to share and change the works.  By contrast, |  | ||||||
| # the GNU General Public License is intended to guarantee your freedom to |  | ||||||
| # share and change all versions of a program--to make sure it remains free |  | ||||||
| # software for all its users.  We, the Free Software Foundation, use the |  | ||||||
| # GNU General Public License for most of our software; it applies also to |  | ||||||
| # any other work released this way by its authors.  You can apply it to |  | ||||||
| # your programs, too. |  | ||||||
| # |  | ||||||
| #   When we speak of free software, we are referring to freedom, not |  | ||||||
| # price.  Our General Public Licenses are designed to make sure that you |  | ||||||
| # have the freedom to distribute copies of free software (and charge for |  | ||||||
| # them if you wish), that you receive source code or can get it if you |  | ||||||
| # want it, that you can change the software or use pieces of it in new |  | ||||||
| # free programs, and that you know you can do these things. |  | ||||||
| # |  | ||||||
| #   To protect your rights, we need to prevent others from denying you |  | ||||||
| # these rights or asking you to surrender the rights.  Therefore, you have |  | ||||||
| # certain responsibilities if you distribute copies of the software, or if |  | ||||||
| # you modify it: responsibilities to respect the freedom of others. |  | ||||||
| # |  | ||||||
| #   For example, if you distribute copies of such a program, whether |  | ||||||
| # gratis or for a fee, you must pass on to the recipients the same |  | ||||||
| # freedoms that you received.  You must make sure that they, too, receive |  | ||||||
| # or can get the source code.  And you must show them these terms so they |  | ||||||
| # know their rights. |  | ||||||
| # |  | ||||||
| #   Developers that use the GNU GPL protect your rights with two steps: |  | ||||||
| # (1) assert copyright on the software, and (2) offer you this License |  | ||||||
| # giving you legal permission to copy, distribute and/or modify it. |  | ||||||
| # |  | ||||||
| #   For the developers' and authors' protection, the GPL clearly explains |  | ||||||
| # that there is no warranty for this free software.  For both users' and |  | ||||||
| # authors' sake, the GPL requires that modified versions be marked as |  | ||||||
| # changed, so that their problems will not be attributed erroneously to |  | ||||||
| # authors of previous versions. |  | ||||||
| # |  | ||||||
| #   Some devices are designed to deny users access to install or run |  | ||||||
| # modified versions of the software inside them, although the manufacturer |  | ||||||
| # can do so.  This is fundamentally incompatible with the aim of |  | ||||||
| # protecting users' freedom to change the software.  The systematic |  | ||||||
| # pattern of such abuse occurs in the area of products for individuals to |  | ||||||
| # use, which is precisely where it is most unacceptable.  Therefore, we |  | ||||||
| # have designed this version of the GPL to prohibit the practice for those |  | ||||||
| # products.  If such problems arise substantially in other domains, we |  | ||||||
| # stand ready to extend this provision to those domains in future versions |  | ||||||
| # of the GPL, as needed to protect the freedom of users. |  | ||||||
| # |  | ||||||
| #   Finally, every program is threatened constantly by software patents. |  | ||||||
| # States should not allow patents to restrict development and use of |  | ||||||
| # software on general-purpose computers, but in those that do, we wish to |  | ||||||
| # avoid the special danger that patents applied to a free program could |  | ||||||
| # make it effectively proprietary.  To prevent this, the GPL assures that |  | ||||||
| # patents cannot be used to render the program non-free. |  | ||||||
| # |  | ||||||
| #   The precise terms and conditions for copying, distribution and |  | ||||||
| # modification follow. |  | ||||||
| # |  | ||||||
| #                        TERMS AND CONDITIONS |  | ||||||
| # |  | ||||||
| #   0. Definitions. |  | ||||||
| # |  | ||||||
| #   "This License" refers to version 3 of the GNU General Public License. |  | ||||||
| # |  | ||||||
| #   "Copyright" also means copyright-like laws that apply to other kinds of |  | ||||||
| # works, such as semiconductor masks. |  | ||||||
| # |  | ||||||
| #   "The Program" refers to any copyrightable work licensed under this |  | ||||||
| # License.  Each licensee is addressed as "you".  "Licensees" and |  | ||||||
| # "recipients" may be individuals or organizations. |  | ||||||
| # |  | ||||||
| #   To "modify" a work means to copy from or adapt all or part of the work |  | ||||||
| # in a fashion requiring copyright permission, other than the making of an |  | ||||||
| # exact copy.  The resulting work is called a "modified version" of the |  | ||||||
| # earlier work or a work "based on" the earlier work. |  | ||||||
| # |  | ||||||
| #   A "covered work" means either the unmodified Program or a work based |  | ||||||
| # on the Program. |  | ||||||
| # |  | ||||||
| #   To "propagate" a work means to do anything with it that, without |  | ||||||
| # permission, would make you directly or secondarily liable for |  | ||||||
| # infringement under applicable copyright law, except executing it on a |  | ||||||
| # computer or modifying a private copy.  Propagation includes copying, |  | ||||||
| # distribution (with or without modification), making available to the |  | ||||||
| # public, and in some countries other activities as well. |  | ||||||
| # |  | ||||||
| #   To "convey" a work means any kind of propagation that enables other |  | ||||||
| # parties to make or receive copies.  Mere interaction with a user through |  | ||||||
| # a computer network, with no transfer of a copy, is not conveying. |  | ||||||
| # |  | ||||||
| #   An interactive user interface displays "Appropriate Legal Notices" |  | ||||||
| # to the extent that it includes a convenient and prominently visible |  | ||||||
| # feature that (1) displays an appropriate copyright notice, and (2) |  | ||||||
| # tells the user that there is no warranty for the work (except to the |  | ||||||
| # extent that warranties are provided), that licensees may convey the |  | ||||||
| # work under this License, and how to view a copy of this License.  If |  | ||||||
| # the interface presents a list of user commands or options, such as a |  | ||||||
| # menu, a prominent item in the list meets this criterion. |  | ||||||
| # |  | ||||||
| #   1. Source Code. |  | ||||||
| # |  | ||||||
| #   The "source code" for a work means the preferred form of the work |  | ||||||
| # for making modifications to it.  "Object code" means any non-source |  | ||||||
| # form of a work. |  | ||||||
| # |  | ||||||
| #   A "Standard Interface" means an interface that either is an official |  | ||||||
| # standard defined by a recognized standards body, or, in the case of |  | ||||||
| # interfaces specified for a particular programming language, one that |  | ||||||
| # is widely used among developers working in that language. |  | ||||||
| # |  | ||||||
| #   The "System Libraries" of an executable work include anything, other |  | ||||||
| # than the work as a whole, that (a) is included in the normal form of |  | ||||||
| # packaging a Major Component, but which is not part of that Major |  | ||||||
| # Component, and (b) serves only to enable use of the work with that |  | ||||||
| # Major Component, or to implement a Standard Interface for which an |  | ||||||
| # implementation is available to the public in source code form.  A |  | ||||||
| # "Major Component", in this context, means a major essential component |  | ||||||
| # (kernel, window system, and so on) of the specific operating system |  | ||||||
| # (if any) on which the executable work runs, or a compiler used to |  | ||||||
| # produce the work, or an object code interpreter used to run it. |  | ||||||
| # |  | ||||||
| #   The "Corresponding Source" for a work in object code form means all |  | ||||||
| # the source code needed to generate, install, and (for an executable |  | ||||||
| # work) run the object code and to modify the work, including scripts to |  | ||||||
| # control those activities.  However, it does not include the work's |  | ||||||
| # System Libraries, or general-purpose tools or generally available free |  | ||||||
| # programs which are used unmodified in performing those activities but |  | ||||||
| # which are not part of the work.  For example, Corresponding Source |  | ||||||
| # includes interface definition files associated with source files for |  | ||||||
| # the work, and the source code for shared libraries and dynamically |  | ||||||
| # linked subprograms that the work is specifically designed to require, |  | ||||||
| # such as by intimate data communication or control flow between those |  | ||||||
| # subprograms and other parts of the work. |  | ||||||
| # |  | ||||||
| #   The Corresponding Source need not include anything that users |  | ||||||
| # can regenerate automatically from other parts of the Corresponding |  | ||||||
| # Source. |  | ||||||
| # |  | ||||||
| #   The Corresponding Source for a work in source code form is that |  | ||||||
| # same work. |  | ||||||
| # |  | ||||||
| #   2. Basic Permissions. |  | ||||||
| # |  | ||||||
| #   All rights granted under this License are granted for the term of |  | ||||||
| # copyright on the Program, and are irrevocable provided the stated |  | ||||||
| # conditions are met.  This License explicitly affirms your unlimited |  | ||||||
| # permission to run the unmodified Program.  The output from running a |  | ||||||
| # covered work is covered by this License only if the output, given its |  | ||||||
| # content, constitutes a covered work.  This License acknowledges your |  | ||||||
| # rights of fair use or other equivalent, as provided by copyright law. |  | ||||||
| # |  | ||||||
| #   You may make, run and propagate covered works that you do not |  | ||||||
| # convey, without conditions so long as your license otherwise remains |  | ||||||
| # in force.  You may convey covered works to others for the sole purpose |  | ||||||
| # of having them make modifications exclusively for you, or provide you |  | ||||||
| # with facilities for running those works, provided that you comply with |  | ||||||
| # the terms of this License in conveying all material for which you do |  | ||||||
| # not control copyright.  Those thus making or running the covered works |  | ||||||
| # for you must do so exclusively on your behalf, under your direction |  | ||||||
| # and control, on terms that prohibit them from making any copies of |  | ||||||
| # your copyrighted material outside their relationship with you. |  | ||||||
| # |  | ||||||
| #   Conveying under any other circumstances is permitted solely under |  | ||||||
| # the conditions stated below.  Sublicensing is not allowed; section 10 |  | ||||||
| # makes it unnecessary. |  | ||||||
| # |  | ||||||
| #   3. Protecting Users' Legal Rights From Anti-Circumvention Law. |  | ||||||
| # |  | ||||||
| #   No covered work shall be deemed part of an effective technological |  | ||||||
| # measure under any applicable law fulfilling obligations under article |  | ||||||
| # 11 of the WIPO copyright treaty adopted on 20 December 1996, or |  | ||||||
| # similar laws prohibiting or restricting circumvention of such |  | ||||||
| # measures. |  | ||||||
| # |  | ||||||
| #   When you convey a covered work, you waive any legal power to forbid |  | ||||||
| # circumvention of technological measures to the extent such circumvention |  | ||||||
| # is effected by exercising rights under this License with respect to |  | ||||||
| # the covered work, and you disclaim any intention to limit operation or |  | ||||||
| # modification of the work as a means of enforcing, against the work's |  | ||||||
| # users, your or third parties' legal rights to forbid circumvention of |  | ||||||
| # technological measures. |  | ||||||
| # |  | ||||||
| #   4. Conveying Verbatim Copies. |  | ||||||
| # |  | ||||||
| #   You may convey verbatim copies of the Program's source code as you |  | ||||||
| # receive it, in any medium, provided that you conspicuously and |  | ||||||
| # appropriately publish on each copy an appropriate copyright notice; |  | ||||||
| # keep intact all notices stating that this License and any |  | ||||||
| # non-permissive terms added in accord with section 7 apply to the code; |  | ||||||
| # keep intact all notices of the absence of any warranty; and give all |  | ||||||
| # recipients a copy of this License along with the Program. |  | ||||||
| # |  | ||||||
| #   You may charge any price or no price for each copy that you convey, |  | ||||||
| # and you may offer support or warranty protection for a fee. |  | ||||||
| # |  | ||||||
| #   5. Conveying Modified Source Versions. |  | ||||||
| # |  | ||||||
| #   You may convey a work based on the Program, or the modifications to |  | ||||||
| # produce it from the Program, in the form of source code under the |  | ||||||
| # terms of section 4, provided that you also meet all of these conditions: |  | ||||||
| # |  | ||||||
| #     a) The work must carry prominent notices stating that you modified |  | ||||||
| #     it, and giving a relevant date. |  | ||||||
| # |  | ||||||
| #     b) The work must carry prominent notices stating that it is |  | ||||||
| #     released under this License and any conditions added under section |  | ||||||
| #     7.  This requirement modifies the requirement in section 4 to |  | ||||||
| #     "keep intact all notices". |  | ||||||
| # |  | ||||||
| #     c) You must license the entire work, as a whole, under this |  | ||||||
| #     License to anyone who comes into possession of a copy.  This |  | ||||||
| #     License will therefore apply, along with any applicable section 7 |  | ||||||
| #     additional terms, to the whole of the work, and all its parts, |  | ||||||
| #     regardless of how they are packaged.  This License gives no |  | ||||||
| #     permission to license the work in any other way, but it does not |  | ||||||
| #     invalidate such permission if you have separately received it. |  | ||||||
| # |  | ||||||
| #     d) If the work has interactive user interfaces, each must display |  | ||||||
| #     Appropriate Legal Notices; however, if the Program has interactive |  | ||||||
| #     interfaces that do not display Appropriate Legal Notices, your |  | ||||||
| #     work need not make them do so. |  | ||||||
| # |  | ||||||
| #   A compilation of a covered work with other separate and independent |  | ||||||
| # works, which are not by their nature extensions of the covered work, |  | ||||||
| # and which are not combined with it such as to form a larger program, |  | ||||||
| # in or on a volume of a storage or distribution medium, is called an |  | ||||||
| # "aggregate" if the compilation and its resulting copyright are not |  | ||||||
| # used to limit the access or legal rights of the compilation's users |  | ||||||
| # beyond what the individual works permit.  Inclusion of a covered work |  | ||||||
| # in an aggregate does not cause this License to apply to the other |  | ||||||
| # parts of the aggregate. |  | ||||||
| # |  | ||||||
| #   6. Conveying Non-Source Forms. |  | ||||||
| # |  | ||||||
| #   You may convey a covered work in object code form under the terms |  | ||||||
| # of sections 4 and 5, provided that you also convey the |  | ||||||
| # machine-readable Corresponding Source under the terms of this License, |  | ||||||
| # in one of these ways: |  | ||||||
| # |  | ||||||
| #     a) Convey the object code in, or embodied in, a physical product |  | ||||||
| #     (including a physical distribution medium), accompanied by the |  | ||||||
| #     Corresponding Source fixed on a durable physical medium |  | ||||||
| #     customarily used for software interchange. |  | ||||||
| # |  | ||||||
| #     b) Convey the object code in, or embodied in, a physical product |  | ||||||
| #     (including a physical distribution medium), accompanied by a |  | ||||||
| #     written offer, valid for at least three years and valid for as |  | ||||||
| #     long as you offer spare parts or customer support for that product |  | ||||||
| #     model, to give anyone who possesses the object code either (1) a |  | ||||||
| #     copy of the Corresponding Source for all the software in the |  | ||||||
| #     product that is covered by this License, on a durable physical |  | ||||||
| #     medium customarily used for software interchange, for a price no |  | ||||||
| #     more than your reasonable cost of physically performing this |  | ||||||
| #     conveying of source, or (2) access to copy the |  | ||||||
| #     Corresponding Source from a network server at no charge. |  | ||||||
| # |  | ||||||
| #     c) Convey individual copies of the object code with a copy of the |  | ||||||
| #     written offer to provide the Corresponding Source.  This |  | ||||||
| #     alternative is allowed only occasionally and noncommercially, and |  | ||||||
| #     only if you received the object code with such an offer, in accord |  | ||||||
| #     with subsection 6b. |  | ||||||
| # |  | ||||||
| #     d) Convey the object code by offering access from a designated |  | ||||||
| #     place (gratis or for a charge), and offer equivalent access to the |  | ||||||
| #     Corresponding Source in the same way through the same place at no |  | ||||||
| #     further charge.  You need not require recipients to copy the |  | ||||||
| #     Corresponding Source along with the object code.  If the place to |  | ||||||
| #     copy the object code is a network server, the Corresponding Source |  | ||||||
| #     may be on a different server (operated by you or a third party) |  | ||||||
| #     that supports equivalent copying facilities, provided you maintain |  | ||||||
| #     clear directions next to the object code saying where to find the |  | ||||||
| #     Corresponding Source.  Regardless of what server hosts the |  | ||||||
| #     Corresponding Source, you remain obligated to ensure that it is |  | ||||||
| #     available for as long as needed to satisfy these requirements. |  | ||||||
| # |  | ||||||
| #     e) Convey the object code using peer-to-peer transmission, provided |  | ||||||
| #     you inform other peers where the object code and Corresponding |  | ||||||
| #     Source of the work are being offered to the general public at no |  | ||||||
| #     charge under subsection 6d. |  | ||||||
| # |  | ||||||
| #   A separable portion of the object code, whose source code is excluded |  | ||||||
| # from the Corresponding Source as a System Library, need not be |  | ||||||
| # included in conveying the object code work. |  | ||||||
| # |  | ||||||
| #   A "User Product" is either (1) a "consumer product", which means any |  | ||||||
| # tangible personal property which is normally used for personal, family, |  | ||||||
| # or household purposes, or (2) anything designed or sold for incorporation |  | ||||||
| # into a dwelling.  In determining whether a product is a consumer product, |  | ||||||
| # doubtful cases shall be resolved in favor of coverage.  For a particular |  | ||||||
| # product received by a particular user, "normally used" refers to a |  | ||||||
| # typical or common use of that class of product, regardless of the status |  | ||||||
| # of the particular user or of the way in which the particular user |  | ||||||
| # actually uses, or expects or is expected to use, the product.  A product |  | ||||||
| # is a consumer product regardless of whether the product has substantial |  | ||||||
| # commercial, industrial or non-consumer uses, unless such uses represent |  | ||||||
| # the only significant mode of use of the product. |  | ||||||
| # |  | ||||||
| #   "Installation Information" for a User Product means any methods, |  | ||||||
| # procedures, authorization keys, or other information required to install |  | ||||||
| # and execute modified versions of a covered work in that User Product from |  | ||||||
| # a modified version of its Corresponding Source.  The information must |  | ||||||
| # suffice to ensure that the continued functioning of the modified object |  | ||||||
| # code is in no case prevented or interfered with solely because |  | ||||||
| # modification has been made. |  | ||||||
| # |  | ||||||
| #   If you convey an object code work under this section in, or with, or |  | ||||||
| # specifically for use in, a User Product, and the conveying occurs as |  | ||||||
| # part of a transaction in which the right of possession and use of the |  | ||||||
| # User Product is transferred to the recipient in perpetuity or for a |  | ||||||
| # fixed term (regardless of how the transaction is characterized), the |  | ||||||
| # Corresponding Source conveyed under this section must be accompanied |  | ||||||
| # by the Installation Information.  But this requirement does not apply |  | ||||||
| # if neither you nor any third party retains the ability to install |  | ||||||
| # modified object code on the User Product (for example, the work has |  | ||||||
| # been installed in ROM). |  | ||||||
| # |  | ||||||
| #   The requirement to provide Installation Information does not include a |  | ||||||
| # requirement to continue to provide support service, warranty, or updates |  | ||||||
| # for a work that has been modified or installed by the recipient, or for |  | ||||||
| # the User Product in which it has been modified or installed.  Access to a |  | ||||||
| # network may be denied when the modification itself materially and |  | ||||||
| # adversely affects the operation of the network or violates the rules and |  | ||||||
| # protocols for communication across the network. |  | ||||||
| # |  | ||||||
| #   Corresponding Source conveyed, and Installation Information provided, |  | ||||||
| # in accord with this section must be in a format that is publicly |  | ||||||
| # documented (and with an implementation available to the public in |  | ||||||
| # source code form), and must require no special password or key for |  | ||||||
| # unpacking, reading or copying. |  | ||||||
| # |  | ||||||
| #   7. Additional Terms. |  | ||||||
| # |  | ||||||
| #   "Additional permissions" are terms that supplement the terms of this |  | ||||||
| # License by making exceptions from one or more of its conditions. |  | ||||||
| # Additional permissions that are applicable to the entire Program shall |  | ||||||
| # be treated as though they were included in this License, to the extent |  | ||||||
| # that they are valid under applicable law.  If additional permissions |  | ||||||
| # apply only to part of the Program, that part may be used separately |  | ||||||
| # under those permissions, but the entire Program remains governed by |  | ||||||
| # this License without regard to the additional permissions. |  | ||||||
| # |  | ||||||
| #   When you convey a copy of a covered work, you may at your option |  | ||||||
| # remove any additional permissions from that copy, or from any part of |  | ||||||
| # it.  (Additional permissions may be written to require their own |  | ||||||
| # removal in certain cases when you modify the work.)  You may place |  | ||||||
| # additional permissions on material, added by you to a covered work, |  | ||||||
| # for which you have or can give appropriate copyright permission. |  | ||||||
| # |  | ||||||
| #   Notwithstanding any other provision of this License, for material you |  | ||||||
| # add to a covered work, you may (if authorized by the copyright holders of |  | ||||||
| # that material) supplement the terms of this License with terms: |  | ||||||
| # |  | ||||||
| #     a) Disclaiming warranty or limiting liability differently from the |  | ||||||
| #     terms of sections 15 and 16 of this License; or |  | ||||||
| # |  | ||||||
| #     b) Requiring preservation of specified reasonable legal notices or |  | ||||||
| #     author attributions in that material or in the Appropriate Legal |  | ||||||
| #     Notices displayed by works containing it; or |  | ||||||
| # |  | ||||||
| #     c) Prohibiting misrepresentation of the origin of that material, or |  | ||||||
| #     requiring that modified versions of such material be marked in |  | ||||||
| #     reasonable ways as different from the original version; or |  | ||||||
| # |  | ||||||
| #     d) Limiting the use for publicity purposes of names of licensors or |  | ||||||
| #     authors of the material; or |  | ||||||
| # |  | ||||||
| #     e) Declining to grant rights under trademark law for use of some |  | ||||||
| #     trade names, trademarks, or service marks; or |  | ||||||
| # |  | ||||||
| #     f) Requiring indemnification of licensors and authors of that |  | ||||||
| #     material by anyone who conveys the material (or modified versions of |  | ||||||
| #     it) with contractual assumptions of liability to the recipient, for |  | ||||||
| #     any liability that these contractual assumptions directly impose on |  | ||||||
| #     those licensors and authors. |  | ||||||
| # |  | ||||||
| #   All other non-permissive additional terms are considered "further |  | ||||||
| # restrictions" within the meaning of section 10.  If the Program as you |  | ||||||
| # received it, or any part of it, contains a notice stating that it is |  | ||||||
| # governed by this License along with a term that is a further |  | ||||||
| # restriction, you may remove that term.  If a license document contains |  | ||||||
| # a further restriction but permits relicensing or conveying under this |  | ||||||
| # License, you may add to a covered work material governed by the terms |  | ||||||
| # of that license document, provided that the further restriction does |  | ||||||
| # not survive such relicensing or conveying. |  | ||||||
| # |  | ||||||
| #   If you add terms to a covered work in accord with this section, you |  | ||||||
| # must place, in the relevant source files, a statement of the |  | ||||||
| # additional terms that apply to those files, or a notice indicating |  | ||||||
| # where to find the applicable terms. |  | ||||||
| # |  | ||||||
| #   Additional terms, permissive or non-permissive, may be stated in the |  | ||||||
| # form of a separately written license, or stated as exceptions; |  | ||||||
| # the above requirements apply either way. |  | ||||||
| # |  | ||||||
| #   8. Termination. |  | ||||||
| # |  | ||||||
| #   You may not propagate or modify a covered work except as expressly |  | ||||||
| # provided under this License.  Any attempt otherwise to propagate or |  | ||||||
| # modify it is void, and will automatically terminate your rights under |  | ||||||
| # this License (including any patent licenses granted under the third |  | ||||||
| # paragraph of section 11). |  | ||||||
| # |  | ||||||
| #   However, if you cease all violation of this License, then your |  | ||||||
| # license from a particular copyright holder is reinstated (a) |  | ||||||
| # provisionally, unless and until the copyright holder explicitly and |  | ||||||
| # finally terminates your license, and (b) permanently, if the copyright |  | ||||||
| # holder fails to notify you of the violation by some reasonable means |  | ||||||
| # prior to 60 days after the cessation. |  | ||||||
| # |  | ||||||
| #   Moreover, your license from a particular copyright holder is |  | ||||||
| # reinstated permanently if the copyright holder notifies you of the |  | ||||||
| # violation by some reasonable means, this is the first time you have |  | ||||||
| # received notice of violation of this License (for any work) from that |  | ||||||
| # copyright holder, and you cure the violation prior to 30 days after |  | ||||||
| # your receipt of the notice. |  | ||||||
| # |  | ||||||
| #   Termination of your rights under this section does not terminate the |  | ||||||
| # licenses of parties who have received copies or rights from you under |  | ||||||
| # this License.  If your rights have been terminated and not permanently |  | ||||||
| # reinstated, you do not qualify to receive new licenses for the same |  | ||||||
| # material under section 10. |  | ||||||
| # |  | ||||||
| #   9. Acceptance Not Required for Having Copies. |  | ||||||
| # |  | ||||||
| #   You are not required to accept this License in order to receive or |  | ||||||
| # run a copy of the Program.  Ancillary propagation of a covered work |  | ||||||
| # occurring solely as a consequence of using peer-to-peer transmission |  | ||||||
| # to receive a copy likewise does not require acceptance.  However, |  | ||||||
| # nothing other than this License grants you permission to propagate or |  | ||||||
| # modify any covered work.  These actions infringe copyright if you do |  | ||||||
| # not accept this License.  Therefore, by modifying or propagating a |  | ||||||
| # covered work, you indicate your acceptance of this License to do so. |  | ||||||
| # |  | ||||||
| #   10. Automatic Licensing of Downstream Recipients. |  | ||||||
| # |  | ||||||
| #   Each time you convey a covered work, the recipient automatically |  | ||||||
| # receives a license from the original licensors, to run, modify and |  | ||||||
| # propagate that work, subject to this License.  You are not responsible |  | ||||||
| # for enforcing compliance by third parties with this License. |  | ||||||
| # |  | ||||||
| #   An "entity transaction" is a transaction transferring control of an |  | ||||||
| # organization, or substantially all assets of one, or subdividing an |  | ||||||
| # organization, or merging organizations.  If propagation of a covered |  | ||||||
| # work results from an entity transaction, each party to that |  | ||||||
| # transaction who receives a copy of the work also receives whatever |  | ||||||
| # licenses to the work the party's predecessor in interest had or could |  | ||||||
| # give under the previous paragraph, plus a right to possession of the |  | ||||||
| # Corresponding Source of the work from the predecessor in interest, if |  | ||||||
| # the predecessor has it or can get it with reasonable efforts. |  | ||||||
| # |  | ||||||
| #   You may not impose any further restrictions on the exercise of the |  | ||||||
| # rights granted or affirmed under this License.  For example, you may |  | ||||||
| # not impose a license fee, royalty, or other charge for exercise of |  | ||||||
| # rights granted under this License, and you may not initiate litigation |  | ||||||
| # (including a cross-claim or counterclaim in a lawsuit) alleging that |  | ||||||
| # any patent claim is infringed by making, using, selling, offering for |  | ||||||
| # sale, or importing the Program or any portion of it. |  | ||||||
| # |  | ||||||
| #   11. Patents. |  | ||||||
| # |  | ||||||
| #   A "contributor" is a copyright holder who authorizes use under this |  | ||||||
| # License of the Program or a work on which the Program is based.  The |  | ||||||
| # work thus licensed is called the contributor's "contributor version". |  | ||||||
| # |  | ||||||
| #   A contributor's "essential patent claims" are all patent claims |  | ||||||
| # owned or controlled by the contributor, whether already acquired or |  | ||||||
| # hereafter acquired, that would be infringed by some manner, permitted |  | ||||||
| # by this License, of making, using, or selling its contributor version, |  | ||||||
| # but do not include claims that would be infringed only as a |  | ||||||
| # consequence of further modification of the contributor version.  For |  | ||||||
| # purposes of this definition, "control" includes the right to grant |  | ||||||
| # patent sublicenses in a manner consistent with the requirements of |  | ||||||
| # this License. |  | ||||||
| # |  | ||||||
| #   Each contributor grants you a non-exclusive, worldwide, royalty-free |  | ||||||
| # patent license under the contributor's essential patent claims, to |  | ||||||
| # make, use, sell, offer for sale, import and otherwise run, modify and |  | ||||||
| # propagate the contents of its contributor version. |  | ||||||
| # |  | ||||||
| #   In the following three paragraphs, a "patent license" is any express |  | ||||||
| # agreement or commitment, however denominated, not to enforce a patent |  | ||||||
| # (such as an express permission to practice a patent or covenant not to |  | ||||||
| # sue for patent infringement).  To "grant" such a patent license to a |  | ||||||
| # party means to make such an agreement or commitment not to enforce a |  | ||||||
| # patent against the party. |  | ||||||
| # |  | ||||||
| #   If you convey a covered work, knowingly relying on a patent license, |  | ||||||
| # and the Corresponding Source of the work is not available for anyone |  | ||||||
| # to copy, free of charge and under the terms of this License, through a |  | ||||||
| # publicly available network server or other readily accessible means, |  | ||||||
| # then you must either (1) cause the Corresponding Source to be so |  | ||||||
| # available, or (2) arrange to deprive yourself of the benefit of the |  | ||||||
| # patent license for this particular work, or (3) arrange, in a manner |  | ||||||
| # consistent with the requirements of this License, to extend the patent |  | ||||||
| # license to downstream recipients.  "Knowingly relying" means you have |  | ||||||
| # actual knowledge that, but for the patent license, your conveying the |  | ||||||
| # covered work in a country, or your recipient's use of the covered work |  | ||||||
| # in a country, would infringe one or more identifiable patents in that |  | ||||||
| # country that you have reason to believe are valid. |  | ||||||
| # |  | ||||||
| #   If, pursuant to or in connection with a single transaction or |  | ||||||
| # arrangement, you convey, or propagate by procuring conveyance of, a |  | ||||||
| # covered work, and grant a patent license to some of the parties |  | ||||||
| # receiving the covered work authorizing them to use, propagate, modify |  | ||||||
| # or convey a specific copy of the covered work, then the patent license |  | ||||||
| # you grant is automatically extended to all recipients of the covered |  | ||||||
| # work and works based on it. |  | ||||||
| # |  | ||||||
| #   A patent license is "discriminatory" if it does not include within |  | ||||||
| # the scope of its coverage, prohibits the exercise of, or is |  | ||||||
| # conditioned on the non-exercise of one or more of the rights that are |  | ||||||
| # specifically granted under this License.  You may not convey a covered |  | ||||||
| # work if you are a party to an arrangement with a third party that is |  | ||||||
| # in the business of distributing software, under which you make payment |  | ||||||
| # to the third party based on the extent of your activity of conveying |  | ||||||
| # the work, and under which the third party grants, to any of the |  | ||||||
| # parties who would receive the covered work from you, a discriminatory |  | ||||||
| # patent license (a) in connection with copies of the covered work |  | ||||||
| # conveyed by you (or copies made from those copies), or (b) primarily |  | ||||||
| # for and in connection with specific products or compilations that |  | ||||||
| # contain the covered work, unless you entered into that arrangement, |  | ||||||
| # or that patent license was granted, prior to 28 March 2007. |  | ||||||
| # |  | ||||||
| #   Nothing in this License shall be construed as excluding or limiting |  | ||||||
| # any implied license or other defenses to infringement that may |  | ||||||
| # otherwise be available to you under applicable patent law. |  | ||||||
| # |  | ||||||
| #   12. No Surrender of Others' Freedom. |  | ||||||
| # |  | ||||||
| #   If conditions are imposed on you (whether by court order, agreement or |  | ||||||
| # otherwise) that contradict the conditions of this License, they do not |  | ||||||
| # excuse you from the conditions of this License.  If you cannot convey a |  | ||||||
| # covered work so as to satisfy simultaneously your obligations under this |  | ||||||
| # License and any other pertinent obligations, then as a consequence you may |  | ||||||
| # not convey it at all.  For example, if you agree to terms that obligate you |  | ||||||
| # to collect a royalty for further conveying from those to whom you convey |  | ||||||
| # the Program, the only way you could satisfy both those terms and this |  | ||||||
| # License would be to refrain entirely from conveying the Program. |  | ||||||
| # |  | ||||||
| #   13. Use with the GNU Affero General Public License. |  | ||||||
| # |  | ||||||
| #   Notwithstanding any other provision of this License, you have |  | ||||||
| # permission to link or combine any covered work with a work licensed |  | ||||||
| # under version 3 of the GNU Affero General Public License into a single |  | ||||||
| # combined work, and to convey the resulting work.  The terms of this |  | ||||||
| # License will continue to apply to the part which is the covered work, |  | ||||||
| # but the special requirements of the GNU Affero General Public License, |  | ||||||
| # section 13, concerning interaction through a network will apply to the |  | ||||||
| # combination as such. |  | ||||||
| # |  | ||||||
| #   14. Revised Versions of this License. |  | ||||||
| # |  | ||||||
| #   The Free Software Foundation may publish revised and/or new versions of |  | ||||||
| # the GNU General Public License from time to time.  Such new versions will |  | ||||||
| # be similar in spirit to the present version, but may differ in detail to |  | ||||||
| # address new problems or concerns. |  | ||||||
| # |  | ||||||
| #   Each version is given a distinguishing version number.  If the |  | ||||||
| # Program specifies that a certain numbered version of the GNU General |  | ||||||
| # Public License "or any later version" applies to it, you have the |  | ||||||
| # option of following the terms and conditions either of that numbered |  | ||||||
| # version or of any later version published by the Free Software |  | ||||||
| # Foundation.  If the Program does not specify a version number of the |  | ||||||
| # GNU General Public License, you may choose any version ever published |  | ||||||
| # by the Free Software Foundation. |  | ||||||
| # |  | ||||||
| #   If the Program specifies that a proxy can decide which future |  | ||||||
| # versions of the GNU General Public License can be used, that proxy's |  | ||||||
| # public statement of acceptance of a version permanently authorizes you |  | ||||||
| # to choose that version for the Program. |  | ||||||
| # |  | ||||||
| #   Later license versions may give you additional or different |  | ||||||
| # permissions.  However, no additional obligations are imposed on any |  | ||||||
| # author or copyright holder as a result of your choosing to follow a |  | ||||||
| # later version. |  | ||||||
| # |  | ||||||
| #   15. Disclaimer of Warranty. |  | ||||||
| # |  | ||||||
| #   THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY |  | ||||||
| # APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT |  | ||||||
| # HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY |  | ||||||
| # OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, |  | ||||||
| # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |  | ||||||
| # PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM |  | ||||||
| # IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF |  | ||||||
| # ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |  | ||||||
| # |  | ||||||
| #   16. Limitation of Liability. |  | ||||||
| # |  | ||||||
| #   IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |  | ||||||
| # WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS |  | ||||||
| # THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY |  | ||||||
| # GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE |  | ||||||
| # USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF |  | ||||||
| # DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD |  | ||||||
| # PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), |  | ||||||
| # EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF |  | ||||||
| # SUCH DAMAGES. |  | ||||||
| # |  | ||||||
| #   17. Interpretation of Sections 15 and 16. |  | ||||||
| # |  | ||||||
| #   If the disclaimer of warranty and limitation of liability provided |  | ||||||
| # above cannot be given local legal effect according to their terms, |  | ||||||
| # reviewing courts shall apply local law that most closely approximates |  | ||||||
| # an absolute waiver of all civil liability in connection with the |  | ||||||
| # Program, unless a warranty or assumption of liability accompanies a |  | ||||||
| # copy of the Program in return for a fee. |  | ||||||
| # |  | ||||||
| #                      END OF TERMS AND CONDITIONS |  | ||||||
| # |  | ||||||
| #             How to Apply These Terms to Your New Programs |  | ||||||
| # |  | ||||||
| #   If you develop a new program, and you want it to be of the greatest |  | ||||||
| # possible use to the public, the best way to achieve this is to make it |  | ||||||
| # free software which everyone can redistribute and change under these terms. |  | ||||||
| # |  | ||||||
| #   To do so, attach the following notices to the program.  It is safest |  | ||||||
| # to attach them to the start of each source file to most effectively |  | ||||||
| # state the exclusion of warranty; and each file should have at least |  | ||||||
| # the "copyright" line and a pointer to where the full notice is found. |  | ||||||
| # |  | ||||||
| #     <one line to give the program's name and a brief idea of what it does.> |  | ||||||
| #     Copyright (C) <year>  <name of author> |  | ||||||
| # |  | ||||||
| #     This program is free software: you can redistribute it and/or modify |  | ||||||
| #     it under the terms of the GNU 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 General Public License for more details. |  | ||||||
| # |  | ||||||
| #     You should have received a copy of the GNU General Public License |  | ||||||
| #     along with this program.  If not, see <http://www.gnu.org/licenses/>. |  | ||||||
| # |  | ||||||
| # Also add information on how to contact you by electronic and paper mail. |  | ||||||
| # |  | ||||||
| #   If the program does terminal interaction, make it output a short |  | ||||||
| # notice like this when it starts in an interactive mode: |  | ||||||
| # |  | ||||||
| #     <program>  Copyright (C) <year>  <name of author> |  | ||||||
| #     This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. |  | ||||||
| #     This is free software, and you are welcome to redistribute it |  | ||||||
| #     under certain conditions; type `show c' for details. |  | ||||||
| # |  | ||||||
| # The hypothetical commands `show w' and `show c' should show the appropriate |  | ||||||
| # parts of the General Public License.  Of course, your program's commands |  | ||||||
| # might be different; for a GUI interface, you would use an "about box". |  | ||||||
| # |  | ||||||
| #   You should also get your employer (if you work as a programmer) or school, |  | ||||||
| # if any, to sign a "copyright disclaimer" for the program, if necessary. |  | ||||||
| # For more information on this, and how to apply and follow the GNU GPL, see |  | ||||||
| # <http://www.gnu.org/licenses/>. |  | ||||||
| # |  | ||||||
| #   The GNU General Public License does not permit incorporating your program |  | ||||||
| # into proprietary programs.  If your program is a subroutine library, you |  | ||||||
| # may consider it more useful to permit linking proprietary applications with |  | ||||||
| # the library.  If this is what you want to do, use the GNU Lesser General |  | ||||||
| # Public License instead of this License.  But first, please read |  | ||||||
| # <http://www.gnu.org/philosophy/why-not-lgpl.html>. |  | ||||||
| # |  | ||||||
|  |  | ||||||
| name: "PlaceholderAPI" |  | ||||||
| main: "me.clip.placeholderapi.PlaceholderAPIPlugin" | main: "me.clip.placeholderapi.PlaceholderAPIPlugin" | ||||||
|  |  | ||||||
| version: "@version@" | version: "@version@" | ||||||
| @@ -698,15 +21,15 @@ permissions: | |||||||
|   placeholderapi.admin: |   placeholderapi.admin: | ||||||
|     description: "Ability to use all PAPI commands" |     description: "Ability to use all PAPI commands" | ||||||
|     children: |     children: | ||||||
|         placeholderapi.help: true |       placeholderapi.help: true | ||||||
|         placeholderapi.info: true |       placeholderapi.info: true | ||||||
|         placeholderapi.list: true |       placeholderapi.list: true | ||||||
|         placeholderapi.parse: true |       placeholderapi.parse: true | ||||||
|         placeholderapi.reload: true |       placeholderapi.reload: true | ||||||
|         placeholderapi.version: true |       placeholderapi.version: true | ||||||
|         placeholderapi.register: true |       placeholderapi.register: true | ||||||
|         placeholderapi.unregister: true |       placeholderapi.unregister: true | ||||||
|         placeholderapi.updatenotify: true |       placeholderapi.updatenotify: true | ||||||
|   placeholderapi.ecloud.*: |   placeholderapi.ecloud.*: | ||||||
|     description: "Ability to use all PAPI ecloud commands" |     description: "Ability to use all PAPI ecloud commands" | ||||||
|     children: |     children: | ||||||
|   | |||||||
| @@ -29,75 +29,67 @@ import org.bukkit.OfflinePlayer; | |||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
| public interface Values | public interface Values { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	String SMALL_TEXT = "My name is %player_name%"; |   String SMALL_TEXT = "My name is %player_name%"; | ||||||
| 	String LARGE_TEXT = "My name is %player_name% and my location is (%player_x%, %player_y%, %player_z%), this placeholder is invalid %server_name%"; |   String LARGE_TEXT = "My name is %player_name% and my location is (%player_x%, %player_y%, %player_z%), this placeholder is invalid %server_name%"; | ||||||
|  |  | ||||||
| 	ImmutableMap<String, PlaceholderExpansion> PLACEHOLDERS = ImmutableMap.<String, PlaceholderExpansion>builder() |   ImmutableMap<String, PlaceholderExpansion> PLACEHOLDERS = ImmutableMap.<String, PlaceholderExpansion>builder() | ||||||
| 			.put("player", new MockPlayerPlaceholderExpansion()) |       .put("player", new MockPlayerPlaceholderExpansion()) | ||||||
| 			.build(); |       .build(); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	Replacer CHARS_REPLACER = new CharsReplacer(Replacer.Closure.PERCENT); |   Replacer CHARS_REPLACER = new CharsReplacer(Replacer.Closure.PERCENT); | ||||||
| 	Replacer REGEX_REPLACER = new RegexReplacer(Replacer.Closure.PERCENT); |   Replacer REGEX_REPLACER = new RegexReplacer(Replacer.Closure.PERCENT); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	final class MockPlayerPlaceholderExpansion extends PlaceholderExpansion |   final class MockPlayerPlaceholderExpansion extends PlaceholderExpansion { | ||||||
| 	{ |  | ||||||
|  |  | ||||||
| 		public static final String PLAYER_X    = "10"; |     public static final String PLAYER_X = "10"; | ||||||
| 		public static final String PLAYER_Y    = "20"; |     public static final String PLAYER_Y = "20"; | ||||||
| 		public static final String PLAYER_Z    = "30"; |     public static final String PLAYER_Z = "30"; | ||||||
| 		public static final String PLAYER_NAME = "Sxtanna"; |     public static final String PLAYER_NAME = "Sxtanna"; | ||||||
|  |  | ||||||
|  |  | ||||||
| 		@NotNull |     @NotNull | ||||||
| 		@Override |     @Override | ||||||
| 		public String getIdentifier() |     public String getIdentifier() { | ||||||
| 		{ |       return "player"; | ||||||
| 			return "player"; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		@NotNull |     @NotNull | ||||||
| 		@Override |     @Override | ||||||
| 		public String getAuthor() |     public String getAuthor() { | ||||||
| 		{ |       return "Sxtanna"; | ||||||
| 			return "Sxtanna"; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		@NotNull |     @NotNull | ||||||
| 		@Override |     @Override | ||||||
| 		public String getVersion() |     public String getVersion() { | ||||||
| 		{ |       return "1.0"; | ||||||
| 			return "1.0"; |     } | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		@Override |     @Override | ||||||
| 		public String onRequest(@Nullable final OfflinePlayer player, @NotNull final String params) |     public String onRequest(@Nullable final OfflinePlayer player, @NotNull final String params) { | ||||||
| 		{ |       final String[] parts = params.split("_"); | ||||||
| 			final String[] parts = params.split("_"); |       if (parts.length == 0) { | ||||||
| 			if (parts.length == 0) |         return null; | ||||||
| 			{ |       } | ||||||
| 				return null; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			switch (parts[0]) |       switch (parts[0]) { | ||||||
| 			{ |         case "name": | ||||||
| 				case "name": |           return PLAYER_NAME; | ||||||
| 					return PLAYER_NAME; |         case "x": | ||||||
| 				case "x": |           return PLAYER_X; | ||||||
| 					return PLAYER_X; |         case "y": | ||||||
| 				case "y": |           return PLAYER_Y; | ||||||
| 					return PLAYER_Y; |         case "z": | ||||||
| 				case "z": |           return PLAYER_Z; | ||||||
| 					return PLAYER_Z; |       } | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			return null; |       return null; | ||||||
| 		} |     } | ||||||
|  |  | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -23,31 +23,26 @@ package me.clip.placeholderapi.replacer; | |||||||
| import me.clip.placeholderapi.Values; | import me.clip.placeholderapi.Values; | ||||||
| import org.openjdk.jmh.annotations.Benchmark; | import org.openjdk.jmh.annotations.Benchmark; | ||||||
|  |  | ||||||
| public class ReplacerBenchmarks | public class ReplacerBenchmarks { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	@Benchmark |   @Benchmark | ||||||
| 	public void measureCharsReplacerSmallText() |   public void measureCharsReplacerSmallText() { | ||||||
| 	{ |     Values.CHARS_REPLACER.apply(Values.SMALL_TEXT, null, Values.PLACEHOLDERS::get); | ||||||
| 		Values.CHARS_REPLACER.apply(Values.SMALL_TEXT, null, Values.PLACEHOLDERS::get); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Benchmark |   @Benchmark | ||||||
| 	public void measureRegexReplacerSmallText() |   public void measureRegexReplacerSmallText() { | ||||||
| 	{ |     Values.REGEX_REPLACER.apply(Values.SMALL_TEXT, null, Values.PLACEHOLDERS::get); | ||||||
| 		Values.REGEX_REPLACER.apply(Values.SMALL_TEXT, null, Values.PLACEHOLDERS::get); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Benchmark |   @Benchmark | ||||||
| 	public void measureCharsReplacerLargeText() |   public void measureCharsReplacerLargeText() { | ||||||
| 	{ |     Values.CHARS_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get); | ||||||
| 		Values.CHARS_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Benchmark |   @Benchmark | ||||||
| 	public void measureRegexReplacerLargeText() |   public void measureRegexReplacerLargeText() { | ||||||
| 	{ |     Values.REGEX_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get); | ||||||
| 		Values.REGEX_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get); |   } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -20,76 +20,80 @@ | |||||||
|  |  | ||||||
| package me.clip.placeholderapi.replacer; | package me.clip.placeholderapi.replacer; | ||||||
|  |  | ||||||
| import me.clip.placeholderapi.Values; |  | ||||||
| import org.junit.jupiter.api.Test; |  | ||||||
|  |  | ||||||
| import static me.clip.placeholderapi.Values.MockPlayerPlaceholderExpansion.PLAYER_NAME; | import static me.clip.placeholderapi.Values.MockPlayerPlaceholderExpansion.PLAYER_NAME; | ||||||
| import static me.clip.placeholderapi.Values.MockPlayerPlaceholderExpansion.PLAYER_X; | import static me.clip.placeholderapi.Values.MockPlayerPlaceholderExpansion.PLAYER_X; | ||||||
| import static me.clip.placeholderapi.Values.MockPlayerPlaceholderExpansion.PLAYER_Y; | import static me.clip.placeholderapi.Values.MockPlayerPlaceholderExpansion.PLAYER_Y; | ||||||
| import static me.clip.placeholderapi.Values.MockPlayerPlaceholderExpansion.PLAYER_Z; | import static me.clip.placeholderapi.Values.MockPlayerPlaceholderExpansion.PLAYER_Z; | ||||||
| import static org.junit.jupiter.api.Assertions.assertEquals; | import static org.junit.jupiter.api.Assertions.assertEquals; | ||||||
|  |  | ||||||
| public final class ReplacerUnitTester | import me.clip.placeholderapi.Values; | ||||||
| { | import org.junit.jupiter.api.Test; | ||||||
|  |  | ||||||
| 	@Test | public final class ReplacerUnitTester { | ||||||
| 	void testCharsReplacerProducesExpectedSingleValue() |  | ||||||
| 	{ |  | ||||||
| 		assertEquals(PLAYER_NAME, Values.CHARS_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get)); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Test |   @Test | ||||||
| 	void testRegexReplacerProducesExpectedSingleValue() |   void testCharsReplacerProducesExpectedSingleValue() { | ||||||
| 	{ |     assertEquals(PLAYER_NAME, | ||||||
| 		assertEquals(PLAYER_NAME, Values.REGEX_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get)); |         Values.CHARS_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get)); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	@Test |   @Test | ||||||
| 	void testCharsReplacerProducesExpectedSentence() |   void testRegexReplacerProducesExpectedSingleValue() { | ||||||
| 	{ |     assertEquals(PLAYER_NAME, | ||||||
| 		assertEquals(String.format("My name is %s and my location is (%s, %s, %s), this placeholder is invalid %%server_name%%", PLAYER_NAME, PLAYER_X, PLAYER_Y, PLAYER_Z), Values.CHARS_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get)); |         Values.REGEX_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get)); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	@Test |   @Test | ||||||
| 	void testRegexReplacerProducesExpectedSentence() |   void testCharsReplacerProducesExpectedSentence() { | ||||||
| 	{ |     assertEquals(String.format( | ||||||
| 		assertEquals(String.format("My name is %s and my location is (%s, %s, %s), this placeholder is invalid %%server_name%%", PLAYER_NAME, PLAYER_X, PLAYER_Y, PLAYER_Z), Values.REGEX_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get)); |         "My name is %s and my location is (%s, %s, %s), this placeholder is invalid %%server_name%%", | ||||||
| 	} |         PLAYER_NAME, PLAYER_X, PLAYER_Y, PLAYER_Z), | ||||||
|  |         Values.CHARS_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get)); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 	@Test |   @Test | ||||||
| 	void testResultsAreTheSameAsReplacement() |   void testRegexReplacerProducesExpectedSentence() { | ||||||
| 	{ |     assertEquals(String.format( | ||||||
| 		final String resultChars = Values.CHARS_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get); |         "My name is %s and my location is (%s, %s, %s), this placeholder is invalid %%server_name%%", | ||||||
| 		final String resultRegex = Values.REGEX_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get); |         PLAYER_NAME, PLAYER_X, PLAYER_Y, PLAYER_Z), | ||||||
|  |         Values.REGEX_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get)); | ||||||
|  |   } | ||||||
|  |  | ||||||
| 		assertEquals(resultChars, resultRegex); |   @Test | ||||||
|  |   void testResultsAreTheSameAsReplacement() { | ||||||
|  |     final String resultChars = Values.CHARS_REPLACER | ||||||
|  |         .apply("%player_name%", null, Values.PLACEHOLDERS::get); | ||||||
|  |     final String resultRegex = Values.REGEX_REPLACER | ||||||
|  |         .apply("%player_name%", null, Values.PLACEHOLDERS::get); | ||||||
|  |  | ||||||
| 		assertEquals(PLAYER_NAME, resultChars); |     assertEquals(resultChars, resultRegex); | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Test |     assertEquals(PLAYER_NAME, resultChars); | ||||||
| 	void testResultsAreTheSameNoReplacement() |   } | ||||||
| 	{ |  | ||||||
| 		final String resultChars = Values.CHARS_REPLACER.apply("%player_location%", null, Values.PLACEHOLDERS::get); |  | ||||||
| 		final String resultRegex = Values.REGEX_REPLACER.apply("%player_location%", null, Values.PLACEHOLDERS::get); |  | ||||||
|  |  | ||||||
| 		assertEquals(resultChars, resultRegex); |   @Test | ||||||
| 	} |   void testResultsAreTheSameNoReplacement() { | ||||||
|  |     final String resultChars = Values.CHARS_REPLACER | ||||||
|  |         .apply("%player_location%", null, Values.PLACEHOLDERS::get); | ||||||
|  |     final String resultRegex = Values.REGEX_REPLACER | ||||||
|  |         .apply("%player_location%", null, Values.PLACEHOLDERS::get); | ||||||
|  |  | ||||||
| 	@Test |     assertEquals(resultChars, resultRegex); | ||||||
| 	void testCharsReplacerIgnoresMalformed() |   } | ||||||
| 	{ |  | ||||||
| 		final String text = "10% and %hello world 15%"; |  | ||||||
|  |  | ||||||
| 		assertEquals(text, Values.CHARS_REPLACER.apply(text, null, Values.PLACEHOLDERS::get)); |   @Test | ||||||
| 	} |   void testCharsReplacerIgnoresMalformed() { | ||||||
|  |     final String text = "10% and %hello world 15%"; | ||||||
|  |  | ||||||
| 	@Test |     assertEquals(text, Values.CHARS_REPLACER.apply(text, null, Values.PLACEHOLDERS::get)); | ||||||
| 	void testCharsReplacerHandlesEscapedHex() |   } | ||||||
| 	{ |  | ||||||
| 		final String text = "\\&xffffffThis should not change."; |  | ||||||
|  |  | ||||||
| 		assertEquals(text.substring(1), Values.CHARS_REPLACER.apply(text, null, Values.PLACEHOLDERS::get)); |   @Test | ||||||
| 	} |   void testCharsReplacerHandlesEscapedHex() { | ||||||
|  |     final String text = "\\&xffffffThis should not change."; | ||||||
|  |  | ||||||
|  |     assertEquals(text.substring(1), | ||||||
|  |         Values.CHARS_REPLACER.apply(text, null, Values.PLACEHOLDERS::get)); | ||||||
|  |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -889,10 +889,6 @@ This placeholder is for all players on the server. | |||||||
| - ### **Statistic** | - ### **Statistic** | ||||||
| > /papi ecloud download Statistic | > /papi ecloud download Statistic | ||||||
|  |  | ||||||
| **For MC v1.12.2 or older:** <br /> |  | ||||||
| You'll have to download v1.7.0 manually: <br /> |  | ||||||
| Download the jar file from [the eCloud](https://api.extendedclip.com/expansions/statistic/versions/statistic-170/) then place it in your `plugins/PlaceholderAPI/expansions` folder. After that reload PlaceholderAPI `/papi reload`. |  | ||||||
|  |  | ||||||
| Supports all statistics in [SpigotAPI](https://helpch.at/docs/1.13.1/org/bukkit/Statistic.html). `%statistic_<StatisticType>%` | Supports all statistics in [SpigotAPI](https://helpch.at/docs/1.13.1/org/bukkit/Statistic.html). `%statistic_<StatisticType>%` | ||||||
|  |  | ||||||
| For specific blocks, items, entities, ... | For specific blocks, items, entities, ... | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user