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 --> |  | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							| @@ -1,8 +1,13 @@ | |||||||
| ## Please read | <!-- | ||||||
|  |   ### Please read ### | ||||||
|   Please make sure you checked the following: |   Please make sure you checked the following: | ||||||
| - You checked the [Pull requests] page for any upcoming changes. |  | ||||||
|  |   - You checked the Pull requests page for any upcoming changes. | ||||||
|   - You documented any public code that the end-user might use. |   - You documented any public code that the end-user might use. | ||||||
| - You followed the [contributing file]  |   - 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 | ||||||
|   | |||||||
| @@ -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?) --> | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								build.gradle
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								build.gradle
									
									
									
									
									
								
							| @@ -6,7 +6,7 @@ plugins { | |||||||
| } | } | ||||||
|  |  | ||||||
| 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!" | ||||||
|  |  | ||||||
| @@ -52,12 +52,14 @@ shadowJar { | |||||||
| } | } | ||||||
|  |  | ||||||
| license { | license { | ||||||
|  |     include '**/*.java' | ||||||
|  |  | ||||||
|     matching('**/*.java') { |     matching('**/*.java') { | ||||||
| 		header = file('headers/main.txt') |         header = file('config/headers/main.txt') | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     matching('**/JSONMessage.java') { |     matching('**/JSONMessage.java') { | ||||||
| 		header = file('headers/jsonmessage.txt') |         header = file('config/headers/jsonmessage.txt') | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ext { |     ext { | ||||||
| @@ -92,11 +94,23 @@ publishing { | |||||||
|  |  | ||||||
|     publications { |     publications { | ||||||
|         mavenJava(MavenPublication) { |         mavenJava(MavenPublication) { | ||||||
|  |             artifactId = "placeholderapi" | ||||||
|  |  | ||||||
|             from components.java |             from components.java | ||||||
|  |  | ||||||
|             pom.withXml { |             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().appendNode("packaging", "jar") | ||||||
|                 asNode().remove(asNode().get("dependencies")) |                 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") | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
							
								
								
									
										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,42 +40,31 @@ 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) { | ||||||
| 		catch (final ExceptionInInitializerError | ClassNotFoundException ignored) |  | ||||||
| 		{ |  | ||||||
|       isSpigot = false; |       isSpigot = false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     VERSION = new Version(version, isSpigot); |     VERSION = new Version(version, isSpigot); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 	private static PlaceholderAPIPlugin instance; |  | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
|   private final PlaceholderAPIConfig config = new PlaceholderAPIConfig(this); |   private final PlaceholderAPIConfig config = new PlaceholderAPIConfig(this); | ||||||
|  |  | ||||||
| @@ -80,139 +73,6 @@ public final class PlaceholderAPIPlugin extends JavaPlugin | |||||||
|   @NotNull |   @NotNull | ||||||
|   private final CloudExpansionManager cloudExpansionManager = new CloudExpansionManager(this); |   private final CloudExpansionManager cloudExpansionManager = new CloudExpansionManager(this); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@Override |  | ||||||
| 	public void onLoad() |  | ||||||
| 	{ |  | ||||||
| 		instance = this; |  | ||||||
|  |  | ||||||
| 		saveDefaultConfig(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Override |  | ||||||
| 	public void onEnable() |  | ||||||
| 	{ |  | ||||||
| 		setupCommand(); |  | ||||||
| 		setupMetrics(); |  | ||||||
| 		setupExpansions(); |  | ||||||
|  |  | ||||||
| 		if (config.isCloudEnabled()) |  | ||||||
| 		{ |  | ||||||
| 			getCloudExpansionManager().load(); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (config.checkUpdates()) |  | ||||||
| 		{ |  | ||||||
| 			new UpdateChecker(this).fetch(); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Override |  | ||||||
| 	public void onDisable() |  | ||||||
| 	{ |  | ||||||
| 		getCloudExpansionManager().kill(); |  | ||||||
| 		getLocalExpansionManager().kill(); |  | ||||||
|  |  | ||||||
| 		HandlerList.unregisterAll(this); |  | ||||||
|  |  | ||||||
| 		Bukkit.getScheduler().cancelTasks(this); |  | ||||||
|  |  | ||||||
| 		instance = null; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public void reloadConf(@NotNull final CommandSender sender) |  | ||||||
| 	{ |  | ||||||
| 		getLocalExpansionManager().kill(); |  | ||||||
|  |  | ||||||
| 		reloadConfig(); |  | ||||||
|  |  | ||||||
| 		getLocalExpansionManager().load(sender); |  | ||||||
|  |  | ||||||
| 		if (config.isCloudEnabled()) |  | ||||||
| 		{ |  | ||||||
| 			getCloudExpansionManager().load(); |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			getCloudExpansionManager().kill(); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public LocalExpansionManager getLocalExpansionManager() |  | ||||||
| 	{ |  | ||||||
| 		return localExpansionManager; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public CloudExpansionManager getCloudExpansionManager() |  | ||||||
| 	{ |  | ||||||
| 		return cloudExpansionManager; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Obtain the configuration class for PlaceholderAPI. |  | ||||||
| 	 * |  | ||||||
| 	 * @return PlaceholderAPIConfig instance |  | ||||||
| 	 */ |  | ||||||
| 	@NotNull |  | ||||||
| 	public PlaceholderAPIConfig getPlaceholderAPIConfig() |  | ||||||
| 	{ |  | ||||||
| 		return config; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	private void setupCommand() |  | ||||||
| 	{ |  | ||||||
| 		final PluginCommand pluginCommand = getCommand("placeholderapi"); |  | ||||||
| 		if (pluginCommand == null) |  | ||||||
| 		{ |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final PlaceholderCommandRouter router = new PlaceholderCommandRouter(this); |  | ||||||
| 		pluginCommand.setExecutor(router); |  | ||||||
| 		pluginCommand.setTabCompleter(router); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	private void setupMetrics() |  | ||||||
| 	{ |  | ||||||
| 		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<>(); |  | ||||||
|  |  | ||||||
| 			for (final PlaceholderExpansion expansion : getLocalExpansionManager().getExpansions()) |  | ||||||
| 			{ |  | ||||||
| 				values.put(expansion.getRequiredPlugin() == null ? expansion.getIdentifier() : expansion.getRequiredPlugin(), 1); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			return values; |  | ||||||
| 		})); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	private void setupExpansions() |  | ||||||
| 	{ |  | ||||||
| 		Bukkit.getPluginManager().registerEvents(getLocalExpansionManager(), this); |  | ||||||
|  |  | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
| 			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 |    * 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 |    * class, this is the main class that extends JavaPlugin. For most API methods, use static methods | ||||||
| @@ -221,20 +81,17 @@ public final class PlaceholderAPIPlugin extends JavaPlugin | |||||||
|    * @return PlaceholderAPIPlugin instance |    * @return PlaceholderAPIPlugin instance | ||||||
|    */ |    */ | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public static PlaceholderAPIPlugin getInstance() |   public static PlaceholderAPIPlugin getInstance() { | ||||||
| 	{ |  | ||||||
|     return instance; |     return instance; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Get the configurable {@linkplain String} value that should be returned when a boolean is true |    * Get the configurable {@linkplain String} value that should be returned when a boolean is true | ||||||
|    * |    * | ||||||
|    * @return string value of true |    * @return string value of true | ||||||
|    */ |    */ | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public static String booleanTrue() |   public static String booleanTrue() { | ||||||
| 	{ |  | ||||||
|     return getInstance().getPlaceholderAPIConfig().booleanTrue(); |     return getInstance().getPlaceholderAPIConfig().booleanTrue(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -244,8 +101,7 @@ public final class PlaceholderAPIPlugin extends JavaPlugin | |||||||
|    * @return string value of false |    * @return string value of false | ||||||
|    */ |    */ | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public static String booleanFalse() |   public static String booleanFalse() { | ||||||
| 	{ |  | ||||||
|     return getInstance().getPlaceholderAPIConfig().booleanFalse(); |     return getInstance().getPlaceholderAPIConfig().booleanFalse(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -256,23 +112,128 @@ public final class PlaceholderAPIPlugin extends JavaPlugin | |||||||
|    * @return date format |    * @return date format | ||||||
|    */ |    */ | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public static SimpleDateFormat getDateFormat() |   public static SimpleDateFormat getDateFormat() { | ||||||
| 	{ |     try { | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
|       return new SimpleDateFormat(getInstance().getPlaceholderAPIConfig().dateFormat()); |       return new SimpleDateFormat(getInstance().getPlaceholderAPIConfig().dateFormat()); | ||||||
| 		} |     } catch (final IllegalArgumentException ex) { | ||||||
| 		catch (final IllegalArgumentException ex) |  | ||||||
| 		{ |  | ||||||
|       getInstance().getLogger().log(Level.WARNING, "configured date format is invalid", ex); |       getInstance().getLogger().log(Level.WARNING, "configured date format is invalid", ex); | ||||||
|       return new SimpleDateFormat("MM/dd/yy HH:mm:ss"); |       return new SimpleDateFormat("MM/dd/yy HH:mm:ss"); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   public static Version getServerVersion() { | ||||||
| 	public static Version getServerVersion() |  | ||||||
| 	{ |  | ||||||
|     return VERSION; |     return VERSION; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void onLoad() { | ||||||
|  |     instance = this; | ||||||
|  |  | ||||||
|  |     saveDefaultConfig(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void onEnable() { | ||||||
|  |     setupCommand(); | ||||||
|  |     setupMetrics(); | ||||||
|  |     setupExpansions(); | ||||||
|  |  | ||||||
|  |     if (config.isCloudEnabled()) { | ||||||
|  |       getCloudExpansionManager().load(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (config.checkUpdates()) { | ||||||
|  |       new UpdateChecker(this).fetch(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void onDisable() { | ||||||
|  |     getCloudExpansionManager().kill(); | ||||||
|  |     getLocalExpansionManager().kill(); | ||||||
|  |  | ||||||
|  |     HandlerList.unregisterAll(this); | ||||||
|  |  | ||||||
|  |     Bukkit.getScheduler().cancelTasks(this); | ||||||
|  |  | ||||||
|  |     instance = null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void reloadConf(@NotNull final CommandSender sender) { | ||||||
|  |     getLocalExpansionManager().kill(); | ||||||
|  |  | ||||||
|  |     reloadConfig(); | ||||||
|  |  | ||||||
|  |     getLocalExpansionManager().load(sender); | ||||||
|  |  | ||||||
|  |     if (config.isCloudEnabled()) { | ||||||
|  |       getCloudExpansionManager().load(); | ||||||
|  |     } else { | ||||||
|  |       getCloudExpansionManager().kill(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
|  |   public LocalExpansionManager getLocalExpansionManager() { | ||||||
|  |     return localExpansionManager; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
|  |   public CloudExpansionManager getCloudExpansionManager() { | ||||||
|  |     return cloudExpansionManager; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Obtain the configuration class for PlaceholderAPI. | ||||||
|  |    * | ||||||
|  |    * @return PlaceholderAPIConfig instance | ||||||
|  |    */ | ||||||
|  |   @NotNull | ||||||
|  |   public PlaceholderAPIConfig getPlaceholderAPIConfig() { | ||||||
|  |     return config; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private void setupCommand() { | ||||||
|  |     final PluginCommand pluginCommand = getCommand("placeholderapi"); | ||||||
|  |     if (pluginCommand == null) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     final PlaceholderCommandRouter router = new PlaceholderCommandRouter(this); | ||||||
|  |     pluginCommand.setExecutor(router); | ||||||
|  |     pluginCommand.setTabCompleter(router); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private void setupMetrics() { | ||||||
|  |     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<>(); | ||||||
|  |  | ||||||
|  |       for (final PlaceholderExpansion expansion : getLocalExpansionManager().getExpansions()) { | ||||||
|  |         values.put(expansion.getRequiredPlugin() == null ? expansion.getIdentifier() | ||||||
|  |             : expansion.getRequiredPlugin(), 1); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       return values; | ||||||
|  |     })); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private void setupExpansions() { | ||||||
|  |     Bukkit.getPluginManager().registerEvents(getLocalExpansionManager(), this); | ||||||
|  |  | ||||||
|  |     try { | ||||||
|  |       Class.forName("org.bukkit.event.server.ServerLoadEvent"); | ||||||
|  |       new ServerLoadEventListener(this); | ||||||
|  |     } catch (final ExceptionInInitializerError | ClassNotFoundException ignored) { | ||||||
|  |       Bukkit.getScheduler() | ||||||
|  |           .runTaskLater(this, () -> getLocalExpansionManager().load(Bukkit.getConsoleSender()), 1); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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()) { | ||||||
| 	{ |  | ||||||
| 		if (player != null && player.isOnline()) |  | ||||||
| 		{ |  | ||||||
|       return onPlaceholderRequest((Player) player, params); |       return onPlaceholderRequest((Player) player, params); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return onPlaceholderRequest(null, params); |     return onPlaceholderRequest(null, params); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 	/** |   public String onPlaceholderRequest(final Player player, @NotNull final String 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; |     return null; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,18 +22,16 @@ 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 |   @NotNull | ||||||
|   private final String label; |   private final String label; | ||||||
| @@ -44,75 +42,66 @@ public abstract class PlaceholderCommand | |||||||
|   private String permission; |   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())); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   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); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public final String getLabel() |   public final String getLabel() { | ||||||
| 	{ |  | ||||||
|     return label; |     return label; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
|   @Unmodifiable |   @Unmodifiable | ||||||
| 	public final Set<String> getAlias() |   public final Set<String> getAlias() { | ||||||
| 	{ |  | ||||||
|     return ImmutableSet.copyOf(alias); |     return ImmutableSet.copyOf(alias); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
|   @Unmodifiable |   @Unmodifiable | ||||||
| 	public final Set<String> getLabels() |   public final Set<String> getLabels() { | ||||||
| 	{ |  | ||||||
|     return ImmutableSet.<String>builder().add(label).addAll(alias).build(); |     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, | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) |       @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,11 +48,7 @@ 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 |   @Unmodifiable | ||||||
|   private static final List<PlaceholderCommand> COMMANDS = ImmutableList.of(new CommandHelp(), |   private static final List<PlaceholderCommand> COMMANDS = ImmutableList.of(new CommandHelp(), | ||||||
| @@ -67,14 +70,12 @@ public final class PlaceholderCommandRouter implements CommandExecutor, TabCompl | |||||||
|   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)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -83,13 +84,11 @@ public final class PlaceholderCommandRouter implements CommandExecutor, TabCompl | |||||||
|  |  | ||||||
|  |  | ||||||
|   @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()); | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -99,42 +98,42 @@ public final class PlaceholderCommandRouter implements CommandExecutor, TabCompl | |||||||
|     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 | ||||||
|  |         .filterByPermission(sender, commands.values().stream()).map(PlaceholderCommand::getLabels) | ||||||
|  |         .flatMap(Collection::stream); | ||||||
|     PlaceholderCommand.suggestByParameter(targets, suggestions, args.length == 0 ? null : args[0]); |     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,16 +33,11 @@ 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 |   @Unmodifiable | ||||||
| 	private static final List<PlaceholderCommand> COMMANDS = ImmutableList.of(new CommandECloudClear(), |   private static final List<PlaceholderCommand> COMMANDS = ImmutableList | ||||||
|  |       .of(new CommandECloudClear(), | ||||||
|           new CommandECloudToggle(), |           new CommandECloudToggle(), | ||||||
|           new CommandECloudStatus(), |           new CommandECloudStatus(), | ||||||
|           new CommandECloudUpdate(), |           new CommandECloudUpdate(), | ||||||
| @@ -48,9 +47,9 @@ public final class CommandECloud extends PlaceholderCommand | |||||||
|           new CommandECloudExpansionList(), |           new CommandECloudExpansionList(), | ||||||
|           new CommandECloudExpansionPlaceholders()); |           new CommandECloudExpansionPlaceholders()); | ||||||
|  |  | ||||||
| 	static |   static { | ||||||
| 	{ |     COMMANDS | ||||||
| 		COMMANDS.forEach(command -> command.setPermission("placeholderapi.ecloud." + command.getLabel())); |         .forEach(command -> command.setPermission("placeholderapi.ecloud." + command.getLabel())); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
| @@ -58,14 +57,12 @@ public final class CommandECloud extends PlaceholderCommand | |||||||
|   private final Map<String, PlaceholderCommand> commands; |   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)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -74,10 +71,10 @@ public final class CommandECloud extends PlaceholderCommand | |||||||
|  |  | ||||||
|  |  | ||||||
|   @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- ", | ||||||
|           " ", |           " ", | ||||||
| @@ -106,21 +103,19 @@ public final class CommandECloud extends PlaceholderCommand | |||||||
|     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; | ||||||
| @@ -130,11 +125,12 @@ public final class CommandECloud extends PlaceholderCommand | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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()) | ||||||
|  |           .map(PlaceholderCommand::getLabels).flatMap(Collection::stream); | ||||||
|       suggestByParameter(targets, suggestions, params.isEmpty() ? null : params.get(0)); |       suggestByParameter(targets, suggestions, params.isEmpty() ? null : params.get(0)); | ||||||
|  |  | ||||||
|       return; // send sub commands |       return; // send sub commands | ||||||
| @@ -143,8 +139,7 @@ public final class CommandECloud extends PlaceholderCommand | |||||||
|     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; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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,19 +28,16 @@ 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() { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	public CommandECloudClear() |  | ||||||
| 	{ |  | ||||||
|     super("clear"); |     super("clear"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|     plugin.getCloudExpansionManager().clean(); |     plugin.getCloudExpansionManager().clean(); | ||||||
|     Msg.msg(sender, |     Msg.msg(sender, | ||||||
|         "&aThe eCloud cache has been cleared!"); |         "&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,52 +31,41 @@ 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() { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	public CommandECloudDownload() |  | ||||||
| 	{ |  | ||||||
|     super("download"); |     super("download"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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 supply the name of an expansion."); |           "&cYou must supply the name of an expansion."); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		final CloudExpansion expansion = plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)).orElse(null); |     final CloudExpansion expansion = plugin.getCloudExpansionManager() | ||||||
| 		if (expansion == null) |         .findCloudExpansionByName(params.get(0)).orElse(null); | ||||||
| 		{ |     if (expansion == null) { | ||||||
|       Msg.msg(sender, |       Msg.msg(sender, | ||||||
|           "&cFailed to find an expansion named: &f" + params.get(0)); |           "&cFailed to find an expansion named: &f" + params.get(0)); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     final CloudExpansion.Version version; |     final CloudExpansion.Version version; | ||||||
| 		if (params.size() < 2) |     if (params.size() < 2) { | ||||||
| 		{ |  | ||||||
|       version = expansion.getVersion(expansion.getLatestVersion()); |       version = expansion.getVersion(expansion.getLatestVersion()); | ||||||
| 			if (version == null) |       if (version == null) { | ||||||
| 			{ |  | ||||||
|         Msg.msg(sender, |         Msg.msg(sender, | ||||||
|             "&cCould not find latest version for expansion."); |             "&cCould not find latest version for expansion."); | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
| 		} |     } else { | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
|       version = expansion.getVersion(params.get(1)); |       version = expansion.getVersion(params.get(1)); | ||||||
| 			if (version == null) |       if (version == null) { | ||||||
| 			{ |  | ||||||
|         Msg.msg(sender, |         Msg.msg(sender, | ||||||
|             "&cCould not find specified version: &f" + params.get(1), |             "&cCould not find specified version: &f" + params.get(1), | ||||||
|             "&7Available versions: &f" + expansion.getAvailableVersions()); |             "&7Available versions: &f" + expansion.getAvailableVersions()); | ||||||
| @@ -81,41 +73,43 @@ public final class CommandECloudDownload extends PlaceholderCommand | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		plugin.getCloudExpansionManager().downloadExpansion(expansion, version).whenComplete((file, exception) -> { |     plugin.getCloudExpansionManager().downloadExpansion(expansion, version) | ||||||
| 			if (exception != null) |         .whenComplete((file, exception) -> { | ||||||
| 			{ |           if (exception != null) { | ||||||
|             Msg.msg(sender, |             Msg.msg(sender, | ||||||
|                 "&cFailed to download expansion: &f" + exception.getMessage()); |                 "&cFailed to download expansion: &f" + exception.getMessage()); | ||||||
|             return; |             return; | ||||||
|           } |           } | ||||||
|  |  | ||||||
|           Msg.msg(sender, |           Msg.msg(sender, | ||||||
| 					"&aSuccessfully downloaded expansion &f" + expansion.getName() + " [" + version.getVersion() + "] &ato file: &f" + file.getName(), |               "&aSuccessfully downloaded expansion &f" + expansion.getName() + " [" + version | ||||||
|  |                   .getVersion() + "] &ato file: &f" + file.getName(), | ||||||
|               "&aMake sure to type &f/papi reload &ato enable your new expansion!"); |               "&aMake sure to type &f/papi reload &ato enable your new expansion!"); | ||||||
|  |  | ||||||
|           plugin.getCloudExpansionManager().clean(); |           plugin.getCloudExpansionManager().clean(); | ||||||
| 			plugin.getCloudExpansionManager().fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); |           plugin.getCloudExpansionManager() | ||||||
|  |               .fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); | ||||||
|         }); |         }); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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() > 2) |       @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) { | ||||||
| 		{ |     if (params.size() > 2) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		if (params.size() <= 1) |     if (params.size() <= 1) { | ||||||
| 		{ |       final Stream<String> names = plugin.getCloudExpansionManager().getCloudExpansions().values() | ||||||
| 			final Stream<String> names = plugin.getCloudExpansionManager().getCloudExpansions().values().stream().map(CloudExpansion::getName).map(name -> name.replace(' ', '_')); |           .stream().map(CloudExpansion::getName).map(name -> name.replace(' ', '_')); | ||||||
|       suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); |       suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		final Optional<CloudExpansion> expansion = plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)); |     final Optional<CloudExpansion> expansion = plugin.getCloudExpansionManager() | ||||||
| 		if (!expansion.isPresent()) |         .findCloudExpansionByName(params.get(0)); | ||||||
| 		{ |     if (!expansion.isPresent()) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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,31 +31,25 @@ 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() { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	public CommandECloudExpansionInfo() |  | ||||||
| 	{ |  | ||||||
|     super("info"); |     super("info"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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 specify the name of the expansion."); |           "&cYou must specify the name of the expansion."); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		final CloudExpansion expansion = plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)).orElse(null); |     final CloudExpansion expansion = plugin.getCloudExpansionManager() | ||||||
| 		if (expansion == null) |         .findCloudExpansionByName(params.get(0)).orElse(null); | ||||||
| 		{ |     if (expansion == null) { | ||||||
|       Msg.msg(sender, |       Msg.msg(sender, | ||||||
|           "&cThere is no expansion with the name: &f" + params.get(0)); |           "&cThere is no expansion with the name: &f" + params.get(0)); | ||||||
|       return; |       return; | ||||||
| @@ -71,8 +68,7 @@ public final class CommandECloudExpansionInfo extends PlaceholderCommand | |||||||
|         .append(expansion.isVerified() ? "&a&l✔" : "&c&l❌") |         .append(expansion.isVerified() ? "&a&l✔" : "&c&l❌") | ||||||
|         .append('\n'); |         .append('\n'); | ||||||
|  |  | ||||||
| 		if (params.size() < 2) |     if (params.size() < 2) { | ||||||
| 		{ |  | ||||||
|       builder.append("&bLatest Version: &f") |       builder.append("&bLatest Version: &f") | ||||||
|           .append(expansion.getLatestVersion()) |           .append(expansion.getLatestVersion()) | ||||||
|           .append('\n') |           .append('\n') | ||||||
| @@ -83,12 +79,9 @@ public final class CommandECloudExpansionInfo extends PlaceholderCommand | |||||||
|           .append("&bRelease Notes: &f") |           .append("&bRelease Notes: &f") | ||||||
|           .append(expansion.getVersion().getReleaseNotes()) |           .append(expansion.getVersion().getReleaseNotes()) | ||||||
|           .append('\n'); |           .append('\n'); | ||||||
| 		} |     } else { | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
|       final CloudExpansion.Version version = expansion.getVersion(params.get(1)); |       final CloudExpansion.Version version = expansion.getVersion(params.get(1)); | ||||||
| 			if (version == null) |       if (version == null) { | ||||||
| 			{ |  | ||||||
|         Msg.msg(sender, |         Msg.msg(sender, | ||||||
|             "&cCould not find specified version: &f" + params.get(1), |             "&cCould not find specified version: &f" + params.get(1), | ||||||
|             "&aVersions: &f" + expansion.getAvailableVersions()); |             "&aVersions: &f" + expansion.getAvailableVersions()); | ||||||
| @@ -110,23 +103,23 @@ public final class CommandECloudExpansionInfo extends PlaceholderCommand | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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() > 2) |       @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) { | ||||||
| 		{ |     if (params.size() > 2) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		if (params.size() <= 1) |     if (params.size() <= 1) { | ||||||
| 		{ |       final Stream<String> names = plugin.getCloudExpansionManager().getCloudExpansions().values() | ||||||
| 			final Stream<String> names = plugin.getCloudExpansionManager().getCloudExpansions().values().stream().map(CloudExpansion::getName).map(name -> name.replace(' ', '_')); |           .stream().map(CloudExpansion::getName).map(name -> name.replace(' ', '_')); | ||||||
|       suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); |       suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		final Optional<CloudExpansion> expansion = plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)); |     final Optional<CloudExpansion> expansion = plugin.getCloudExpansionManager() | ||||||
| 		if (!expansion.isPresent()) |         .findCloudExpansionByName(params.get(0)); | ||||||
| 		{ |     if (!expansion.isPresent()) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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,28 +52,14 @@ 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 |   @NotNull | ||||||
|   private static final Function<CloudExpansion, Object> EXPANSION_NAME = |   private static final Function<CloudExpansion, Object> EXPANSION_NAME = | ||||||
| 			expansion -> (expansion.shouldUpdate() ? "&6" : expansion.hasExpansion() ? "&a" : "&7") + 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(); | ||||||
| @@ -72,43 +71,198 @@ public final class CommandECloudExpansionList extends PlaceholderCommand | |||||||
|       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().findExpansionByName(expansion.getName()).map(PlaceholderExpansion::getVersion).orElse("Unknown"); |       expansion -> "&f" + PlaceholderAPIPlugin.getInstance().getLocalExpansionManager() | ||||||
|  |           .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"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
|  |   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 | ||||||
|  |   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); | ||||||
|  |  | ||||||
|  |     if (expansions.size() < head) { | ||||||
|  |       return Collections.emptyList(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return expansions.subList(head, tail); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   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 (page == -1) { | ||||||
|  |       builder.append('\n'); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     builder.append(" &bPage&7: &a") | ||||||
|  |         .append(page) | ||||||
|  |         .append("&r") | ||||||
|  |         .append('\n'); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
|  |   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 StringBuilder tooltip = new StringBuilder(); | ||||||
|  |     final JSONMessage message = JSONMessage.create(); | ||||||
|  |  | ||||||
|  |     for (int index = 0; index < expansions.size(); index++) { | ||||||
|  |       final CloudExpansion expansion = expansions.get(index); | ||||||
|  |  | ||||||
|  |       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())); | ||||||
|  |  | ||||||
|  |       final String description = expansion.getDescription(); | ||||||
|  |       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())); | ||||||
|  |  | ||||||
|  |       message.tooltip(Msg.color(tooltip.toString())); | ||||||
|  |       message.suggestCommand("/papi ecloud download " + expansion.getName()); | ||||||
|  |  | ||||||
|  |       if (index < expansions.size() - 1) { | ||||||
|  |         message.newline(); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       tooltip.setLength(0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (limit > 1) { | ||||||
|  |       message.newline(); | ||||||
|  |  | ||||||
|  |       message.then("◀") | ||||||
|  |           .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); | ||||||
|  |  | ||||||
|  |       message.then("▶") | ||||||
|  |           .color(page < limit ? ChatColor.GRAY : ChatColor.DARK_GRAY); | ||||||
|  |       if (page < limit) { | ||||||
|  |         message.runCommand("/papi ecloud list " + target + " " + (page + 1)); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return message; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   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) { | ||||||
|  |     final Map<String, Function<CloudExpansion, Object>> functions = new LinkedHashMap<>(); | ||||||
|  |  | ||||||
|  |     final AtomicInteger counter = new AtomicInteger(startIndex); | ||||||
|  |     functions.put("&f", expansion -> "&8" + counter.getAndIncrement() + "."); | ||||||
|  |  | ||||||
|  |     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<>(); | ||||||
|  |  | ||||||
|  |     rows.add(0, new ArrayList<>(functions.keySet())); | ||||||
|  |  | ||||||
|  |     for (final CloudExpansion expansion : expansions) { | ||||||
|  |       rows.add(functions.values().stream().map(function -> function.apply(expansion)) | ||||||
|  |           .map(Objects::toString).collect(Collectors.toList())); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     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)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @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 specify an option. [all, {author}, installed]"); |           "&cYou must specify an option. [all, {author}, installed]"); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     final boolean installed = params.get(0).equalsIgnoreCase("installed"); |     final boolean installed = params.get(0).equalsIgnoreCase("installed"); | ||||||
| 		final List<CloudExpansion> expansions = Lists.newArrayList(getExpansions(params.get(0), plugin)); |     final List<CloudExpansion> expansions = Lists | ||||||
|  |         .newArrayList(getExpansions(params.get(0), plugin)); | ||||||
|  |  | ||||||
| 		if (expansions.isEmpty()) |     if (expansions.isEmpty()) { | ||||||
| 		{ |  | ||||||
|       Msg.msg(sender, |       Msg.msg(sender, | ||||||
|           "&cNo expansions available to list."); |           "&cNo expansions available to list."); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		expansions.sort(plugin.getPlaceholderAPIConfig().getExpansionSort().orElse(ExpansionSort.LATEST)); |     expansions | ||||||
|  |         .sort(plugin.getPlaceholderAPIConfig().getExpansionSort().orElse(ExpansionSort.LATEST)); | ||||||
|  |  | ||||||
| 		if (!(sender instanceof Player) && params.size() < 2) |     if (!(sender instanceof Player) && params.size() < 2) { | ||||||
| 		{ |  | ||||||
|       final StringBuilder builder = new StringBuilder(); |       final StringBuilder builder = new StringBuilder(); | ||||||
|  |  | ||||||
|       addExpansionTitle(builder, params.get(0), -1); |       addExpansionTitle(builder, params.get(0), -1); | ||||||
| @@ -124,16 +278,12 @@ public final class CommandECloudExpansionList extends PlaceholderCommand | |||||||
|  |  | ||||||
|     final int page; |     final int page; | ||||||
|  |  | ||||||
| 		if (params.size() < 2) |     if (params.size() < 2) { | ||||||
| 		{ |  | ||||||
|       page = 1; |       page = 1; | ||||||
| 		} |     } else { | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
|       //noinspection UnstableApiUsage |       //noinspection UnstableApiUsage | ||||||
|       final Integer parsed = Ints.tryParse(params.get(1)); |       final Integer parsed = Ints.tryParse(params.get(1)); | ||||||
| 			if (parsed == null) |       if (parsed == null) { | ||||||
| 			{ |  | ||||||
|         Msg.msg(sender, |         Msg.msg(sender, | ||||||
|             "&cPage number must be an integer."); |             "&cPage number must be an integer."); | ||||||
|         return; |         return; | ||||||
| @@ -141,8 +291,7 @@ public final class CommandECloudExpansionList extends PlaceholderCommand | |||||||
|  |  | ||||||
|       final int limit = (int) Math.ceil((double) expansions.size() / PAGE_SIZE); |       final int limit = (int) Math.ceil((double) expansions.size() / PAGE_SIZE); | ||||||
|  |  | ||||||
| 			if (parsed < 1 || parsed > limit) |       if (parsed < 1 || parsed > limit) { | ||||||
| 			{ |  | ||||||
|         Msg.msg(sender, |         Msg.msg(sender, | ||||||
|             "&cPage number must be in the range &8[&a1&7..&a" + limit + "&8]"); |             "&cPage number must be in the range &8[&a1&7..&a" + limit + "&8]"); | ||||||
|         return; |         return; | ||||||
| @@ -156,8 +305,7 @@ public final class CommandECloudExpansionList extends PlaceholderCommand | |||||||
|  |  | ||||||
|     addExpansionTitle(builder, params.get(0), page); |     addExpansionTitle(builder, params.get(0), page); | ||||||
|  |  | ||||||
| 		if (!(sender instanceof Player)) |     if (!(sender instanceof Player)) { | ||||||
| 		{ |  | ||||||
|       addExpansionTable(values, |       addExpansionTable(values, | ||||||
|           builder, |           builder, | ||||||
|           ((page - 1) * PAGE_SIZE) + 1, |           ((page - 1) * PAGE_SIZE) + 1, | ||||||
| @@ -178,183 +326,23 @@ public final class CommandECloudExpansionList extends PlaceholderCommand | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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() > 2) |       @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) { | ||||||
| 		{ |     if (params.size() > 2) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		if (params.size() <= 1) |     if (params.size() <= 1) { | ||||||
| 		{ |       suggestByParameter( | ||||||
| 			suggestByParameter(Sets.union(OPTIONS, plugin.getCloudExpansionManager().getCloudExpansionAuthors()).stream(), suggestions, params.isEmpty() ? null : params.get(0)); |           Sets.union(OPTIONS, plugin.getCloudExpansionManager().getCloudExpansionAuthors()) | ||||||
|  |               .stream(), suggestions, params.isEmpty() ? null : params.get(0)); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		suggestByParameter(IntStream.rangeClosed(1, (int) Math.ceil((double) getExpansions(params.get(0), plugin).size() / PAGE_SIZE)).mapToObj(Objects::toString), suggestions, params.get(1)); |     suggestByParameter(IntStream.rangeClosed(1, | ||||||
| 	} |         (int) Math.ceil((double) getExpansions(params.get(0), plugin).size() / PAGE_SIZE)) | ||||||
|  |         .mapToObj(Objects::toString), suggestions, params.get(1)); | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	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 |  | ||||||
| 	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); |  | ||||||
|  |  | ||||||
| 		if (expansions.size() < head) |  | ||||||
| 		{ |  | ||||||
| 			return Collections.emptyList(); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return expansions.subList(head, tail); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	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 (page == -1) |  | ||||||
| 		{ |  | ||||||
| 			builder.append('\n'); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		builder.append(" &bPage&7: &a") |  | ||||||
| 			   .append(page) |  | ||||||
| 			   .append("&r") |  | ||||||
| 			   .append('\n'); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	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 StringBuilder tooltip = new StringBuilder(); |  | ||||||
| 		final JSONMessage   message = JSONMessage.create(); |  | ||||||
|  |  | ||||||
| 		for (int index = 0; index < expansions.size(); index++) |  | ||||||
| 		{ |  | ||||||
| 			final CloudExpansion expansion = expansions.get(index); |  | ||||||
|  |  | ||||||
| 			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())); |  | ||||||
|  |  | ||||||
| 			final String description = expansion.getDescription(); |  | ||||||
| 			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())); |  | ||||||
|  |  | ||||||
| 			message.tooltip(Msg.color(tooltip.toString())); |  | ||||||
| 			message.suggestCommand("/papi ecloud download " + expansion.getName()); |  | ||||||
|  |  | ||||||
| 			if (index < expansions.size() - 1) |  | ||||||
| 			{ |  | ||||||
| 				message.newline(); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			tooltip.setLength(0); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (limit > 1) |  | ||||||
| 		{ |  | ||||||
| 			message.newline(); |  | ||||||
|  |  | ||||||
| 			message.then("◀") |  | ||||||
| 				   .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); |  | ||||||
|  |  | ||||||
| 			message.then("▶") |  | ||||||
| 				   .color(page < limit ? ChatColor.GRAY : ChatColor.DARK_GRAY); |  | ||||||
| 			if (page < limit) |  | ||||||
| 			{ |  | ||||||
| 				message.runCommand("/papi ecloud list " + target + " " + (page + 1)); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return message; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	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) |  | ||||||
| 	{ |  | ||||||
| 		final Map<String, Function<CloudExpansion, Object>> functions = new LinkedHashMap<>(); |  | ||||||
|  |  | ||||||
| 		final AtomicInteger counter = new AtomicInteger(startIndex); |  | ||||||
| 		functions.put("&f", expansion -> "&8" + counter.getAndIncrement() + "."); |  | ||||||
|  |  | ||||||
| 		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<>(); |  | ||||||
|  |  | ||||||
| 		rows.add(0, new ArrayList<>(functions.keySet())); |  | ||||||
|  |  | ||||||
| 		for (final CloudExpansion expansion : expansions) |  | ||||||
| 		{ |  | ||||||
| 			rows.add(functions.values().stream().map(function -> function.apply(expansion)).map(Objects::toString).collect(Collectors.toList())); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		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,57 +32,52 @@ 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() { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	public CommandECloudExpansionPlaceholders() |  | ||||||
| 	{ |  | ||||||
|     super("placeholders"); |     super("placeholders"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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 specify the name of the expansion."); |           "&cYou must specify the name of the expansion."); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		final CloudExpansion expansion = plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)).orElse(null); |     final CloudExpansion expansion = plugin.getCloudExpansionManager() | ||||||
| 		if (expansion == null) |         .findCloudExpansionByName(params.get(0)).orElse(null); | ||||||
| 		{ |     if (expansion == null) { | ||||||
|       Msg.msg(sender, |       Msg.msg(sender, | ||||||
|           "&cThere is no expansion with the name: &f" + params.get(0)); |           "&cThere is no expansion with the name: &f" + params.get(0)); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     final List<String> placeholders = expansion.getPlaceholders(); |     final List<String> placeholders = expansion.getPlaceholders(); | ||||||
| 		if (placeholders == null || placeholders.isEmpty()) |     if (placeholders == null || placeholders.isEmpty()) { | ||||||
| 		{ |  | ||||||
|       Msg.msg(sender, |       Msg.msg(sender, | ||||||
|           "&cThe expansion specified does not have placeholders listed."); |           "&cThe expansion specified does not have placeholders listed."); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		final List<List<String>> partitions = Lists.partition(placeholders.stream().sorted().collect(Collectors.toList()), 10); |     final List<List<String>> partitions = Lists | ||||||
|  |         .partition(placeholders.stream().sorted().collect(Collectors.toList()), 10); | ||||||
|  |  | ||||||
|     Msg.msg(sender, |     Msg.msg(sender, | ||||||
|         "&6" + placeholders.size() + "&7 placeholders: &a", |         "&6" + placeholders.size() + "&7 placeholders: &a", | ||||||
| 				partitions.stream().map(partition -> "  " + String.join(", ", partition)).collect(Collectors.joining("\n"))); |         partitions.stream().map(partition -> String.join(", ", partition)) | ||||||
|  |             .collect(Collectors.joining("\n"))); | ||||||
|  |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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() { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	public CommandECloudRefresh() |  | ||||||
| 	{ |  | ||||||
|     super("refresh"); |     super("refresh"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|     plugin.getCloudExpansionManager().clean(); |     plugin.getCloudExpansionManager().clean(); | ||||||
| 		plugin.getCloudExpansionManager().fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); |     plugin.getCloudExpansionManager() | ||||||
|  |         .fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); | ||||||
|  |  | ||||||
|     Msg.msg(sender, |     Msg.msg(sender, | ||||||
| 				"&aThe eCloud Manager has been refreshed!"); |         "&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,19 +29,16 @@ 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() { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	public CommandECloudStatus() |  | ||||||
| 	{ |  | ||||||
|     super("status"); |     super("status"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|     final CloudExpansionManager manager = plugin.getCloudExpansionManager(); |     final CloudExpansionManager manager = plugin.getCloudExpansionManager(); | ||||||
|  |  | ||||||
|     final int updateCount = manager.getCloudUpdateCount(); |     final int updateCount = manager.getCloudUpdateCount(); | ||||||
| @@ -49,12 +47,15 @@ public final class CommandECloudStatus extends PlaceholderCommand | |||||||
|  |  | ||||||
|     final StringBuilder builder = new StringBuilder(); |     final StringBuilder builder = new StringBuilder(); | ||||||
|  |  | ||||||
| 		builder.append("&bThere are &a").append(expansionCount).append("&b expansions available on the eCloud.").append('\n'); |     builder.append("&bThere are &a").append(expansionCount) | ||||||
| 		builder.append("&7A total of &f").append(authorCount).append("&7 authors have contributed to the eCloud.").append('\n'); |         .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'); | ||||||
|  |  | ||||||
| 		if (updateCount > 0) |     if (updateCount > 0) { | ||||||
| 		{ |       builder.append("&eYou have &f").append(updateCount) | ||||||
| 			builder.append("&eYou have &a").append(updateCount).append("&e expansions installed that have updates available."); |           .append(updateCount > 1 ? "&e expansions" : "&e expansion").append("installed that ") | ||||||
|  |           .append(updateCount > 1 ? "have an" : "has an").append(" update available."); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     Msg.msg(sender, builder.toString()); |     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,24 +28,20 @@ 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() { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	public CommandECloudToggle() |  | ||||||
| 	{ |  | ||||||
|     super("toggle", "enable", "disable"); |     super("toggle", "enable", "disable"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|     final boolean desiredState; |     final boolean desiredState; | ||||||
|     final boolean currentState = plugin.getPlaceholderAPIConfig().isCloudEnabled(); |     final boolean currentState = plugin.getPlaceholderAPIConfig().isCloudEnabled(); | ||||||
|  |  | ||||||
| 		switch (alias.toLowerCase()) |     switch (alias.toLowerCase()) { | ||||||
| 		{ |  | ||||||
|       case "enable": |       case "enable": | ||||||
|         desiredState = true; |         desiredState = true; | ||||||
|         break; |         break; | ||||||
| @@ -56,20 +53,16 @@ public final class CommandECloudToggle extends PlaceholderCommand | |||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		if (desiredState == currentState) |     if (desiredState == currentState) { | ||||||
| 		{ |  | ||||||
|       Msg.msg(sender, "&7The eCloud Manager is already " + (desiredState ? "enabled" : "disabled")); |       Msg.msg(sender, "&7The eCloud Manager is already " + (desiredState ? "enabled" : "disabled")); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     plugin.getPlaceholderAPIConfig().setCloudEnabled(desiredState); |     plugin.getPlaceholderAPIConfig().setCloudEnabled(desiredState); | ||||||
|  |  | ||||||
| 		if (desiredState) |     if (desiredState) { | ||||||
| 		{ |  | ||||||
|       plugin.getCloudExpansionManager().load(); |       plugin.getCloudExpansionManager().load(); | ||||||
| 		} |     } else { | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
|       plugin.getCloudExpansionManager().kill(); |       plugin.getCloudExpansionManager().kill(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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,30 +38,29 @@ 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; | ||||||
| @@ -65,32 +70,29 @@ public final class CommandECloudUpdate extends PlaceholderCommand | |||||||
|     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 { | ||||||
| 		else |       plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)) | ||||||
| 		{ |           .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." : "your active expansions.")); |           "&cNo updates available for " + (!multiple ? "this expansion." | ||||||
|  |               : "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) -> { |     Futures.onMainThread(plugin, downloadAndDiscover(expansions, plugin), (classes, exception) -> { | ||||||
| 			if (exception != null) |       if (exception != null) { | ||||||
| 			{ |  | ||||||
|         Msg.msg(sender, |         Msg.msg(sender, | ||||||
|             "&cFailed to update expansions: &e" + exception.getMessage()); |             "&cFailed to update expansions: &e" + exception.getMessage()); | ||||||
|         return; |         return; | ||||||
| @@ -99,7 +101,6 @@ public final class CommandECloudUpdate extends PlaceholderCommand | |||||||
|       Msg.msg(sender, |       Msg.msg(sender, | ||||||
|           "&aSuccessfully downloaded updates, registering new versions."); |           "&aSuccessfully downloaded updates, registering new versions."); | ||||||
|  |  | ||||||
|  |  | ||||||
|       final String message = classes.stream() |       final String message = classes.stream() | ||||||
|           .filter(Objects::nonNull) |           .filter(Objects::nonNull) | ||||||
|           .map(plugin.getLocalExpansionManager()::register) |           .map(plugin.getLocalExpansionManager()::register) | ||||||
| @@ -115,31 +116,25 @@ public final class CommandECloudUpdate extends PlaceholderCommand | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		final List<CloudExpansion> installed = Lists.newArrayList(plugin.getCloudExpansionManager().getCloudExpansionsInstalled().values()); |     final List<CloudExpansion> installed = Lists | ||||||
|  |         .newArrayList(plugin.getCloudExpansionManager().getCloudExpansionsInstalled().values()); | ||||||
|     installed.removeIf(expansion -> !expansion.shouldUpdate()); |     installed.removeIf(expansion -> !expansion.shouldUpdate()); | ||||||
|  |  | ||||||
| 		if (!installed.isEmpty() && (params.isEmpty() || "all".startsWith(params.get(0).toLowerCase()))) |     if (!installed.isEmpty() && (params.isEmpty() || "all" | ||||||
| 		{ |         .startsWith(params.get(0).toLowerCase()))) { | ||||||
|       suggestions.add("all"); |       suggestions.add("all"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		suggestByParameter(installed.stream().map(CloudExpansion::getName).map(name -> name.replace(" ", "_")), suggestions, params.isEmpty() ? null : params.get(0)); |     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,37 +33,45 @@ 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 | ||||||
|  |       .ofLocalizedDateTime(FormatStyle.LONG) | ||||||
|       .withLocale(Locale.US) |       .withLocale(Locale.US) | ||||||
|       .withZone(ZoneId.of("UTC")); |       .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, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|     postDump(makeDump(plugin)).whenComplete((key, exception) -> { |     postDump(makeDump(plugin)).whenComplete((key, exception) -> { | ||||||
| 			if (exception != null) |       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, | ||||||
| @@ -86,40 +85,35 @@ public final class CommandDump extends PlaceholderCommand | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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") | ||||||
| 				final HttpURLConnection connection = ((HttpURLConnection) new URL(URL + "documents").openConnection()); |             .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.toString(new InputStreamReader(stream, StandardCharsets.UTF_8)); |           final String json = CharStreams | ||||||
|  |               .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: ") | ||||||
| @@ -133,29 +127,33 @@ public final class CommandDump extends PlaceholderCommand | |||||||
|     builder.append("Expansions Registered:") |     builder.append("Expansions Registered:") | ||||||
|         .append('\n'); |         .append('\n'); | ||||||
|  |  | ||||||
|  |     final List<PlaceholderExpansion> expansions = plugin.getLocalExpansionManager() | ||||||
| 		final Map<String, List<PlaceholderExpansion>> expansions = plugin.getLocalExpansionManager() |  | ||||||
|         .getExpansions() |         .getExpansions() | ||||||
|         .stream() |         .stream() | ||||||
| 																		 .collect(Collectors.groupingBy(PlaceholderExpansion::getAuthor)); |         .sorted(Comparator.comparing(PlaceholderExpansion::getIdentifier)) | ||||||
|  |         .sorted(Comparator.comparing(PlaceholderExpansion::getAuthor)) | ||||||
|  |         .collect(Collectors.toList()); | ||||||
|  |  | ||||||
| 		for (final Map.Entry<String, List<PlaceholderExpansion>> expansionsByAuthor : expansions.entrySet()) |     int size = 0; | ||||||
| 		{ |  | ||||||
| 			builder.append("  ") |  | ||||||
| 				   .append(expansionsByAuthor.getKey()) |  | ||||||
| 				   .append(": ") |  | ||||||
| 				   .append('\n'); |  | ||||||
|  |  | ||||||
| 			for (final PlaceholderExpansion expansion : expansionsByAuthor.getValue()) |     for (final String name : expansions.stream().map(PlaceholderExpansion::getIdentifier) | ||||||
| 			{ |         .collect(Collectors.toList())) { | ||||||
| 				builder.append("    ") |       if (name.length() > size) { | ||||||
| 					   .append(expansion.getName()) |         size = name.length(); | ||||||
| 					   .append(':') |  | ||||||
| 					   .append(expansion.getVersion()) |  | ||||||
| 					   .append('\n'); |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     for (final PlaceholderExpansion expansion : expansions) { | ||||||
|  |       builder.append("  ") | ||||||
|  |           .append(String.format("%-" + size + "s", expansion.getIdentifier())) | ||||||
|  |           .append(" [Author: ") | ||||||
|  |           .append(expansion.getAuthor()) | ||||||
|  |           .append(", Version: ") | ||||||
|  |           .append(expansion.getVersion()) | ||||||
|  |           .append("]\n"); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|     builder.append('\n'); |     builder.append('\n'); | ||||||
|  |  | ||||||
|     builder.append("Expansions Directory:") |     builder.append("Expansions Directory:") | ||||||
| @@ -165,8 +163,7 @@ public final class CommandDump extends PlaceholderCommand | |||||||
|         .getExpansionsFolder() |         .getExpansionsFolder() | ||||||
|         .list((dir, name) -> name.toLowerCase().endsWith(".jar")); |         .list((dir, name) -> name.toLowerCase().endsWith(".jar")); | ||||||
|  |  | ||||||
| 		for (final String jar : jars) |     for (final String jar : jars) { | ||||||
| 		{ |  | ||||||
|       builder.append("  ") |       builder.append("  ") | ||||||
|           .append(jar) |           .append(jar) | ||||||
|           .append('\n'); |           .append('\n'); | ||||||
| @@ -174,7 +171,6 @@ public final class CommandDump extends PlaceholderCommand | |||||||
|  |  | ||||||
|     builder.append('\n'); |     builder.append('\n'); | ||||||
|  |  | ||||||
|  |  | ||||||
|     builder.append("Server Info: ") |     builder.append("Server Info: ") | ||||||
|         .append(plugin.getServer().getBukkitVersion()) |         .append(plugin.getServer().getBukkitVersion()) | ||||||
|         .append('/') |         .append('/') | ||||||
| @@ -184,16 +180,26 @@ public final class CommandDump extends PlaceholderCommand | |||||||
|     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)) | ||||||
|  |         .collect(Collectors.toList()); | ||||||
|  |  | ||||||
|  |     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("  ") |       builder.append("  ") | ||||||
| 				   .append(other.getName()) |           .append(String.format("%-" + size + "s", other.getName())) | ||||||
| 				   .append(": ") |           .append(" [Version: ") | ||||||
|           .append(other.getDescription().getVersion()) |           .append(other.getDescription().getVersion()) | ||||||
| 				   .append('\n'); |           .append("]") | ||||||
|  |           .append("\n"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return builder.toString(); |     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,62 +35,49 @@ 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() { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	public CommandExpansionRegister() |  | ||||||
| 	{ |  | ||||||
|     super("register"); |     super("register"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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.size() < 1) |       @NotNull @Unmodifiable final List<String> params) { | ||||||
| 		{ |     if (params.size() < 1) { | ||||||
|       Msg.msg(sender, |       Msg.msg(sender, | ||||||
|           "&cYou must specify the name of an expansion file."); |           "&cYou must specify the name of an expansion file."); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     final LocalExpansionManager manager = plugin.getLocalExpansionManager(); |     final LocalExpansionManager manager = plugin.getLocalExpansionManager(); | ||||||
|  |  | ||||||
|     final File file = new File(manager.getExpansionsFolder(), params.get(0)); |     final File file = new File(manager.getExpansionsFolder(), params.get(0)); | ||||||
| 		if (!file.exists()) |     if (!file.exists()) { | ||||||
| 		{ |  | ||||||
|       Msg.msg(sender, |       Msg.msg(sender, | ||||||
|           "&cThe file &f" + file.getName() + "&c doesn't exist!"); |           "&cThe file &f" + file.getName() + "&c doesn't exist!"); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     Futures.onMainThread(plugin, manager.findExpansionInFile(file), (clazz, exception) -> { |     Futures.onMainThread(plugin, manager.findExpansionInFile(file), (clazz, exception) -> { | ||||||
| 			if (exception != null) |       if (exception != null) { | ||||||
| 			{ |  | ||||||
|         Msg.msg(sender, |         Msg.msg(sender, | ||||||
|             "&cFailed to find expansion in file: &f" + file); |             "&cFailed to find expansion in file: &f" + file); | ||||||
|  |  | ||||||
| 				plugin.getLogger().log(Level.WARNING, "failed to find expansion in file: " + file, exception); |         plugin.getLogger() | ||||||
|  |             .log(Level.WARNING, "failed to find expansion in file: " + file, exception); | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| 			if (clazz == null) |       if (clazz == null) { | ||||||
| 			{ |  | ||||||
|         Msg.msg(sender, |         Msg.msg(sender, | ||||||
|             "&cNo expansion class found in file: &f" + file); |             "&cNo expansion class found in file: &f" + file); | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |  | ||||||
|       final Optional<PlaceholderExpansion> expansion = manager.register(clazz); |       final Optional<PlaceholderExpansion> expansion = manager.register(clazz); | ||||||
| 			if (!expansion.isPresent()) |       if (!expansion.isPresent()) { | ||||||
| 			{ |  | ||||||
|         Msg.msg(sender, |         Msg.msg(sender, | ||||||
|             "&cFailed to register expansion from &f" + params.get(0)); |             "&cFailed to register expansion from &f" + params.get(0)); | ||||||
|         return; |         return; | ||||||
| @@ -98,20 +90,21 @@ public final class CommandExpansionRegister extends PlaceholderCommand | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		final String[] fileNames = plugin.getLocalExpansionManager().getExpansionsFolder().list((dir, name) -> name.endsWith(".jar")); |     final String[] fileNames = plugin.getLocalExpansionManager().getExpansionsFolder() | ||||||
| 		if (fileNames == null || fileNames.length == 0) |         .list((dir, name) -> name.endsWith(".jar")); | ||||||
| 		{ |     if (fileNames == null || fileNames.length == 0) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		suggestByParameter(Arrays.stream(fileNames), suggestions, params.isEmpty() ? null : params.get(0)); |     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,36 +31,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 CommandExpansionUnregister extends PlaceholderCommand { | ||||||
| import java.util.Optional; |  | ||||||
|  |  | ||||||
| public final class CommandExpansionUnregister extends PlaceholderCommand |   public CommandExpansionUnregister() { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	public CommandExpansionUnregister() |  | ||||||
| 	{ |  | ||||||
|     super("unregister"); |     super("unregister"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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 specify the name of the expansion."); |           "&cYou must specify the name of the expansion."); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		final Optional<PlaceholderExpansion> expansion = plugin.getLocalExpansionManager().findExpansionByName(params.get(0)); |     final Optional<PlaceholderExpansion> expansion = plugin.getLocalExpansionManager() | ||||||
| 		if (!expansion.isPresent()) |         .findExpansionByName(params.get(0)); | ||||||
| 		{ |     if (!expansion.isPresent()) { | ||||||
|       Msg.msg(sender, |       Msg.msg(sender, | ||||||
|           "&cThere is no expansion loaded with the identifier: &f" + params.get(0)); |           "&cThere is no expansion loaded with the identifier: &f" + params.get(0)); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     final String message = !expansion.get().unregister() ? |     final String message = !expansion.get().unregister() ? | ||||||
|         "&cFailed to unregister expansion: &f" : |         "&cFailed to unregister expansion: &f" : | ||||||
|         "&aSuccessfully unregistered expansion: &f"; |         "&aSuccessfully unregistered expansion: &f"; | ||||||
| @@ -67,14 +63,15 @@ public final class CommandExpansionUnregister extends PlaceholderCommand | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		suggestByParameter(PlaceholderAPI.getRegisteredIdentifiers().stream(), suggestions, params.isEmpty() ? null : params.get(0)); |     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() { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	public CommandHelp() |  | ||||||
| 	{ |  | ||||||
|     super("help"); |     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, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|     final PluginDescriptionFile description = plugin.getDescription(); |     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", |  | ||||||
| 				"  &7&oView plugin info/version", |  | ||||||
| 				"&b/papi &freload", |  | ||||||
| 				"  &7&oReload the config of PAPI", |  | ||||||
| 				"&b/papi &flist", |  | ||||||
| 				"  &7&oList active expansions", |  | ||||||
| 				"&b/papi &finfo &9<placeholder name>", |  | ||||||
| 				"  &7&oView information for a specific expansion", |  | ||||||
| 				"&b/papi &fparse &9<me/player name> <message>", |  | ||||||
| 				"  &7&oParse a message with placeholders", |  | ||||||
|         "&b/papi &fbcparse &9<me/player name> <message>", |         "&b/papi &fbcparse &9<me/player name> <message>", | ||||||
|         "  &7&oParse a message with placeholders and broadcast it", |         "  &7&oParse a message with placeholders and broadcast it", | ||||||
| 				"&b/papi &fparserel &9<player one> <player two> <message>", |  | ||||||
| 				"  &7&oParse a message with relational placeholders", |  | ||||||
|         "&b/papi &fcmdparse &9<me/player> <command with placeholders>", |         "&b/papi &fcmdparse &9<me/player> <command with placeholders>", | ||||||
|         "  &7&oParse a message with relational placeholders", |         "  &7&oParse a message with relational placeholders", | ||||||
|  |         "&b/papi &fdump", | ||||||
|  |         "  &7&oDump all relevant information needed to help debug issues into a paste link.", | ||||||
|  |         "&b/papi &finfo &9<placeholder name>", | ||||||
|  |         "  &7&oView information for a specific expansion", | ||||||
|  |         "&b/papi &flist", | ||||||
|  |         "  &7&oList active expansions", | ||||||
|  |         "&b/papi &fparse &9<me/player name> <message>", | ||||||
|  |         "  &7&oParse a message with placeholders", | ||||||
|  |         "&b/papi &fparserel &9<player one> <player two> <message>", | ||||||
|  |         "  &7&oParse a message with relational placeholders", | ||||||
|         "&b/papi &fregister &9<file name>", |         "&b/papi &fregister &9<file name>", | ||||||
|         "  &7&oRegister an expansion by the name of the file", |         "  &7&oRegister an expansion by the name of the file", | ||||||
|  |         "&b/papi &freload", | ||||||
|  |         "  &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,29 +30,25 @@ 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() { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	public CommandInfo() |  | ||||||
| 	{ |  | ||||||
|     super("info"); |     super("info"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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 specify the name of the expansion."); |           "&cYou must specify the name of the expansion."); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		final PlaceholderExpansion expansion = plugin.getLocalExpansionManager().findExpansionByName(params.get(0)).orElse(null); |     final PlaceholderExpansion expansion = plugin.getLocalExpansionManager() | ||||||
| 		if (expansion == null) |         .findExpansionByName(params.get(0)).orElse(null); | ||||||
| 		{ |     if (expansion == null) { | ||||||
|       Msg.msg(sender, |       Msg.msg(sender, | ||||||
|           "&cThere is no expansion loaded with the identifier: &f" + params.get(0)); |           "&cThere is no expansion loaded with the identifier: &f" + params.get(0)); | ||||||
|       return; |       return; | ||||||
| @@ -67,37 +64,32 @@ public final class CommandInfo extends PlaceholderCommand | |||||||
|         .append('\n'); |         .append('\n'); | ||||||
|  |  | ||||||
|     final String author = expansion.getAuthor(); |     final String author = expansion.getAuthor(); | ||||||
| 		if (author != null) |     if (author != null) { | ||||||
| 		{ |  | ||||||
|       builder.append("&7Author: &r") |       builder.append("&7Author: &r") | ||||||
|           .append(author) |           .append(author) | ||||||
|           .append('\n'); |           .append('\n'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     final String version = expansion.getVersion(); |     final String version = expansion.getVersion(); | ||||||
| 		if (version != null) |     if (version != null) { | ||||||
| 		{ |  | ||||||
|       builder.append("&7Version: &r") |       builder.append("&7Version: &r") | ||||||
|           .append(version) |           .append(version) | ||||||
|           .append('\n'); |           .append('\n'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     final String requiredPlugin = expansion.getRequiredPlugin(); |     final String requiredPlugin = expansion.getRequiredPlugin(); | ||||||
| 		if (requiredPlugin != null) |     if (requiredPlugin != null) { | ||||||
| 		{ |  | ||||||
|       builder.append("&7Requires plugin: &r") |       builder.append("&7Requires plugin: &r") | ||||||
|           .append(requiredPlugin) |           .append(requiredPlugin) | ||||||
|           .append('\n'); |           .append('\n'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     final List<String> placeholders = expansion.getPlaceholders(); |     final List<String> placeholders = expansion.getPlaceholders(); | ||||||
| 		if (placeholders != null && !placeholders.isEmpty()) |     if (placeholders != null && !placeholders.isEmpty()) { | ||||||
| 		{ |  | ||||||
|       builder.append("&8&m-- &7Placeholders &8&m--&r") |       builder.append("&8&m-- &7Placeholders &8&m--&r") | ||||||
|           .append('\n'); |           .append('\n'); | ||||||
|  |  | ||||||
| 			for (final String placeholder : placeholders) |       for (final String placeholder : placeholders) { | ||||||
| 			{ |  | ||||||
|         builder.append(placeholder) |         builder.append(placeholder) | ||||||
|             .append('\n'); |             .append('\n'); | ||||||
|       } |       } | ||||||
| @@ -107,14 +99,15 @@ public final class CommandInfo extends PlaceholderCommand | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		suggestByParameter(PlaceholderAPI.getRegisteredIdentifiers().stream(), suggestions, params.isEmpty() ? null : params.get(0)); |     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() { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	public CommandList() |  | ||||||
| 	{ |  | ||||||
|     super("list"); |     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, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|     final Set<String> identifiers = PlaceholderAPI.getRegisteredIdentifiers(); |     final Set<String> identifiers = PlaceholderAPI.getRegisteredIdentifiers(); | ||||||
| 		if (identifiers.isEmpty()) |     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,27 +38,18 @@ 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() { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	public CommandParse() |  | ||||||
| 	{ |  | ||||||
|     super("parse", "bcparse", "parserel", "cmdparse"); |     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; | ||||||
| @@ -71,10 +66,10 @@ public final class CommandParse extends PlaceholderCommand | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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; | ||||||
| @@ -87,31 +82,28 @@ public final class CommandParse extends PlaceholderCommand | |||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
| 	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, | ||||||
|  |           "&cYou must supply a target, and a message: &b/papi " + (broadcast ? "bcparse" : "parse") | ||||||
|  |               + " &7{target} &a{message}"); | ||||||
|       return; |       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!"); |         Msg.msg(sender, "&cYou must be a player to use &7me&c as a target!"); | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       player = ((Player) sender); |       player = ((Player) sender); | ||||||
| 		} |     } else { | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
|       final OfflinePlayer target = resolvePlayer(params.get(0)); |       final OfflinePlayer target = resolvePlayer(params.get(0)); | ||||||
| 			if (target == null) |       if (target == null) { | ||||||
| 			{ |  | ||||||
|         Msg.msg(sender, "&cFailed to find player: &7" + params.get(0)); |         Msg.msg(sender, "&cFailed to find player: &7" + params.get(0)); | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
| @@ -119,64 +111,57 @@ public final class CommandParse extends PlaceholderCommand | |||||||
|       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 { | ||||||
| 		else |       if (!(sender instanceof Player)) { | ||||||
| 		{ |  | ||||||
| 			if (!(sender instanceof Player)) |  | ||||||
| 			{ |  | ||||||
|         Msg.msg(sender, message); |         Msg.msg(sender, message); | ||||||
| 			} |       } else { | ||||||
| 			else |  | ||||||
| 			{ |  | ||||||
|         ((Player) sender).spigot().sendMessage(TextComponent.fromLegacyText(message)); |         ((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 | ||||||
|  |         .setRelationalPlaceholders(((Player) targetOne), ((Player) targetTwo), | ||||||
|  |             String.join(" ", params.subList(2, params.size()))); | ||||||
|     Msg.msg(sender, message); |     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"); | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -187,20 +172,19 @@ public final class CommandParse extends PlaceholderCommand | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     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); | ||||||
|  |     if (expansion == null) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -214,10 +198,9 @@ public final class CommandParse extends PlaceholderCommand | |||||||
|     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; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -227,12 +210,10 @@ public final class CommandParse extends PlaceholderCommand | |||||||
|  |  | ||||||
|  |  | ||||||
|   @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. | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,25 +20,23 @@ | |||||||
|  |  | ||||||
| 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() { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	public CommandReload() |  | ||||||
| 	{ |  | ||||||
|     super("reload"); |     super("reload"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @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, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|     plugin.reloadConf(sender); |     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,20 +29,17 @@ 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() { | ||||||
| { |  | ||||||
|  |  | ||||||
| 	public CommandVersion() |  | ||||||
| 	{ |  | ||||||
|     super("version"); |     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, | ||||||
|  |       @NotNull @Unmodifiable final List<String> params) { | ||||||
|     final PluginDescriptionFile description = plugin.getDescription(); |     final PluginDescriptionFile description = plugin.getDescription(); | ||||||
|  |  | ||||||
|     Msg.msg(sender, |     Msg.msg(sender, | ||||||
|   | |||||||
| @@ -20,13 +20,11 @@ | |||||||
|  |  | ||||||
| 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)), |   NAME(Comparator.comparing(CloudExpansion::getName)), | ||||||
|   AUTHOR(Comparator.comparing(CloudExpansion::getAuthor)), |   AUTHOR(Comparator.comparing(CloudExpansion::getAuthor)), | ||||||
| @@ -36,15 +34,13 @@ public enum ExpansionSort implements Comparator<CloudExpansion> | |||||||
|   @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,86 +20,72 @@ | |||||||
|  |  | ||||||
| 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 |   @NotNull | ||||||
|   private final PlaceholderAPIPlugin plugin; |   private final PlaceholderAPIPlugin plugin; | ||||||
|  |  | ||||||
| 	public PlaceholderAPIConfig(@NotNull final PlaceholderAPIPlugin plugin) |   public PlaceholderAPIConfig(@NotNull final PlaceholderAPIPlugin plugin) { | ||||||
| 	{ |  | ||||||
|     this.plugin = 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) { | ||||||
| 		catch (final IllegalArgumentException ignored) |  | ||||||
| 		{ |  | ||||||
|       return Optional.empty(); |       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,54 +26,41 @@ 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(); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	private       boolean              cancelled; |  | ||||||
|   @NotNull |   @NotNull | ||||||
|   private final PlaceholderExpansion expansion; |   private final PlaceholderExpansion expansion; | ||||||
|  |   private boolean cancelled; | ||||||
|  |  | ||||||
| 	public ExpansionRegisterEvent(@NotNull final PlaceholderExpansion expansion) |   public ExpansionRegisterEvent(@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; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
| 	public boolean isCancelled() |   public boolean isCancelled() { | ||||||
| 	{ |  | ||||||
|     return cancelled; |     return cancelled; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
| 	public void setCancelled(boolean cancelled) |   public void setCancelled(boolean cancelled) { | ||||||
| 	{ |  | ||||||
|     this.cancelled = cancelled; |     this.cancelled = cancelled; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
|   @Override |   @Override | ||||||
| 	public HandlerList getHandlers() |   public HandlerList getHandlers() { | ||||||
| 	{ |  | ||||||
| 		return HANDLERS; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public static HandlerList getHandlerList() |  | ||||||
| 	{ |  | ||||||
|     return HANDLERS; |     return HANDLERS; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,8 +25,7 @@ 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(); | ||||||
| @@ -35,30 +34,23 @@ public final class ExpansionUnregisterEvent extends Event | |||||||
|   @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; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public static HandlerList getHandlerList() |  | ||||||
| 	{ |  | ||||||
|     return HANDLERS; |     return HANDLERS; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -29,8 +29,7 @@ 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(); | ||||||
| @@ -41,36 +40,30 @@ public final class PlaceholderHookUnloadEvent extends Event | |||||||
|   @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; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
|  |   public String getHookName() { | ||||||
|     return plugin; |     return plugin; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public PlaceholderHook getHook() |   public PlaceholderHook getHook() { | ||||||
| 	{ |  | ||||||
|     return placeholderHook; |     return placeholderHook; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
|   @Override |   @Override | ||||||
| 	public HandlerList getHandlers() |   public HandlerList getHandlers() { | ||||||
| 	{ |  | ||||||
| 		return HANDLERS; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public static HandlerList getHandlerList() |  | ||||||
| 	{ |  | ||||||
|     return HANDLERS; |     return HANDLERS; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -21,6 +21,7 @@ | |||||||
| 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) { |   public NoDefaultCommandException(final String message) { | ||||||
|     super(message); |     super(message); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -20,22 +20,19 @@ | |||||||
|  |  | ||||||
| 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 |    * The placeholder identifier of this expansion | ||||||
| @@ -61,22 +58,13 @@ public abstract class PlaceholderExpansion extends PlaceholderHook | |||||||
|   @NotNull |   @NotNull | ||||||
|   public abstract String getVersion(); |   public abstract String getVersion(); | ||||||
|  |  | ||||||
| 	@Nullable |  | ||||||
| 	@Override /* override for now >:) */ |  | ||||||
| 	public String onRequest(@Nullable final OfflinePlayer player, @NotNull final String params) |  | ||||||
| 	{ |  | ||||||
| 		return super.onRequest(player, params); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * The name of this expansion |    * The name of this expansion | ||||||
|    * |    * | ||||||
|    * @return {@link #getIdentifier()} by default, name of this expansion if specified |    * @return {@link #getIdentifier()} by default, name of this expansion if specified | ||||||
|    */ |    */ | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public String getName() |   public String getName() { | ||||||
| 	{ |  | ||||||
|     return getIdentifier(); |     return getIdentifier(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -86,8 +74,7 @@ public abstract class PlaceholderExpansion extends PlaceholderHook | |||||||
|    * @return plugin name that this expansion requires to function |    * @return plugin name that this expansion requires to function | ||||||
|    */ |    */ | ||||||
|   @Nullable |   @Nullable | ||||||
| 	public String getRequiredPlugin() |   public String getRequiredPlugin() { | ||||||
| 	{ |  | ||||||
|     return getPlugin(); |     return getPlugin(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -97,8 +84,7 @@ public abstract class PlaceholderExpansion extends PlaceholderHook | |||||||
|    * @return placeholder list that this expansion provides |    * @return placeholder list that this expansion provides | ||||||
|    */ |    */ | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public List<String> getPlaceholders() |   public List<String> getPlaceholders() { | ||||||
| 	{ |  | ||||||
|     return Collections.emptyList(); |     return Collections.emptyList(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -110,8 +96,7 @@ public abstract class PlaceholderExpansion extends PlaceholderHook | |||||||
|    * |    * | ||||||
|    * @return if this expansion should persist through placeholder reloads |    * @return if this expansion should persist through placeholder reloads | ||||||
|    */ |    */ | ||||||
| 	public boolean persist() |   public boolean persist() { | ||||||
| 	{ |  | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -121,9 +106,9 @@ public abstract class PlaceholderExpansion extends PlaceholderHook | |||||||
|    * |    * | ||||||
|    * @return true if the identifier for this expansion is already registered |    * @return true if the identifier for this expansion is already registered | ||||||
|    */ |    */ | ||||||
| 	public final boolean isRegistered() |   public final boolean isRegistered() { | ||||||
| 	{ |     return getPlaceholderAPI().getLocalExpansionManager().findExpansionByIdentifier(getIdentifier()) | ||||||
| 		return getPlaceholderAPI().getLocalExpansionManager().findExpansionByIdentifier(getIdentifier()).map(it -> it.equals(this)).orElse(false); |         .map(it -> it.equals(this)).orElse(false); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -133,9 +118,9 @@ public abstract class PlaceholderExpansion extends PlaceholderHook | |||||||
|    * |    * | ||||||
|    * @return true if this hook meets all the requirements to register |    * @return true if this hook meets all the requirements to register | ||||||
|    */ |    */ | ||||||
| 	public boolean canRegister() |   public boolean canRegister() { | ||||||
| 	{ |     return getRequiredPlugin() == null | ||||||
| 		return getRequiredPlugin() == null || Bukkit.getPluginManager().getPlugin(getRequiredPlugin()) != null; |         || Bukkit.getPluginManager().getPlugin(getRequiredPlugin()) != null; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
| @@ -143,9 +128,8 @@ public abstract class PlaceholderExpansion extends PlaceholderHook | |||||||
|    * |    * | ||||||
|    * @return true if this expansion is now registered with PlaceholderAPI |    * @return true if this expansion is now registered with PlaceholderAPI | ||||||
|    */ |    */ | ||||||
| 	public boolean register() |   public boolean register() { | ||||||
| 	{ |     return getPlaceholderAPI().getLocalExpansionManager().register(this); | ||||||
| 		return canRegister() && getPlaceholderAPI().getLocalExpansionManager().register(this); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
| @@ -153,8 +137,7 @@ public abstract class PlaceholderExpansion extends PlaceholderHook | |||||||
|    * |    * | ||||||
|    * @return true if this expansion is now unregistered with PlaceholderAPI |    * @return true if this expansion is now unregistered with PlaceholderAPI | ||||||
|    */ |    */ | ||||||
| 	public final boolean unregister() |   public final boolean unregister() { | ||||||
| 	{ |  | ||||||
|     return getPlaceholderAPI().getLocalExpansionManager().unregister(this); |     return getPlaceholderAPI().getLocalExpansionManager().unregister(this); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -165,83 +148,69 @@ public abstract class PlaceholderExpansion extends PlaceholderHook | |||||||
|    * @return {@link PlaceholderAPIPlugin} instance |    * @return {@link PlaceholderAPIPlugin} instance | ||||||
|    */ |    */ | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public final PlaceholderAPIPlugin getPlaceholderAPI() |   public final PlaceholderAPIPlugin getPlaceholderAPI() { | ||||||
| 	{ |  | ||||||
|     return PlaceholderAPIPlugin.getInstance(); |     return PlaceholderAPIPlugin.getInstance(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   // === Configuration === |   // === Configuration === | ||||||
|  |  | ||||||
|   @Nullable |   @Nullable | ||||||
| 	public final ConfigurationSection getConfigSection() |   public final ConfigurationSection getConfigSection() { | ||||||
| 	{ |  | ||||||
|     return getPlaceholderAPI().getConfig().getConfigurationSection("expansions." + getIdentifier()); |     return getPlaceholderAPI().getConfig().getConfigurationSection("expansions." + getIdentifier()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Nullable |   @Nullable | ||||||
| 	public final ConfigurationSection getConfigSection(@NotNull final String path) |   public final ConfigurationSection getConfigSection(@NotNull final String path) { | ||||||
| 	{ |  | ||||||
|     final ConfigurationSection section = getConfigSection(); |     final ConfigurationSection section = getConfigSection(); | ||||||
|     return section == null ? null : section.getConfigurationSection(path); |     return section == null ? null : section.getConfigurationSection(path); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Nullable |   @Nullable | ||||||
|   @Contract("_, !null -> !null") |   @Contract("_, !null -> !null") | ||||||
| 	public final Object get(@NotNull final String path, final Object def) |   public final Object get(@NotNull final String path, final Object def) { | ||||||
| 	{ |  | ||||||
|     final ConfigurationSection section = getConfigSection(); |     final ConfigurationSection section = getConfigSection(); | ||||||
|     return section == null ? def : section.get(path, def); |     return section == null ? def : section.get(path, def); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 	public final int getInt(@NotNull final String path, final int def) |   public final int getInt(@NotNull final String path, final int def) { | ||||||
| 	{ |  | ||||||
|     final ConfigurationSection section = getConfigSection(); |     final ConfigurationSection section = getConfigSection(); | ||||||
|     return section == null ? def : section.getInt(path, def); |     return section == null ? def : section.getInt(path, def); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 	public final long getLong(@NotNull final String path, final long def) |   public final long getLong(@NotNull final String path, final long def) { | ||||||
| 	{ |  | ||||||
|     final ConfigurationSection section = getConfigSection(); |     final ConfigurationSection section = getConfigSection(); | ||||||
|     return section == null ? def : section.getLong(path, def); |     return section == null ? def : section.getLong(path, def); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 	public final double getDouble(@NotNull final String path, final double def) |   public final double getDouble(@NotNull final String path, final double def) { | ||||||
| 	{ |  | ||||||
|     final ConfigurationSection section = getConfigSection(); |     final ConfigurationSection section = getConfigSection(); | ||||||
|     return section == null ? def : section.getDouble(path, def); |     return section == null ? def : section.getDouble(path, def); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Nullable |   @Nullable | ||||||
|   @Contract("_, !null -> !null") |   @Contract("_, !null -> !null") | ||||||
| 	public final String getString(@NotNull final String path, @Nullable final String def) |   public final String getString(@NotNull final String path, @Nullable final String def) { | ||||||
| 	{ |  | ||||||
|     final ConfigurationSection section = getConfigSection(); |     final ConfigurationSection section = getConfigSection(); | ||||||
|     return section == null ? def : section.getString(path, def); |     return section == null ? def : section.getString(path, def); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public final List<String> getStringList(@NotNull final String path) |   public final List<String> getStringList(@NotNull final String path) { | ||||||
| 	{ |  | ||||||
|     final ConfigurationSection section = getConfigSection(); |     final ConfigurationSection section = getConfigSection(); | ||||||
|     return section == null ? Collections.emptyList() : section.getStringList(path); |     return section == null ? Collections.emptyList() : section.getStringList(path); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 	public final boolean configurationContains(@NotNull final String path) |   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 && section.contains(path); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
| 	public final boolean equals(final Object o) |   public final boolean equals(final Object o) { | ||||||
| 	{ |     if (this == o) { | ||||||
| 		if (this == o) |  | ||||||
| 		{ |  | ||||||
|       return true; |       return true; | ||||||
|     } |     } | ||||||
| 		if (!(o instanceof PlaceholderExpansion)) |     if (!(o instanceof PlaceholderExpansion)) { | ||||||
| 		{ |  | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -253,15 +222,9 @@ public abstract class PlaceholderExpansion extends PlaceholderHook | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
| 	public final int hashCode() |   public final String toString() { | ||||||
| 	{ |     return String.format("PlaceholderExpansion[name: '%s', author: '%s', version: '%s']", getName(), | ||||||
| 		return Objects.hash(getIdentifier(), getAuthor(), getVersion()); |         getAuthor(), getVersion()); | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Override |  | ||||||
| 	public final String toString() |  | ||||||
| 	{ |  | ||||||
| 		return String.format("PlaceholderExpansion[name: '%s', author: '%s', version: '%s']", getName(), getAuthor(), getVersion()); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // === Deprecated API === |   // === Deprecated API === | ||||||
| @@ -271,8 +234,7 @@ public abstract class PlaceholderExpansion extends PlaceholderHook | |||||||
|    */ |    */ | ||||||
|   @Deprecated |   @Deprecated | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
| 	public String getPlugin() |   public String getPlugin() { | ||||||
| 	{ |  | ||||||
|     return null; |     return null; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -281,8 +243,7 @@ public abstract class PlaceholderExpansion extends PlaceholderHook | |||||||
|    */ |    */ | ||||||
|   @Deprecated |   @Deprecated | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
| 	public String getDescription() |   public String getDescription() { | ||||||
| 	{ |  | ||||||
|     return null; |     return null; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -291,8 +252,7 @@ public abstract class PlaceholderExpansion extends PlaceholderHook | |||||||
|    */ |    */ | ||||||
|   @Deprecated |   @Deprecated | ||||||
|   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") |   @ApiStatus.ScheduledForRemoval(inVersion = "2.11.0") | ||||||
| 	public String getLink() |   public String getLink() { | ||||||
| 	{ |  | ||||||
|     return null; |     return null; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,11 +20,10 @@ | |||||||
|  |  | ||||||
| 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 { | ||||||
| @@ -173,6 +172,7 @@ public class CloudExpansion { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   public class Version { |   public class Version { | ||||||
|  |  | ||||||
|     private String url, version, release_notes; |     private String url, version, release_notes; | ||||||
|  |  | ||||||
|     public String getUrl() { |     public String getUrl() { | ||||||
|   | |||||||
| @@ -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,17 +33,29 @@ 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/"; | ||||||
| @@ -59,7 +66,8 @@ public final class CloudExpansionManager | |||||||
|   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 | ||||||
| @@ -70,38 +78,43 @@ public final class CloudExpansionManager | |||||||
|   @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) { | ||||||
|  |     return toIndexName(expansion.getName()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void load() { | ||||||
|     clean(); |     clean(); | ||||||
|     fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); |     fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 	public void kill() |   public void kill() { | ||||||
| 	{ |  | ||||||
|     clean(); |     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(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -113,10 +126,8 @@ public final class CloudExpansionManager | |||||||
|  |  | ||||||
|   @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(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -128,161 +139,142 @@ public final class CloudExpansionManager | |||||||
|  |  | ||||||
|   @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() { | ||||||
| 	public int getCloudExpansionAuthorCount() |  | ||||||
| 	{ |  | ||||||
|     return getCloudExpansionAuthors().size(); |     return getCloudExpansionAuthors().size(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 	public int getCloudUpdateCount() |   public int getCloudUpdateCount() { | ||||||
| 	{ |  | ||||||
|     return ((int) plugin.getLocalExpansionManager() |     return ((int) plugin.getLocalExpansionManager() | ||||||
|         .getExpansions() |         .getExpansions() | ||||||
|         .stream() |         .stream() | ||||||
| 							.filter(expansion -> findCloudExpansionByName(expansion.getName()).map(CloudExpansion::shouldUpdate).orElse(false)) |         .filter(expansion -> findCloudExpansionByName(expansion.getName()) | ||||||
|  |             .map(CloudExpansion::shouldUpdate).orElse(false)) | ||||||
|         .count()); |         .count()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public Optional<CloudExpansion> findCloudExpansionByName(@NotNull final String name) |   public Optional<CloudExpansion> findCloudExpansionByName(@NotNull final String name) { | ||||||
| 	{ |  | ||||||
|     return Optional.ofNullable(cache.get(toIndexName(name))); |     return Optional.ofNullable(cache.get(toIndexName(name))); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   public void clean() { | ||||||
| 	public void clean() |  | ||||||
| 	{ |  | ||||||
|     cache.clear(); |     cache.clear(); | ||||||
|  |  | ||||||
|     await.values().forEach(future -> future.cancel(true)); |     await.values().forEach(future -> future.cancel(true)); | ||||||
|     await.clear(); |     await.clear(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 	public void fetch(final boolean allowUnverified) |   public void fetch(final boolean allowUnverified) { | ||||||
| 	{ |  | ||||||
|     plugin.getLogger().info("Fetching available expansion information..."); |     plugin.getLogger().info("Fetching available expansion information..."); | ||||||
|  |  | ||||||
| 		CompletableFuture<Map<String, CloudExpansion>> future = CompletableFuture.supplyAsync(() -> { |     ASYNC_EXECUTOR.submit( | ||||||
| 			final Map<String, CloudExpansion> values = new HashMap<>(); |         () -> { | ||||||
|  |           // a defence tactic! use ConcurrentHashMap instead of normal HashMap | ||||||
| 			try |           Map<String, CloudExpansion> values = new ConcurrentHashMap<>(); | ||||||
| 			{ |           try { | ||||||
|             //noinspection UnstableApiUsage |             //noinspection UnstableApiUsage | ||||||
| 				final String json = Resources.toString(new URL(API_URL), StandardCharsets.UTF_8); |             String json = Resources.toString(new URL(API_URL), StandardCharsets.UTF_8); | ||||||
|             values.putAll(GSON.fromJson(json, TYPE)); |             values.putAll(GSON.fromJson(json, TYPE)); | ||||||
|  |  | ||||||
|  |             List<String> toRemove = new ArrayList<>(); | ||||||
|  |  | ||||||
|  |             for (Map.Entry<String, CloudExpansion> entry : values.entrySet()) { | ||||||
|  |               CloudExpansion expansion = entry.getValue(); | ||||||
|  |               if (expansion.getLatestVersion() == null | ||||||
|  |                   || expansion.getVersion(expansion.getLatestVersion()) == null) { | ||||||
|  |                 toRemove.add(entry.getKey()); | ||||||
|  |               } | ||||||
|  |               if (!allowUnverified && !expansion.isVerified()) { | ||||||
|  |                 toRemove.add(entry.getKey()); | ||||||
|               } |               } | ||||||
| 			catch (final IOException ex) |  | ||||||
| 			{ |  | ||||||
| 				throw new CompletionException(ex); |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
| 			values.values().removeIf(value -> value.getLatestVersion() == null || value.getVersion(value.getLatestVersion()) == null); |             for (String name : toRemove) { | ||||||
|  |               values.remove(name); | ||||||
| 			return values; |             } | ||||||
| 		}); |           } 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) |  | ||||||
| 		{ |  | ||||||
| 			future = future.thenApplyAsync((values) -> { |  | ||||||
| 				values.values().removeIf(expansion -> !expansion.isVerified()); |  | ||||||
| 				return values; |  | ||||||
| 			}); |  | ||||||
|           } |           } | ||||||
|  |  | ||||||
|  |           // loop thru what's left on the main thread | ||||||
|  |           plugin | ||||||
|  |               .getServer() | ||||||
|  |               .getScheduler() | ||||||
|  |               .runTask( | ||||||
|  |                   plugin, | ||||||
|  |                   () -> { | ||||||
|  |                     try { | ||||||
|  |                       for (Map.Entry<String, CloudExpansion> entry : values.entrySet()) { | ||||||
|  |                         String name = entry.getKey(); | ||||||
|  |                         CloudExpansion expansion = entry.getValue(); | ||||||
|  |  | ||||||
| 		future = future.thenApplyAsync((values) -> { |  | ||||||
|  |  | ||||||
| 			values.forEach((name, expansion) -> { |  | ||||||
|                         expansion.setName(name); |                         expansion.setName(name); | ||||||
|  |  | ||||||
| 				final Optional<PlaceholderExpansion> local = plugin.getLocalExpansionManager().findExpansionByName(name); |                         Optional<PlaceholderExpansion> localOpt = | ||||||
| 				if (local.isPresent() && local.get().isRegistered()) |                             plugin.getLocalExpansionManager().findExpansionByName(name); | ||||||
| 				{ |                         if (localOpt.isPresent()) { | ||||||
|  |                           PlaceholderExpansion local = localOpt.get(); | ||||||
|  |                           if (local.isRegistered()) { | ||||||
|                             expansion.setHasExpansion(true); |                             expansion.setHasExpansion(true); | ||||||
| 					expansion.setShouldUpdate(!local.get().getVersion().equals(expansion.getLatestVersion())); |                             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); | ||||||
|                     } |                     } | ||||||
|                   }); |                   }); | ||||||
|  |  | ||||||
| 			return values; |  | ||||||
| 		}); |  | ||||||
|  |  | ||||||
| 		future.whenComplete((expansions, exception) -> { |  | ||||||
|  |  | ||||||
| 			if (exception != null) |  | ||||||
| 			{ |  | ||||||
| 				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) { | ||||||
| 	public boolean isDownloading(@NotNull final CloudExpansion expansion) |  | ||||||
| 	{ |  | ||||||
|     return await.containsKey(toIndexName(expansion)); |     return await.containsKey(toIndexName(expansion)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public CompletableFuture<File> downloadExpansion(@NotNull final CloudExpansion expansion, @NotNull final CloudExpansion.Version version) |   public CompletableFuture<File> downloadExpansion(@NotNull final CloudExpansion expansion, | ||||||
| 	{ |       @NotNull final CloudExpansion.Version version) { | ||||||
|     final CompletableFuture<File> previous = await.get(toIndexName(expansion)); |     final CompletableFuture<File> previous = await.get(toIndexName(expansion)); | ||||||
| 		if (previous != null) |     if (previous != null) { | ||||||
| 		{ |  | ||||||
|       return previous; |       return previous; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		final File file = new File(plugin.getLocalExpansionManager().getExpansionsFolder(), "Expansion-" + toIndexName(expansion) + ".jar"); |     final File file = new File(plugin.getLocalExpansionManager().getExpansionsFolder(), | ||||||
|  |         "Expansion-" + toIndexName(expansion) + ".jar"); | ||||||
|  |  | ||||||
|     final CompletableFuture<File> download = CompletableFuture.supplyAsync(() -> { |     final CompletableFuture<File> download = CompletableFuture.supplyAsync(() -> { | ||||||
| 			try (final ReadableByteChannel source = Channels.newChannel(new URL(version.getUrl()).openStream()); final FileOutputStream target = new FileOutputStream(file)) |       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); |         target.getChannel().transferFrom(source, 0, Long.MAX_VALUE); | ||||||
| 			} |       } catch (final IOException ex) { | ||||||
| 			catch (final IOException ex) |  | ||||||
| 			{ |  | ||||||
|         throw new CompletionException(ex); |         throw new CompletionException(ex); | ||||||
|       } |       } | ||||||
|       return file; |       return file; | ||||||
| 		}); |     }, ASYNC_EXECUTOR); | ||||||
|  |  | ||||||
|     download.whenCompleteAsync((value, exception) -> { |     download.whenCompleteAsync((value, exception) -> { | ||||||
|       await.remove(toIndexName(expansion)); |       await.remove(toIndexName(expansion)); | ||||||
|  |  | ||||||
| 			if (exception != null) |       if (exception != null) { | ||||||
| 			{ |         plugin.getLogger().log(Level.SEVERE, | ||||||
| 				plugin.getLogger().log(Level.SEVERE, "failed to download " + expansion.getName() + ":" + version.getVersion(), exception); |             "failed to download " + expansion.getName() + ":" + version.getVersion(), exception); | ||||||
|       } |       } | ||||||
| 		}); |     }, ASYNC_EXECUTOR); | ||||||
|  |  | ||||||
|     await.put(toIndexName(expansion), download); |     await.put(toIndexName(expansion), download); | ||||||
|  |  | ||||||
|     return 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,19 +60,7 @@ 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; |  | ||||||
| import java.util.HashMap; |  | ||||||
| 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.logging.Level; |  | ||||||
|  |  | ||||||
| public final class LocalExpansionManager implements Listener |  | ||||||
| { |  | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
|   private static final String EXPANSIONS_FOLDER_NAME = "expansions"; |   private static final String EXPANSIONS_FOLDER_NAME = "expansions"; | ||||||
| @@ -68,94 +72,103 @@ public final class LocalExpansionManager implements Listener | |||||||
|   private final PlaceholderAPIPlugin plugin; |   private final PlaceholderAPIPlugin plugin; | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
| 	private final Map<String, PlaceholderExpansion> expansions = new HashMap<>(); |   private final Map<String, PlaceholderExpansion> expansions = new ConcurrentHashMap<>(); | ||||||
|  |   private final ReentrantLock expansionsLock = new ReentrantLock(); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public LocalExpansionManager(@NotNull final PlaceholderAPIPlugin plugin) |   public LocalExpansionManager(@NotNull final PlaceholderAPIPlugin plugin) { | ||||||
| 	{ |  | ||||||
|     this.plugin = plugin; |     this.plugin = plugin; | ||||||
|     this.folder = new File(plugin.getDataFolder(), EXPANSIONS_FOLDER_NAME); |     this.folder = new File(plugin.getDataFolder(), EXPANSIONS_FOLDER_NAME); | ||||||
|  |  | ||||||
| 		if (!this.folder.exists() && !folder.mkdirs()) |     if (!this.folder.exists() && !folder.mkdirs()) { | ||||||
| 		{ |  | ||||||
|       plugin.getLogger().log(Level.WARNING, "failed to create expansions folder!"); |       plugin.getLogger().log(Level.WARNING, "failed to create expansions folder!"); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 	public void load(@NotNull final CommandSender sender) |   public void load(@NotNull final CommandSender sender) { | ||||||
| 	{ |  | ||||||
|     registerAll(sender); |     registerAll(sender); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 	public void kill() |   public void kill() { | ||||||
| 	{ |  | ||||||
|     unregisterAll(); |     unregisterAll(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public File getExpansionsFolder() |   public File getExpansionsFolder() { | ||||||
| 	{ |  | ||||||
|     return folder; |     return folder; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 	public int getExpansionsCount() |  | ||||||
| 	{ |  | ||||||
| 		return expansions.size(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
|   @Unmodifiable |   @Unmodifiable | ||||||
| 	public Collection<String> getIdentifiers() |   public Collection<String> getIdentifiers() { | ||||||
| 	{ |     expansionsLock.lock(); | ||||||
|  |     try { | ||||||
|       return ImmutableSet.copyOf(expansions.keySet()); |       return ImmutableSet.copyOf(expansions.keySet()); | ||||||
|  |     } finally { | ||||||
|  |       expansionsLock.unlock(); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
|   @Unmodifiable |   @Unmodifiable | ||||||
| 	public Collection<PlaceholderExpansion> getExpansions() |   public Collection<PlaceholderExpansion> getExpansions() { | ||||||
| 	{ |     expansionsLock.lock(); | ||||||
|  |     try { | ||||||
|       return ImmutableSet.copyOf(expansions.values()); |       return ImmutableSet.copyOf(expansions.values()); | ||||||
|  |     } finally { | ||||||
|  |       expansionsLock.unlock(); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   @Nullable |   @Nullable | ||||||
| 	public PlaceholderExpansion getExpansion(@NotNull final String identifier) |   public PlaceholderExpansion getExpansion(@NotNull final String identifier) { | ||||||
| 	{ |     expansionsLock.lock(); | ||||||
|  |     try { | ||||||
|       return expansions.get(identifier.toLowerCase()); |       return expansions.get(identifier.toLowerCase()); | ||||||
|  |     } finally { | ||||||
|  |       expansionsLock.unlock(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public Optional<PlaceholderExpansion> findExpansionByName(@NotNull final String name) |  | ||||||
| 	{ |  | ||||||
| 		return expansions.values().stream().filter(expansion -> name.equalsIgnoreCase(expansion.getName())).findFirst(); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public Optional<PlaceholderExpansion> findExpansionByIdentifier(@NotNull final String identifier) |   public Optional<PlaceholderExpansion> findExpansionByName(@NotNull final String name) { | ||||||
| 	{ |     expansionsLock.lock(); | ||||||
|  |     try { | ||||||
|  |       PlaceholderExpansion bestMatch = null; | ||||||
|  |       for (Map.Entry<String, PlaceholderExpansion> entry : expansions.entrySet()) { | ||||||
|  |         PlaceholderExpansion expansion = entry.getValue(); | ||||||
|  |         if (expansion.getName().equalsIgnoreCase(name)) { | ||||||
|  |           bestMatch = expansion; | ||||||
|  |           break; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       return Optional.ofNullable(bestMatch); | ||||||
|  |     } finally { | ||||||
|  |       expansionsLock.unlock(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @NotNull | ||||||
|  |   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); |       return Optional.of(expansion); | ||||||
| 		} |     } catch (final LinkageError ex) { | ||||||
| 		catch (final LinkageError ex) |  | ||||||
| 		{ |  | ||||||
|       plugin.getLogger().severe("expansion class " + clazz.getSimpleName() + " is outdated: \n" + |       plugin.getLogger().severe("expansion class " + clazz.getSimpleName() + " is outdated: \n" + | ||||||
| 									  "Failed to load due to a [" + ex.getClass().getSimpleName() + "], attempted to use " + ex.getMessage()); |           "Failed to load due to a [" + ex.getClass().getSimpleName() + "], attempted to use " + ex | ||||||
|  |           .getMessage()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return Optional.empty(); |     return Optional.empty(); | ||||||
| @@ -165,38 +178,32 @@ public final class LocalExpansionManager implements Listener | |||||||
|    * Do not call this method yourself, use {@link PlaceholderExpansion#register()} |    * Do not call this method yourself, use {@link PlaceholderExpansion#register()} | ||||||
|    */ |    */ | ||||||
|   @ApiStatus.Internal |   @ApiStatus.Internal | ||||||
| 	public boolean register(@NotNull final PlaceholderExpansion expansion) |   public boolean register(@NotNull final PlaceholderExpansion expansion) { | ||||||
| 	{ |  | ||||||
|     final String identifier = expansion.getIdentifier().toLowerCase(); |     final String identifier = expansion.getIdentifier().toLowerCase(); | ||||||
|  |  | ||||||
| 		if (expansion instanceof Configurable) |     if (!expansion.canRegister()) { | ||||||
| 		{ |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     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()) { | ||||||
| 				for (Map.Entry<String, Object> entries : defaults.entrySet()) |           if (entries.getKey() == null || entries.getKey().isEmpty()) { | ||||||
| 				{ |  | ||||||
| 					if (entries.getKey() == null || entries.getKey().isEmpty()) |  | ||||||
| 					{ |  | ||||||
|             continue; |             continue; | ||||||
|           } |           } | ||||||
|  |  | ||||||
| 					if (entries.getValue() == null) |           if (entries.getValue() == null) { | ||||||
| 					{ |             if (cfg.contains(pre + entries.getKey())) { | ||||||
| 						if (cfg.contains(pre + entries.getKey())) |  | ||||||
| 						{ |  | ||||||
|               save = true; |               save = true; | ||||||
|               cfg.set(pre + entries.getKey(), null); |               cfg.set(pre + entries.getKey(), null); | ||||||
|             } |             } | ||||||
| 					} |           } else { | ||||||
| 					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(), entries.getValue()); | ||||||
|             } |             } | ||||||
| @@ -204,58 +211,59 @@ public final class LocalExpansionManager implements Listener | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |  | ||||||
| 			if (save) |       if (save) { | ||||||
| 			{ |  | ||||||
|         plugin.saveConfig(); |         plugin.saveConfig(); | ||||||
|         plugin.reloadConfig(); |         plugin.reloadConfig(); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		if (expansion instanceof VersionSpecific) |     if (expansion instanceof VersionSpecific) { | ||||||
| 		{ |  | ||||||
|       VersionSpecific nms = (VersionSpecific) expansion; |       VersionSpecific nms = (VersionSpecific) expansion; | ||||||
| 			if (!nms.isCompatibleWith(PlaceholderAPIPlugin.getServerVersion())) |       if (!nms.isCompatibleWith(PlaceholderAPIPlugin.getServerVersion())) { | ||||||
| 			{ |         plugin.getLogger().info( | ||||||
| 				plugin.getLogger().info("Your server version is not compatible with expansion: " + expansion.getIdentifier() + " version: " + expansion.getVersion()); |             "Your server version is not compatible with expansion: " + expansion.getIdentifier() | ||||||
|  |                 + " version: " + expansion.getVersion()); | ||||||
|         return false; |         return false; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		final PlaceholderExpansion removed = expansions.get(identifier); |     final PlaceholderExpansion removed = getExpansion(identifier); | ||||||
| 		if (removed != null && !removed.unregister()) |     if (removed != null && !removed.unregister()) { | ||||||
| 		{ |  | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     final ExpansionRegisterEvent event = new ExpansionRegisterEvent(expansion); |     final ExpansionRegisterEvent event = new ExpansionRegisterEvent(expansion); | ||||||
|     Bukkit.getPluginManager().callEvent(event); |     Bukkit.getPluginManager().callEvent(event); | ||||||
|  |  | ||||||
| 		if (event.isCancelled()) |     if (event.isCancelled()) { | ||||||
| 		{ |  | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     expansionsLock.lock(); | ||||||
|  |     try { | ||||||
|       expansions.put(identifier, expansion); |       expansions.put(identifier, expansion); | ||||||
|  |     } finally { | ||||||
|  |       expansionsLock.unlock(); | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		if (expansion instanceof Listener) |     if (expansion instanceof Listener) { | ||||||
| 		{ |  | ||||||
|       Bukkit.getPluginManager().registerEvents(((Listener) expansion), plugin); |       Bukkit.getPluginManager().registerEvents(((Listener) expansion), plugin); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     plugin.getLogger().info("Successfully registered expansion: " + expansion.getIdentifier()); |     plugin.getLogger().info("Successfully registered expansion: " + expansion.getIdentifier()); | ||||||
|  |  | ||||||
| 		if (expansion instanceof Taskable) |     if (expansion instanceof Taskable) { | ||||||
| 		{ |  | ||||||
|       ((Taskable) expansion).start(); |       ((Taskable) expansion).start(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		if (plugin.getPlaceholderAPIConfig().isCloudEnabled()) |     if (plugin.getPlaceholderAPIConfig().isCloudEnabled()) { | ||||||
| 		{ |       final Optional<CloudExpansion> cloudExpansionOptional = | ||||||
| 			final Optional<CloudExpansion> cloudExpansion = plugin.getCloudExpansionManager().findCloudExpansionByName(identifier); |           plugin.getCloudExpansionManager().findCloudExpansionByName(identifier); | ||||||
| 			if (cloudExpansion.isPresent()) |       if (cloudExpansionOptional.isPresent()) { | ||||||
| 			{ |         CloudExpansion cloudExpansion = cloudExpansionOptional.get(); | ||||||
| 				cloudExpansion.get().setHasExpansion(true); |         cloudExpansion.setHasExpansion(true); | ||||||
| 				cloudExpansion.get().setShouldUpdate(!cloudExpansion.get().getLatestVersion().equals(expansion.getVersion())); |         cloudExpansion.setShouldUpdate( | ||||||
|  |             !cloudExpansion.getLatestVersion().equals(expansion.getVersion())); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -266,35 +274,28 @@ public final class LocalExpansionManager implements Listener | |||||||
|    * Do not call this method yourself, use {@link PlaceholderExpansion#unregister()} |    * Do not call this method yourself, use {@link PlaceholderExpansion#unregister()} | ||||||
|    */ |    */ | ||||||
|   @ApiStatus.Internal |   @ApiStatus.Internal | ||||||
| 	public boolean unregister(@NotNull final PlaceholderExpansion expansion) |   public boolean unregister(@NotNull final PlaceholderExpansion expansion) { | ||||||
| 	{ |     if (expansions.remove(expansion.getIdentifier()) == null) { | ||||||
| 		if (expansions.remove(expansion.getIdentifier()) == null) |  | ||||||
| 		{ |  | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     Bukkit.getPluginManager().callEvent(new ExpansionUnregisterEvent(expansion)); |     Bukkit.getPluginManager().callEvent(new ExpansionUnregisterEvent(expansion)); | ||||||
|  |  | ||||||
|  |     if (expansion instanceof Listener) { | ||||||
| 		if (expansion instanceof Listener) |  | ||||||
| 		{ |  | ||||||
|       HandlerList.unregisterAll((Listener) expansion); |       HandlerList.unregisterAll((Listener) expansion); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		if (expansion instanceof Taskable) |     if (expansion instanceof Taskable) { | ||||||
| 		{ |  | ||||||
|       ((Taskable) expansion).stop(); |       ((Taskable) expansion).stop(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		if (expansion instanceof Cacheable) |     if (expansion instanceof Cacheable) { | ||||||
| 		{ |  | ||||||
|       ((Cacheable) expansion).clear(); |       ((Cacheable) expansion).clear(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		if (plugin.getPlaceholderAPIConfig().isCloudEnabled()) |     if (plugin.getPlaceholderAPIConfig().isCloudEnabled()) { | ||||||
| 		{ |       plugin.getCloudExpansionManager().findCloudExpansionByName(expansion.getName()) | ||||||
| 			plugin.getCloudExpansionManager().findCloudExpansionByName(expansion.getName()).ifPresent(cloud -> { |           .ifPresent(cloud -> { | ||||||
|             cloud.setHasExpansion(false); |             cloud.setHasExpansion(false); | ||||||
|             cloud.setShouldUpdate(false); |             cloud.setShouldUpdate(false); | ||||||
|           }); |           }); | ||||||
| @@ -304,30 +305,27 @@ public final class LocalExpansionManager implements Listener | |||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
| 	private void registerAll(@NotNull final CommandSender sender) |   private void registerAll(@NotNull final CommandSender sender) { | ||||||
| 	{ |  | ||||||
|     plugin.getLogger().info("Placeholder expansion registration initializing..."); |     plugin.getLogger().info("Placeholder expansion registration initializing..."); | ||||||
|  |  | ||||||
|     Futures.onMainThread(plugin, findExpansionsOnDisk(), (classes, exception) -> { |     Futures.onMainThread(plugin, findExpansionsOnDisk(), (classes, exception) -> { | ||||||
| 			if (exception != null) |       if (exception != null) { | ||||||
| 			{ |  | ||||||
|         plugin.getLogger().log(Level.SEVERE, "failed to load class files of expansions", exception); |         plugin.getLogger().log(Level.SEVERE, "failed to load class files of expansions", exception); | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| 			final long registered = classes.stream().map(this::register).filter(Optional::isPresent).count(); |       final long registered = classes.stream().map(this::register).filter(Optional::isPresent) | ||||||
|  |           .count(); | ||||||
|  |  | ||||||
|       Msg.msg(sender, |       Msg.msg(sender, | ||||||
| 					registered == 0 ? "&6No expansions were registered!" : registered + "&a placeholder hooks successfully registered!"); |           registered == 0 ? "&6No expansions were registered!" | ||||||
|  |               : registered + "&a placeholder hooks successfully registered!"); | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 	private void unregisterAll() |   private void unregisterAll() { | ||||||
| 	{ |     for (final PlaceholderExpansion expansion : Sets.newHashSet(expansions.values())) { | ||||||
| 		for (final PlaceholderExpansion expansion : Sets.newHashSet(expansions.values())) |       if (expansion.persist()) { | ||||||
| 		{ |  | ||||||
| 			if (expansion.persist()) |  | ||||||
| 			{ |  | ||||||
|         continue; |         continue; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -337,29 +335,24 @@ public final class LocalExpansionManager implements Listener | |||||||
|  |  | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public CompletableFuture<@NotNull List<@NotNull Class<? extends PlaceholderExpansion>>> findExpansionsOnDisk() |   public CompletableFuture<@NotNull List<@NotNull Class<? extends PlaceholderExpansion>>> findExpansionsOnDisk() { | ||||||
| 	{ |  | ||||||
|     return Arrays.stream(folder.listFiles((dir, name) -> name.endsWith(".jar"))) |     return Arrays.stream(folder.listFiles((dir, name) -> name.endsWith(".jar"))) | ||||||
|         .map(this::findExpansionInFile) |         .map(this::findExpansionInFile) | ||||||
|         .collect(Futures.collector()); |         .collect(Futures.collector()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public CompletableFuture<@Nullable Class<? extends PlaceholderExpansion>> findExpansionInFile(@NotNull final File file) |   public CompletableFuture<@Nullable Class<? extends PlaceholderExpansion>> findExpansionInFile( | ||||||
| 	{ |       @NotNull final File file) { | ||||||
|     return CompletableFuture.supplyAsync(() -> { |     return CompletableFuture.supplyAsync(() -> { | ||||||
| 			try |       try { | ||||||
| 			{ |  | ||||||
|         return FileUtil.findClass(file, PlaceholderExpansion.class); |         return FileUtil.findClass(file, PlaceholderExpansion.class); | ||||||
| 			} |       } catch (final VerifyError ex) { | ||||||
| 			catch (final VerifyError ex) |  | ||||||
| 			{ |  | ||||||
|         plugin.getLogger().severe("expansion file " + file.getName() + " is outdated: \n" + |         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(' '))); |             "Failed to load due to a [" + ex.getClass().getSimpleName() + "], attempted to use" + ex | ||||||
|  |             .getMessage().substring(ex.getMessage().lastIndexOf(' '))); | ||||||
|         return null; |         return null; | ||||||
| 			} |       } catch (final Exception ex) { | ||||||
| 			catch (final Exception ex) |  | ||||||
| 			{ |  | ||||||
|         throw new CompletionException(ex); |         throw new CompletionException(ex); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
| @@ -367,32 +360,27 @@ public final class LocalExpansionManager implements Listener | |||||||
|  |  | ||||||
|  |  | ||||||
|   @Nullable |   @Nullable | ||||||
| 	public PlaceholderExpansion createExpansionInstance(@NotNull final Class<? extends PlaceholderExpansion> clazz) throws LinkageError |   public PlaceholderExpansion createExpansionInstance( | ||||||
| 	{ |       @NotNull final Class<? extends PlaceholderExpansion> clazz) throws LinkageError { | ||||||
| 		try |     try { | ||||||
| 		{ |  | ||||||
|       return clazz.getDeclaredConstructor().newInstance(); |       return clazz.getDeclaredConstructor().newInstance(); | ||||||
| 		} |     } catch (final Exception ex) { | ||||||
| 		catch (final Exception ex) |       if (ex.getCause() instanceof LinkageError) { | ||||||
| 		{ |  | ||||||
| 			if (ex.getCause() instanceof LinkageError) |  | ||||||
| 			{ |  | ||||||
|         throw ((LinkageError) ex.getCause()); |         throw ((LinkageError) ex.getCause()); | ||||||
|       } |       } | ||||||
|  |  | ||||||
| 			plugin.getLogger().log(Level.SEVERE, "Failed to load placeholder expansion from class: " + clazz.getName(), ex); |       plugin.getLogger() | ||||||
|  |           .log(Level.SEVERE, "Failed to load placeholder expansion from class: " + clazz.getName(), | ||||||
|  |               ex); | ||||||
|       return null; |       return null; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   @EventHandler |   @EventHandler | ||||||
| 	public void onQuit(@NotNull final PlayerQuitEvent event) |   public void onQuit(@NotNull final PlayerQuitEvent event) { | ||||||
| 	{ |     for (final PlaceholderExpansion expansion : getExpansions()) { | ||||||
| 		for (final PlaceholderExpansion expansion : getExpansions()) |       if (!(expansion instanceof Cleanable)) { | ||||||
| 		{ |  | ||||||
| 			if (!(expansion instanceof Cleanable)) |  | ||||||
| 			{ |  | ||||||
|         continue; |         continue; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -401,18 +389,14 @@ public final class LocalExpansionManager implements Listener | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   @EventHandler(priority = EventPriority.HIGH) |   @EventHandler(priority = EventPriority.HIGH) | ||||||
| 	public void onPluginDisable(@NotNull final PluginDisableEvent event) |   public void onPluginDisable(@NotNull final PluginDisableEvent event) { | ||||||
| 	{ |  | ||||||
|     final String name = event.getPlugin().getName(); |     final String name = event.getPlugin().getName(); | ||||||
| 		if (name.equals(plugin.getName())) |     if (name.equals(plugin.getName())) { | ||||||
| 		{ |  | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		for (final PlaceholderExpansion expansion : getExpansions()) |     for (final PlaceholderExpansion expansion : getExpansions()) { | ||||||
| 		{ |       if (!name.equalsIgnoreCase(expansion.getRequiredPlugin())) { | ||||||
| 			if (!name.equalsIgnoreCase(expansion.getRequiredPlugin())) |  | ||||||
| 			{ |  | ||||||
|         continue; |         continue; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 | ||||||
|    */ |    */ | ||||||
| @@ -189,12 +190,14 @@ public class JSONMessage { | |||||||
|    * @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,7 +244,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 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 | ||||||
| @@ -247,8 +253,9 @@ public class JSONMessage { | |||||||
|    * @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,14 +28,12 @@ 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); | ||||||
| @@ -44,16 +42,15 @@ public final class ServerLoadEventListener implements Listener | |||||||
|   /** |   /** | ||||||
|    * 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,60 +20,53 @@ | |||||||
|  |  | ||||||
| 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 |   @NotNull | ||||||
|   private final Closure closure; |   private final Closure closure; | ||||||
|  |  | ||||||
| 	public CharsReplacer(@NotNull final Closure closure) |   public CharsReplacer(@NotNull final Closure closure) { | ||||||
| 	{ |  | ||||||
|     this.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' | ||||||
|  |             && c != 'e' && c != 'f' && c != 'k' && c != 'l' && c != 'm' && c != 'n' && c != 'o' && c != 'r' | ||||||
|  |             && c != 'x') { | ||||||
|           builder.append(l).append(chars[i]); |           builder.append(l).append(chars[i]); | ||||||
| 				} |         } else { | ||||||
| 				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; | ||||||
| @@ -82,10 +75,8 @@ public final class CharsReplacer implements Replacer | |||||||
|           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; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -93,53 +84,44 @@ public final class CharsReplacer implements Replacer | |||||||
|             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 { | ||||||
| 					else |  | ||||||
| 					{ |  | ||||||
|             builder.setLength(builder.length() - (j * 2)); // undo &x parsing |             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 { | ||||||
| 				else |  | ||||||
| 				{ |  | ||||||
|           identifier.append(p); |           identifier.append(p); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| @@ -150,26 +132,24 @@ public final class CharsReplacer implements Replacer | |||||||
|       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); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if (hadSpace) { | ||||||
|           builder.append(' '); |           builder.append(' '); | ||||||
|  |         } | ||||||
|         continue; |         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('_'); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -178,12 +158,10 @@ public final class CharsReplacer implements Replacer | |||||||
|       } |       } | ||||||
|  |  | ||||||
|       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('_'); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,48 +20,44 @@ | |||||||
|  |  | ||||||
| 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 |   @NotNull | ||||||
|   private final Pattern pattern; |   private final Pattern pattern; | ||||||
|  |  | ||||||
| 	public RegexReplacer(@NotNull final Closure closure) |   public RegexReplacer(@NotNull final Closure closure) { | ||||||
| 	{ |     this.pattern = Pattern.compile(String | ||||||
| 		this.pattern = Pattern.compile(String.format("\\%s((?<identifier>[a-zA-Z0-9]+)_)(?<parameters>[^%s%s]+)\\%s", closure.head, closure.head, closure.tail, closure.tail)); |         .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; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,30 +20,27 @@ | |||||||
|  |  | ||||||
| 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 |   @NotNull | ||||||
| 	String apply(@NotNull final String text, @Nullable final OfflinePlayer player, @NotNull final Function<String, @Nullable PlaceholderExpansion> lookup); |   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,11 +32,6 @@ 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; | ||||||
|   | |||||||
| @@ -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,15 +28,15 @@ 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; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -48,33 +45,27 @@ public class FileUtil | |||||||
|     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( | ||||||
| 		try (final JarInputStream stream = new JarInputStream(jar.openStream()); final URLClassLoader loader = new URLClassLoader(new URL[]{jar}, clazz.getClassLoader())) |         jar.openStream()); final URLClassLoader loader = new URLClassLoader(new URL[]{jar}, | ||||||
| 		{ |         clazz.getClassLoader())) { | ||||||
|       JarEntry entry; |       JarEntry entry; | ||||||
| 			while ((entry = stream.getNextJarEntry()) != null) |       while ((entry = stream.getNextJarEntry()) != null) { | ||||||
| 			{ |  | ||||||
|         final String name = entry.getName(); |         final String name = entry.getName(); | ||||||
| 				if (name == null || name.isEmpty() || !name.endsWith(".class")) |         if (name == null || name.isEmpty() || !name.endsWith(".class")) { | ||||||
| 				{ |  | ||||||
|           continue; |           continue; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         matches.add(name.substring(0, name.lastIndexOf('.')).replace('/', '.')); |         matches.add(name.substring(0, name.lastIndexOf('.')).replace('/', '.')); | ||||||
|       } |       } | ||||||
|  |  | ||||||
| 			for (final String match : matches) |       for (final String match : matches) { | ||||||
| 			{ |         try { | ||||||
| 				try |  | ||||||
| 				{ |  | ||||||
|           final Class<?> loaded = loader.loadClass(match); |           final Class<?> loaded = loader.loadClass(match); | ||||||
| 					if (clazz.isAssignableFrom(loaded)) |           if (clazz.isAssignableFrom(loaded)) { | ||||||
| 					{ |  | ||||||
|             classes.add(loaded.asSubclass(clazz)); |             classes.add(loaded.asSubclass(clazz)); | ||||||
|           } |           } | ||||||
|  |         } catch (final NoClassDefFoundError ignored) { | ||||||
|         } |         } | ||||||
| 				catch (final NoClassDefFoundError ignored) |  | ||||||
| 				{ } |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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() |  | ||||||
| 	{} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public enum Align |  | ||||||
| 	{ |  | ||||||
| 		LEFT, RIGHT |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |   private Format() {} | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
| 	public static Optional<List<String>> tablify(@NotNull final Align align, @NotNull final List<List<String>> rows) |   public static Optional<List<String>> tablify(@NotNull final Align align, | ||||||
| 	{ |       @NotNull final List<List<String>> rows) { | ||||||
|     return findSpacing(rows) |     return findSpacing(rows) | ||||||
|         .map(spacing -> buildFormat(align, spacing)) |         .map(spacing -> buildFormat(align, spacing)) | ||||||
|         .map(format -> rows.stream() |         .map(format -> rows.stream() | ||||||
| 								   .map(row -> String.format(format, row.toArray()).substring(align == Align.RIGHT ? 2 : 0)) |             .map( | ||||||
|  |                 row -> String.format(format, row.toArray()).substring(align == Align.RIGHT ? 2 : 0)) | ||||||
|             .collect(toList())); |             .collect(toList())); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
| 	private static String buildFormat(@NotNull final Align align, @NotNull final int[] spacing) |   private static String buildFormat(@NotNull final Align align, @NotNull final int[] spacing) { | ||||||
| 	{ |  | ||||||
|     return stream(spacing) |     return stream(spacing) | ||||||
|         .mapToObj(space -> "%" + (align == Align.LEFT ? "-" : "") + (space + 2) + "s") |         .mapToObj(space -> "%" + (align == Align.LEFT ? "-" : "") + (space + 2) + "s") | ||||||
|         .collect(joining()); |         .collect(joining()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @NotNull |   @NotNull | ||||||
| 	private static Optional<int[]> findSpacing(@NotNull final List<List<String>> rows) |   private static Optional<int[]> findSpacing(@NotNull final List<List<String>> rows) { | ||||||
| 	{ |  | ||||||
|     return rows.stream() |     return rows.stream() | ||||||
|         .map(row -> row.stream().mapToInt(String::length).toArray()) |         .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()); |         .reduce((l, r) -> range(0, min(l.length, r.length)).map(i -> max(l[i], r[i])).toArray()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   public enum Align { | ||||||
|  |     LEFT, RIGHT | ||||||
|  |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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,23 +27,22 @@ 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, | ||||||
|  |       @NotNull final BiConsumer<T, Throwable> consumer) { | ||||||
|     future.whenComplete((value, exception) -> { |     future.whenComplete((value, exception) -> { | ||||||
| 			if (Bukkit.isPrimaryThread()) |       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)); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
| @@ -55,28 +50,27 @@ public final class Futures | |||||||
|  |  | ||||||
|  |  | ||||||
|   @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,39 +20,33 @@ | |||||||
|  |  | ||||||
| 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) { | ||||||
|  |  | ||||||
| 	public static void msg(@NotNull final CommandSender sender, @NotNull final String... messages) |  | ||||||
| 	{ |  | ||||||
| 		if (messages.length == 0) |  | ||||||
| 		{ |  | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     sender.sendMessage(Arrays.stream(messages).map(Msg::color).collect(Collectors.joining("\n"))); |     sender.sendMessage(Arrays.stream(messages).map(Msg::color).collect(Collectors.joining("\n"))); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 	public static void broadcast(@NotNull final String... messages) |   public static void broadcast(@NotNull final String... messages) { | ||||||
| 	{ |     if (messages.length == 0) { | ||||||
| 		if (messages.length == 0) |  | ||||||
| 		{ |  | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 		Bukkit.broadcastMessage(Arrays.stream(messages).map(Msg::color).collect(Collectors.joining("\n"))); |     Bukkit.broadcastMessage( | ||||||
|  |         Arrays.stream(messages).map(Msg::color).collect(Collectors.joining("\n"))); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 	public static String color(@NotNull final String text) |   public static String color(@NotNull final String text) { | ||||||
| 	{ |  | ||||||
|     return ChatColor.translateAlternateColorCodes('&', text); |     return ChatColor.translateAlternateColorCodes('&', text); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public static String getRemaining(final long seconds, final TimeFormat type) { | ||||||
|     switch (type) { |     switch (type) { | ||||||
|                 case DAYS: |       default: | ||||||
|                 case HOURS: |         return String.valueOf(seconds); | ||||||
|                 case MINUTES: |  | ||||||
|                     return "0"; |  | ||||||
|       case SECONDS: |       case SECONDS: | ||||||
|                     return String.valueOf(seconds); |         return String.valueOf(seconds % 60); | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return String.valueOf(seconds); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         int minutes = seconds / 60; |  | ||||||
|         int s = 60 * minutes; |  | ||||||
|         int secondsLeft = seconds - s; |  | ||||||
|  |  | ||||||
|         if (minutes < 60) { |  | ||||||
|             switch (type) { |  | ||||||
|                 case DAYS: |  | ||||||
|                 case HOURS: |  | ||||||
|                     return "0"; |  | ||||||
|       case MINUTES: |       case MINUTES: | ||||||
|                     return String.valueOf(minutes); |         return String.valueOf((seconds / 60) % 60); | ||||||
|                 case SECONDS: |  | ||||||
|                     return String.valueOf(secondsLeft); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return String.valueOf(seconds); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (minutes < 1440) { |  | ||||||
|             int hours = minutes / 60; |  | ||||||
|             int inMins = 60 * hours; |  | ||||||
|             int leftOver = minutes - inMins; |  | ||||||
|  |  | ||||||
|             switch (type) { |  | ||||||
|                 case DAYS: |  | ||||||
|                     return "0"; |  | ||||||
|       case HOURS: |       case HOURS: | ||||||
|                     return String.valueOf(hours); |         return String.valueOf((seconds / 3600) % 24); | ||||||
|                 case MINUTES: |  | ||||||
|                     return String.valueOf(leftOver); |  | ||||||
|                 case SECONDS: |  | ||||||
|                     return String.valueOf(secondsLeft); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return String.valueOf(seconds); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         int days = minutes / 1440; |  | ||||||
|         int inMins = 1440 * days; |  | ||||||
|         int leftOver = minutes - inMins; |  | ||||||
|  |  | ||||||
|         if (leftOver < 60) { |  | ||||||
|             switch (type) { |  | ||||||
|       case DAYS: |       case DAYS: | ||||||
|                     return String.valueOf(days); |         return String.valueOf(seconds / 86400); | ||||||
|                 case HOURS: |  | ||||||
|                     return String.valueOf(0); |  | ||||||
|                 case MINUTES: |  | ||||||
|                     return String.valueOf(leftOver); |  | ||||||
|                 case SECONDS: |  | ||||||
|                     return String.valueOf(secondsLeft); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|             return String.valueOf(seconds); |  | ||||||
|  |  | ||||||
|         } else { |  | ||||||
|             int hours = leftOver / 60; |  | ||||||
|             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) { |  | ||||||
|         return getTime(Duration.ofSeconds(seconds)); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Format the given value with s, m, h and d (seconds, minutes, hours and days) |    * Format the given value with s, m, h and d (seconds, minutes, hours and days) | ||||||
|    * |    * | ||||||
|      * @param duration {@link Duration} (eg, Duration.of(20, {@link ChronoUnit#SECONDS}) for 20 seconds) |    * @param duration {@link Duration} (eg, Duration.of(20, {@link ChronoUnit#SECONDS}) for 20 | ||||||
|  |    *                 seconds) | ||||||
|    * @return formatted time |    * @return formatted time | ||||||
|    */ |    */ | ||||||
|   public static String getTime(final Duration duration) { |   public static String getTime(final Duration duration) { | ||||||
|         final StringBuilder builder = new StringBuilder(); |     return getTime(duration.getSeconds()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public static String getTime(final int seconds) { | ||||||
|  |     return getTime((long) seconds); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public static String getTime(long seconds) { | ||||||
|  |     final StringJoiner joiner = new StringJoiner(" "); | ||||||
|  |  | ||||||
|         long seconds = duration.getSeconds(); |  | ||||||
|     long minutes = seconds / 60; |     long minutes = seconds / 60; | ||||||
|     long hours = minutes / 60; |     long hours = minutes / 60; | ||||||
|         long days = hours / 24; |     final long days = hours / 24; | ||||||
|  |  | ||||||
|     seconds %= 60; |     seconds %= 60; | ||||||
|     minutes %= 60; |     minutes %= 60; | ||||||
|         hours %= 60; |     hours %= 24; | ||||||
|         days %= 24; |  | ||||||
|  |  | ||||||
|         if (seconds > 0) { |     if (days > 0) { | ||||||
|             builder.insert(0, seconds + "s"); |       joiner.add(days + "d"); | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (minutes > 0) { |  | ||||||
|             if (builder.length() > 0) { |  | ||||||
|                 builder.insert(0, ' '); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             builder.insert(0, minutes + "m"); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (hours > 0) { |     if (hours > 0) { | ||||||
|             if (builder.length() > 0) { |       joiner.add(hours + "h"); | ||||||
|                 builder.insert(0, ' '); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|             builder.insert(0, hours + "h"); |     if (minutes > 0) { | ||||||
|  |       joiner.add(minutes + "m"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|         if (days > 0) { |     if (seconds > 0) { | ||||||
|             if (builder.length() > 0) { |       joiner.add(seconds + "s"); | ||||||
|                 builder.insert(0, ' '); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|             builder.insert(0, days + "d"); |     return joiner.toString(); | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return builder.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@" | ||||||
|   | |||||||
| @@ -29,8 +29,7 @@ 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%"; | ||||||
| @@ -44,8 +43,7 @@ public interface Values | |||||||
|   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"; | ||||||
| @@ -55,36 +53,30 @@ public interface Values | |||||||
|  |  | ||||||
|     @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": | ||||||
|   | |||||||
| @@ -23,30 +23,25 @@ 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,47 +20,51 @@ | |||||||
|  |  | ||||||
| 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; | ||||||
|  |  | ||||||
|  | public final class ReplacerUnitTester { | ||||||
|  |  | ||||||
|   @Test |   @Test | ||||||
| 	void testCharsReplacerProducesExpectedSingleValue() |   void testCharsReplacerProducesExpectedSingleValue() { | ||||||
| 	{ |     assertEquals(PLAYER_NAME, | ||||||
| 		assertEquals(PLAYER_NAME, Values.CHARS_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get)); |         Values.CHARS_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Test |   @Test | ||||||
| 	void testRegexReplacerProducesExpectedSingleValue() |   void testRegexReplacerProducesExpectedSingleValue() { | ||||||
| 	{ |     assertEquals(PLAYER_NAME, | ||||||
| 		assertEquals(PLAYER_NAME, Values.REGEX_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get)); |         Values.REGEX_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Test |   @Test | ||||||
| 	void testCharsReplacerProducesExpectedSentence() |   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.CHARS_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 testRegexReplacerProducesExpectedSentence() |   void testRegexReplacerProducesExpectedSentence() { | ||||||
| 	{ |     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.REGEX_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Test |   @Test | ||||||
| 	void testResultsAreTheSameAsReplacement() |   void testResultsAreTheSameAsReplacement() { | ||||||
| 	{ |     final String resultChars = Values.CHARS_REPLACER | ||||||
| 		final String resultChars = Values.CHARS_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get); |         .apply("%player_name%", null, Values.PLACEHOLDERS::get); | ||||||
| 		final String resultRegex = Values.REGEX_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get); |     final String resultRegex = Values.REGEX_REPLACER | ||||||
|  |         .apply("%player_name%", null, Values.PLACEHOLDERS::get); | ||||||
|  |  | ||||||
|     assertEquals(resultChars, resultRegex); |     assertEquals(resultChars, resultRegex); | ||||||
|  |  | ||||||
| @@ -68,28 +72,28 @@ public final class ReplacerUnitTester | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Test |   @Test | ||||||
| 	void testResultsAreTheSameNoReplacement() |   void testResultsAreTheSameNoReplacement() { | ||||||
| 	{ |     final String resultChars = Values.CHARS_REPLACER | ||||||
| 		final String resultChars = Values.CHARS_REPLACER.apply("%player_location%", null, Values.PLACEHOLDERS::get); |         .apply("%player_location%", null, Values.PLACEHOLDERS::get); | ||||||
| 		final String resultRegex = Values.REGEX_REPLACER.apply("%player_location%", null, Values.PLACEHOLDERS::get); |     final String resultRegex = Values.REGEX_REPLACER | ||||||
|  |         .apply("%player_location%", null, Values.PLACEHOLDERS::get); | ||||||
|  |  | ||||||
|     assertEquals(resultChars, resultRegex); |     assertEquals(resultChars, resultRegex); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Test |   @Test | ||||||
| 	void testCharsReplacerIgnoresMalformed() |   void testCharsReplacerIgnoresMalformed() { | ||||||
| 	{ |  | ||||||
|     final String text = "10% and %hello world 15%"; |     final String text = "10% and %hello world 15%"; | ||||||
|  |  | ||||||
|     assertEquals(text, Values.CHARS_REPLACER.apply(text, null, Values.PLACEHOLDERS::get)); |     assertEquals(text, Values.CHARS_REPLACER.apply(text, null, Values.PLACEHOLDERS::get)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Test |   @Test | ||||||
| 	void testCharsReplacerHandlesEscapedHex() |   void testCharsReplacerHandlesEscapedHex() { | ||||||
| 	{ |  | ||||||
|     final String text = "\\&xffffffThis should not change."; |     final String text = "\\&xffffffThis should not change."; | ||||||
|  |  | ||||||
| 		assertEquals(text.substring(1), Values.CHARS_REPLACER.apply(text, null, Values.PLACEHOLDERS::get)); |     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