Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3db789fb17 | ||
|
|
bf4119c6ee | ||
|
|
6a056a0c31 |
No files matched your search
@@ -1 +0,0 @@
|
||||
.gitea/CODEOWNERS linguist-detectable=false
|
||||
@@ -1,3 +0,0 @@
|
||||
# Pull requests request review from the eligible staff team(s).
|
||||
# One approval from either an Admin or Developer satisfies branch protection.
|
||||
* @trueog/Admins @trueog/Developers
|
||||
@@ -1,2 +0,0 @@
|
||||
github: Multiverse
|
||||
open_collective: multiverse-plugins
|
||||
@@ -1,77 +0,0 @@
|
||||
name: 🐛 Report a Bug
|
||||
description: Report a problem with Multiverse-Core.
|
||||
title: "[Bug]: "
|
||||
labels: ["Bug: Unconfirmed"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
|
||||
If you are having issues with other submodules of Multiverse, please go to their respective git repo:
|
||||
Multiverse-Portals: https://github.com/Multiverse/Multiverse-Portals/issues/new/choose
|
||||
Multiverse-NetherPortals: https://github.com/Multiverse/Multiverse-NetherPortals/issues/new/choose
|
||||
Multiverse-Inventories: https://github.com/Multiverse/Multiverse-Inventories/issues/new/choose
|
||||
Multiverse-SignPortals: https://github.com/Multiverse/Multiverse-SignPortals/issues/new/choose
|
||||
|
||||
Not sure if this is a bug with Multiverse-Core? Feel free to ask on our Discord server: https://discord.gg/NZtfKky
|
||||
|
||||
When completing the report, please ensure all fields are filled with the correct details requested. Failure to do so will result in your issue being closed.
|
||||
- type: input
|
||||
id: multiverse-version-info
|
||||
attributes:
|
||||
label: '`/mv dumps` output'
|
||||
description: Run `/mv dumps` in the console, then copy and paste the link from the output of the command into this box. If `/mv dumps` command is not available, update multiverse to v5.
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: server-logs
|
||||
attributes:
|
||||
label: Server logs
|
||||
description: >
|
||||
Include full startup log and console error (if any). upload all relevant logs to either https://pastes.dev
|
||||
or https://gist.github.com, save and the paste the link in this box.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: server-version
|
||||
attributes:
|
||||
label: Server Version
|
||||
description: Output of `/version` command.
|
||||
placeholder: server version info
|
||||
render: shell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: bug-description
|
||||
attributes:
|
||||
label: Bug Description
|
||||
description: Describe in detail what the bug is about. Include the expected behaviour and actual behaviour.
|
||||
placeholder: "Example: When running `/mv` it cause the server to crash..."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduce-steps
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Provide detailed instructions to trigger the bug.
|
||||
placeholder: |
|
||||
Example:
|
||||
1. Start a server with only multiverse installed.
|
||||
2. Run `/mv` command.
|
||||
3. Players all get kicked with a "server closed" message.
|
||||
...
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: agreements
|
||||
attributes:
|
||||
label: Agreements
|
||||
description: Ensure you have done the following being submitting this issue.
|
||||
options:
|
||||
- label: I have searched for and ensured there isn't already an open or resolved issue(s) regarding this.
|
||||
required: true
|
||||
- label: >
|
||||
I was able to reproduce my issue on a freshly setup and up-to-date server with the latest
|
||||
version of Multiverse plugins with no other plugins and with no kinds of other server or client mods.
|
||||
required: true
|
||||
@@ -1,5 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: 💬 Multiverse Discord Server
|
||||
url: https://discord.gg/NZtfKky
|
||||
about: Need help with using Multiverse-Core or just want to chat with the devs? Join the Multiverse Discord Server for help!
|
||||
@@ -1,41 +0,0 @@
|
||||
name: 💡 Request a Feature
|
||||
description: Suggest a feature you want to see in Multiverse-Core!
|
||||
title: "[Idea]: "
|
||||
labels: ["Type: Idea"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to share your ideas!
|
||||
|
||||
If you are look for other submodules of Multiverse, go to their respective git repo:
|
||||
Multiverse-Portals: https://github.com/Multiverse/Multiverse-Portals/issues/new/choose
|
||||
Multiverse-NetherPortals: https://github.com/Multiverse/Multiverse-NetherPortals/issues/new/choose
|
||||
Multiverse-Inventories: https://github.com/Multiverse/Multiverse-Inventories/issues/new/choose
|
||||
Multiverse-SignPortals: https://github.com/Multiverse/Multiverse-SignPortals/issues/new/choose
|
||||
|
||||
Not sure if your feature fits in Multiverse-Core? Feel free to ask on our Discord server: https://discord.gg/NZtfKky
|
||||
- type: textarea
|
||||
id: feature-description
|
||||
attributes:
|
||||
label: Describe the feature
|
||||
description: What feature are you suggesting?
|
||||
placeholder: "Example: I hope multiverse can implement random teleport feature..."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: feature-reasoning
|
||||
attributes:
|
||||
label: How is the feature useful to all Multiverse users?
|
||||
description: How is the feature useful to all players, server owners and/or developers?
|
||||
placeholder: "Example: Random teleporting can be integrated into many multiverse modules such as mv-portals..."
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: agreements
|
||||
attributes:
|
||||
label: Agreements
|
||||
description: Ensure you have done the following being submitting this issue.
|
||||
options:
|
||||
- label: I have searched for and ensured there isn't already an open issue regarding this.
|
||||
required: true
|
||||
@@ -1,34 +0,0 @@
|
||||
name: 'Call: GitHub Release'
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
release_mode:
|
||||
description: 'Release mode'
|
||||
required: true
|
||||
type: string
|
||||
version_bump:
|
||||
description: 'Version bump'
|
||||
required: false
|
||||
type: string
|
||||
promote_from:
|
||||
description: 'Promote from'
|
||||
required: false
|
||||
type: string
|
||||
outputs:
|
||||
release_created:
|
||||
description: 'Release created'
|
||||
value: ${{ jobs.github_release.outputs.release_created }}
|
||||
tag_name:
|
||||
description: 'Tag name'
|
||||
value: ${{ jobs.github_release.outputs.tag_name }}
|
||||
|
||||
jobs:
|
||||
github_release:
|
||||
uses: ./.github/workflows/generic.github_release.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
plugin_name: multiverse-core
|
||||
release_mode: ${{ inputs.release_mode }}
|
||||
version_bump: ${{ inputs.version_bump }}
|
||||
promote_from: ${{ inputs.promote_from }}
|
||||
@@ -1,83 +0,0 @@
|
||||
name: 'Call: Platform Uploads'
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
target_tag:
|
||||
description: 'Version to upload'
|
||||
required: true
|
||||
type: string
|
||||
upload_modrinth:
|
||||
description: 'Upload to modrinth.com'
|
||||
required: true
|
||||
type: string
|
||||
upload_dbo:
|
||||
description: 'Upload to dev.bukkit.org'
|
||||
required: true
|
||||
type: string
|
||||
upload_hangar:
|
||||
description: 'Upload to hangar.papermc.io'
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
MODRINTH_TOKEN:
|
||||
required: true
|
||||
DBO_UPLOAD_API_TOKEN:
|
||||
required: true
|
||||
HANGAR_UPLOAD_TOKEN:
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
platform_uploads:
|
||||
uses: ./.github/workflows/generic.platform_uploads.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
plugin_name: multiverse-core
|
||||
modrinth_project_id: 3wmN97b8
|
||||
modrinth_dependencies: >
|
||||
[
|
||||
{"project_id": "qvdtDX3s", "dependency_type": "optional"},
|
||||
{"project_id": "8VMk6P0I", "dependency_type": "optional"},
|
||||
{"project_id": "vtawPsTo", "dependency_type": "optional"},
|
||||
{"project_id": "WuErDeI1", "dependency_type": "optional"}
|
||||
]
|
||||
|
||||
dbo_project_id: 30765
|
||||
dbo_project_relations: >
|
||||
[
|
||||
{"slug": "multiverse-inventories", "type": "optionalDependency"},
|
||||
{"slug": "multiverse-portals", "type": "optionalDependency"},
|
||||
{"slug": "multiverse-netherportals", "type": "optionalDependency"},
|
||||
{"slug": "multiverse-signportals", "type": "optionalDependency"},
|
||||
{"slug": "vault", "type": "optionalDependency"}
|
||||
]
|
||||
|
||||
hangar_slug: Multiverse-Core
|
||||
hangar_plugin_dependencies: >
|
||||
{ "PAPER": [
|
||||
{
|
||||
"name": "Multiverse-Inventories",
|
||||
"required": false,
|
||||
"platforms": ["PAPER"]
|
||||
},
|
||||
{
|
||||
"name": "Multiverse-Portals",
|
||||
"required": false,
|
||||
"platforms": ["PAPER"]
|
||||
},
|
||||
{
|
||||
"name": "Multiverse-NetherPortals",
|
||||
"required": false,
|
||||
"platforms": ["PAPER"]
|
||||
},
|
||||
{
|
||||
"name": "Multiverse-SignPortals",
|
||||
"required": false,
|
||||
"platforms": ["PAPER"]
|
||||
}
|
||||
]}
|
||||
|
||||
target_tag: ${{ inputs.target_tag }}
|
||||
upload_modrinth: ${{ inputs.upload_modrinth }}
|
||||
upload_dbo: ${{ inputs.upload_dbo }}
|
||||
upload_hangar: ${{ inputs.upload_hangar }}
|
||||
@@ -1,39 +0,0 @@
|
||||
name: 'Dispatch: Create Release'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_type:
|
||||
description: 'Stable or pre-release'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- prerelease
|
||||
- release
|
||||
version_bump:
|
||||
description: 'Version bump type'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- major
|
||||
- minor
|
||||
- patch
|
||||
|
||||
jobs:
|
||||
github_release:
|
||||
uses: ./.github/workflows/call.github_release.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
release_mode: ${{ inputs.release_type }}
|
||||
version_bump: ${{ inputs.version_bump }}
|
||||
|
||||
platform_uploads:
|
||||
needs: github_release
|
||||
if: needs.github_release.outputs.release_created == 'true'
|
||||
uses: ./.github/workflows/call.platform_uploads.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
target_tag: ${{ needs.github_release.outputs.tag_name }}
|
||||
upload_modrinth: 'true'
|
||||
upload_dbo: 'false'
|
||||
upload_hangar: 'false'
|
||||
@@ -1,55 +0,0 @@
|
||||
name: 'Dispatch: Deploy Javadoc'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
target_tag:
|
||||
description: 'Version to generate javadoc'
|
||||
required: true
|
||||
replace_latest:
|
||||
description: 'Replace the latest folder'
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
javadocs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.target_tag }}
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'adopt'
|
||||
cache: gradle
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: build javadoc
|
||||
run: ./gradlew javadoc
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_VERSION: ${{ inputs.target_tag }}
|
||||
|
||||
- name: Copy javadoc to deploy folder
|
||||
run: |
|
||||
mkdir -p build/docs/javadoc-deploy/${{ inputs.target_tag }}
|
||||
cp -r build/docs/javadoc/* build/docs/javadoc-deploy/${{ inputs.target_tag }}
|
||||
|
||||
- name: Copy javadoc to latest folder
|
||||
if: inputs.replace_latest
|
||||
run: |
|
||||
mkdir -p build/docs/javadoc-deploy/latest
|
||||
cp -r build/docs/javadoc/* build/docs/javadoc-deploy/latest
|
||||
|
||||
- name: Deploy javadoc to gh pages
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
folder: build/docs/javadoc-deploy
|
||||
branch: javadoc
|
||||
target-folder: javadoc
|
||||
clean: false
|
||||
commit-message: Deploy javadoc for ${{ inputs.target_tag }}
|
||||
@@ -1,31 +0,0 @@
|
||||
name: 'Dispatch: Platform Uploads'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
target_tag:
|
||||
description: 'Version to upload'
|
||||
required: true
|
||||
type: string
|
||||
upload_modrinth:
|
||||
description: 'Upload to modrinth.com'
|
||||
required: true
|
||||
type: boolean
|
||||
upload_dbo:
|
||||
description: 'Upload to dev.bukkit.org'
|
||||
required: true
|
||||
type: boolean
|
||||
upload_hangar:
|
||||
description: 'Upload to hangar.papermc.io'
|
||||
required: true
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
dispatch_platform_uploads:
|
||||
uses: ./.github/workflows/call.platform_uploads.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
target_tag: ${{ github.event.inputs.target_tag }}
|
||||
upload_modrinth: ${{ github.event.inputs.upload_modrinth }}
|
||||
upload_dbo: ${{ github.event.inputs.upload_dbo }}
|
||||
upload_hangar: ${{ github.event.inputs.upload_hangar }}
|
||||
@@ -1,38 +0,0 @@
|
||||
name: 'Dispatch: Promote Release'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
target_tag:
|
||||
description: 'Version to promote'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
check_version:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Verify input version is prerelease
|
||||
run: |
|
||||
if [[ "${{ github.event.inputs.target_tag }}" != *"pre"* ]]; then
|
||||
echo "Version must be a prerelease"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
github_release:
|
||||
needs: check_version
|
||||
uses: ./.github/workflows/call.github_release.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
release_mode: promote
|
||||
promote_from: ${{ github.event.inputs.target_tag }}
|
||||
|
||||
platform_uploads:
|
||||
needs: github_release
|
||||
if: needs.github_release.outputs.release_created == 'true'
|
||||
uses: ./.github/workflows/call.platform_uploads.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
target_tag: ${{ needs.github_release.outputs.tag_name }}
|
||||
upload_modrinth: 'true'
|
||||
upload_dbo: 'true'
|
||||
upload_hangar: 'true'
|
||||
@@ -1,22 +0,0 @@
|
||||
name: 'Generic: Checkstyle'
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
checkstyle:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- uses: dbelyaev/action-checkstyle@v3
|
||||
continue-on-error: true
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
checkstyle_version: 10.12.2
|
||||
checkstyle_config: ./config/mv_checks.xml
|
||||
level: warning
|
||||
@@ -1,131 +0,0 @@
|
||||
name: 'Generic: GitHub Release'
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
# Plugin specific
|
||||
plugin_name:
|
||||
description: 'Plugin name'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
# Common params
|
||||
release_mode:
|
||||
description: 'Release mode'
|
||||
required: true
|
||||
type: string
|
||||
version_bump:
|
||||
description: 'Version bump'
|
||||
required: false
|
||||
type: string
|
||||
promote_from:
|
||||
description: 'Promote from'
|
||||
required: false
|
||||
type: string
|
||||
outputs:
|
||||
release_created:
|
||||
description: 'Release created'
|
||||
value: ${{ jobs.github_release.outputs.release_created }}
|
||||
tag_name:
|
||||
description: 'Tag name'
|
||||
value: ${{ jobs.github_release.outputs.tag_name }}
|
||||
|
||||
jobs:
|
||||
github_release:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
release_created: ${{ steps.release.outputs.release_created }}
|
||||
tag_name: ${{ steps.release.outputs.tag_name }}
|
||||
steps:
|
||||
- name: Echo inputs
|
||||
run: |
|
||||
echo "release_mode: ${{ inputs.release_mode }}"
|
||||
echo "version_bump: ${{ inputs.version_bump }}"
|
||||
echo "promote_from: ${{ inputs.promote_from }}"
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.promote_from }}
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'adopt'
|
||||
cache: gradle
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Build to test
|
||||
id: test
|
||||
run: ./gradlew clean build -x assemble -x shadowJar
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create release
|
||||
id: release
|
||||
if: steps.test.outcome == 'success'
|
||||
uses: benwoo1110/semantic-release-action@v1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
release_mode: ${{ inputs.release_mode }}
|
||||
version_bump: ${{ inputs.version_bump }}
|
||||
promote_from: ${{ inputs.promote_from }}
|
||||
|
||||
- name: Publish package
|
||||
if: steps.release.outputs.release_created == 'true'
|
||||
run: >
|
||||
./gradlew publish -x test
|
||||
-PmultiverseUsername=${{ secrets.REPOSILITE_REPO_USERNAME }}
|
||||
-PmultiversePassword=${{ secrets.REPOSILITE_REPO_PASSWORD }}
|
||||
env:
|
||||
GITHUB_VERSION: ${{ steps.release.outputs.publish_version }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build for upload
|
||||
id: build
|
||||
if: steps.release.outputs.release_created == 'true'
|
||||
run: ./gradlew build -x test
|
||||
env:
|
||||
GITHUB_VERSION: ${{ steps.release.outputs.tag_name }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload release artifact
|
||||
if: steps.build.outcome == 'success'
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: build/libs/${{ inputs.plugin_name }}-${{ steps.release.outputs.tag_name }}.jar
|
||||
asset_name: ${{ inputs.plugin_name }}-${{ steps.release.outputs.tag_name }}.jar
|
||||
tag: ${{ steps.release.outputs.tag_name }}
|
||||
|
||||
- name: Generate javadoc
|
||||
id: javadoc
|
||||
if: steps.build.outcome == 'success'
|
||||
run: ./gradlew javadoc -x test
|
||||
env:
|
||||
GITHUB_VERSION: ${{ steps.release.outputs.publish_version }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload javadoc
|
||||
if: steps.javadoc.outcome == 'success'
|
||||
run: |
|
||||
mkdir -p build/docs/javadoc-deploy/${{ steps.release.outputs.publish_version }}
|
||||
cp -r build/docs/javadoc/* build/docs/javadoc-deploy/${{ steps.release.outputs.publish_version }}
|
||||
|
||||
- name: Override latest javadoc for stable release
|
||||
if: steps.javadoc.outcome == 'success' && steps.release.outputs.release_type == 'release'
|
||||
run: |
|
||||
mkdir -p build/docs/javadoc-deploy/latest
|
||||
cp -r build/docs/javadoc/* build/docs/javadoc-deploy/latest
|
||||
|
||||
- name: Deploy javadoc to gh pages
|
||||
if: steps.javadoc.outcome == 'success'
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
folder: build/docs/javadoc-deploy
|
||||
branch: javadoc
|
||||
target-folder: javadoc
|
||||
clean: false
|
||||
commit-message: Deploy javadoc for ${{ steps.release.outputs.tag_name }}
|
||||
@@ -1,140 +0,0 @@
|
||||
name: 'Generic: Platform Uploads'
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
# Plugin specific params
|
||||
plugin_name:
|
||||
description: 'Plugin name'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
modrinth_project_id:
|
||||
description: 'modrinth.com project ID'
|
||||
required: true
|
||||
type: string
|
||||
modrinth_dependencies:
|
||||
description: 'modrinth.com project dependencies'
|
||||
required: false
|
||||
type: string
|
||||
default: '[]'
|
||||
|
||||
dbo_project_id:
|
||||
description: 'dev.bukkit.org project ID'
|
||||
required: true
|
||||
type: string
|
||||
dbo_project_relations:
|
||||
description: 'dev.bukkit.org project relations'
|
||||
required: false
|
||||
type: string
|
||||
default: '[]'
|
||||
|
||||
hangar_slug:
|
||||
description: 'hangar.papermc.io project slug'
|
||||
required: true
|
||||
type: string
|
||||
hangar_plugin_dependencies:
|
||||
description: 'hangar.papermc.io project dependencies'
|
||||
required: false
|
||||
type: string
|
||||
default: '{}'
|
||||
|
||||
# Common params
|
||||
target_tag:
|
||||
description: 'Version to upload'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
upload_modrinth:
|
||||
description: 'Upload to modrinth.com'
|
||||
required: true
|
||||
type: string
|
||||
upload_dbo:
|
||||
description: 'Upload to dev.bukkit.org'
|
||||
required: true
|
||||
type: string
|
||||
upload_hangar:
|
||||
description: 'Upload to hangar.papermc.io'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
secrets:
|
||||
MODRINTH_TOKEN:
|
||||
required: true
|
||||
DBO_UPLOAD_API_TOKEN:
|
||||
required: true
|
||||
HANGAR_UPLOAD_TOKEN:
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
platform_uploads:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get release info
|
||||
id: release-info
|
||||
uses: cardinalby/git-get-release-action@1.2.4
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag: ${{ inputs.target_tag }}
|
||||
|
||||
- name: Download release artifact
|
||||
id: release-artifact
|
||||
uses: dsaltares/fetch-gh-release-asset@1.1.1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
version: tags/${{ steps.release-info.outputs.tag_name }}
|
||||
file: ${{ inputs.plugin_name }}-${{ steps.release-info.outputs.tag_name }}.jar
|
||||
|
||||
- name: Parse release type
|
||||
id: parse-release-type
|
||||
run: |
|
||||
if [[ "${{ steps.release-info.outputs.prerelease }}" == "true" ]]; then
|
||||
echo Setting release_type to Beta
|
||||
echo "release_type=Beta" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo Setting release_type to Release
|
||||
echo "release_type=Release" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Upload to Modrinth
|
||||
if: ${{ !cancelled() && inputs.upload_modrinth == 'true' }}
|
||||
uses: benwoo1110/modrinth-upload-action@v1
|
||||
with:
|
||||
api_token: ${{ secrets.MODRINTH_TOKEN }}
|
||||
project_id: ${{ inputs.modrinth_project_id }}
|
||||
version_number: ${{ steps.release-info.outputs.tag_name }}
|
||||
files: '["${{ github.workspace }}/${{ inputs.plugin_name }}-${{ steps.release-info.outputs.tag_name }}.jar"]'
|
||||
name: ${{ steps.release-info.outputs.tag_name }}
|
||||
changelog: ${{ steps.release-artifact.outputs.body }}
|
||||
game_versions: 1.21.11, 1.21.10, 1.21.9, 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21, 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2
|
||||
version_type: ${{ steps.parse-release-type.outputs.release_type }}
|
||||
loaders: bukkit, spigot, paper, purpur
|
||||
dependencies: ${{ inputs.modrinth_dependencies }}
|
||||
|
||||
- name: Upload to DBO
|
||||
if: ${{ !cancelled() && inputs.upload_dbo == 'true' }}
|
||||
uses: benwoo1110/dbo-upload-action@v1
|
||||
with:
|
||||
api_token: ${{ secrets.DBO_UPLOAD_API_TOKEN }}
|
||||
project_id: ${{ inputs.dbo_project_id }}
|
||||
changelog: ${{ steps.release-artifact.outputs.body }}
|
||||
changelog_type: markdown
|
||||
display_name: ${{ steps.release-info.outputs.tag_name }}
|
||||
game_versions: 1.21.11, 1.21.10, 1.21.9, 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21, 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2
|
||||
release_type: ${{ steps.parse-release-type.outputs.release_type }}
|
||||
project_relations: ${{ inputs.dbo_project_relations }}
|
||||
file_path: ${{ github.workspace }}/${{ inputs.plugin_name }}-${{ steps.release-info.outputs.tag_name }}.jar
|
||||
|
||||
- name: Upload to Hangar
|
||||
if: ${{ !cancelled() && inputs.upload_hangar == 'true' }}
|
||||
uses: benwoo1110/hangar-upload-action@v1
|
||||
with:
|
||||
api_token: ${{ secrets.HANGAR_UPLOAD_TOKEN }}
|
||||
slug: ${{ inputs.hangar_slug }}
|
||||
version: ${{ steps.release-info.outputs.tag_name }}
|
||||
channel: ${{ steps.parse-release-type.outputs.release_type }}
|
||||
files: '[{"path": "${{ github.workspace }}/${{ inputs.plugin_name }}-${{ steps.release-info.outputs.tag_name }}.jar", "platforms": ["PAPER"]}]'
|
||||
description: ${{ steps.release-artifact.outputs.body }}
|
||||
platform_dependencies: '{"PAPER": ["1.18.2-1.21.11"]}'
|
||||
plugin_dependencies: ${{ inputs.hangar_plugin_dependencies }}
|
||||
@@ -1,48 +0,0 @@
|
||||
name: 'Generic: Test'
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
plugin_name:
|
||||
description: 'Plugin name'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
test-and-artifact:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'adopt'
|
||||
cache: gradle
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Run unit tests
|
||||
run: ./gradlew build
|
||||
env:
|
||||
GITHUB_VERSION: pr${{ github.event.pull_request.number }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Artifact output
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ inputs.plugin_name }}-pr${{ github.event.pull_request.number }}
|
||||
path: build/libs/${{ inputs.plugin_name }}-pr${{ github.event.pull_request.number }}.jar
|
||||
|
||||
comment-artifact:
|
||||
needs: test-and-artifact
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: benwoo1110/artifact-comment-action@v1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -1,24 +0,0 @@
|
||||
name: 'Main: Prerelease'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
github_release_on_push:
|
||||
uses: ./.github/workflows/call.github_release.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
release_mode: prerelease
|
||||
version_bump: prlabel
|
||||
|
||||
platform_uploads_on_push:
|
||||
needs: github_release_on_push
|
||||
if: needs.github_release_on_push.outputs.release_created == 'true'
|
||||
uses: ./.github/workflows/call.platform_uploads.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
target_tag: ${{ needs.github_release_on_push.outputs.tag_name }}
|
||||
upload_modrinth: 'true'
|
||||
upload_dbo: 'false'
|
||||
upload_hangar: 'false'
|
||||
@@ -1,9 +0,0 @@
|
||||
name: 'PR: Checkstyle'
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
|
||||
jobs:
|
||||
checkstyle:
|
||||
uses: ./.github/workflows/generic.checkstyle.yml
|
||||
@@ -1,18 +0,0 @@
|
||||
name: 'PR: Require Label'
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, labeled, unlabeled, synchronize]
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
require_label:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: mheap/github-action-required-labels@v2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
mode: exactly
|
||||
count: 1
|
||||
labels: "release:major, release:minor, release:patch, no release"
|
||||
@@ -1,11 +0,0 @@
|
||||
name: 'PR: Test'
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
uses: ./.github/workflows/generic.test.yml
|
||||
with:
|
||||
plugin_name: multiverse-core
|
||||
@@ -1,48 +0,0 @@
|
||||
# Eclipse stuff
|
||||
/.classpath
|
||||
/.project
|
||||
/.settings
|
||||
/.checkstyle
|
||||
|
||||
# netbeans
|
||||
/nbproject
|
||||
|
||||
# we use maven!
|
||||
/build.xml
|
||||
|
||||
# maven
|
||||
/target
|
||||
dependency-reduced-pom.xml
|
||||
|
||||
# vim
|
||||
.*.sw[a-p]
|
||||
|
||||
# various other potential build files
|
||||
/build
|
||||
/bin
|
||||
/dist
|
||||
/manifest.mf
|
||||
|
||||
/world
|
||||
|
||||
# Mac filesystem dust
|
||||
*.DS_Store
|
||||
|
||||
# intellij
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# Fern's utils
|
||||
uploadtoserver.sh
|
||||
|
||||
# Testing files:
|
||||
debug.log
|
||||
|
||||
# Doxygen
|
||||
/docs/html
|
||||
debug.txt
|
||||
|
||||
# Gradle
|
||||
.gradle
|
||||
@@ -1,4 +0,0 @@
|
||||
kotlin version: 2.0.21
|
||||
error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
|
||||
1. Kotlin compile daemon is ready
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
Copyright (c) 2011, The Multiverse Team All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the The Multiverse Team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
<p align="center">
|
||||
<img src="config/multiverse-banner.png" alt="Multiverse Logo">
|
||||
</p>
|
||||
|
||||
[](https://modrinth.com/plugin/multiverse-core)
|
||||
[](https://hangar.papermc.io/Multiverse/Multiverse-Core)
|
||||
[](https://dev.bukkit.org/projects/multiverse-core)
|
||||
[](https://www.spigotmc.org/resources/multiverse-core.390/)
|
||||
|
||||
[](https://github.com/Multiverse/Multiverse-Core/releases/latest)
|
||||
[](https://github.com/Multiverse/Multiverse-Core/releases)
|
||||
[](https://discord.gg/NZtfKky)
|
||||
[](https://github.com/sponsors/Multiverse)
|
||||
[](https://opencollective.com/multiverse-plugins)
|
||||
|
||||
# About
|
||||
|
||||
[Multiverse](https://modrinth.com/plugin/multiverse-core) was created at the dawn of Bukkit multiworld support. It has since then grown into a **complete world management solution!** Multiverse provides the easiest to use world management solution for your Minecraft server, big or small, and with great addons like [Portals](https://dev.bukkit.org/projects/multiverse-portals) and [NetherPortals](https://dev.bukkit.org/projects/multiverse-netherportals/), what's not to love!
|
||||
|
||||
Now it's time to create your very own Multiverse server, do check out our [Wiki](https://github.com/Multiverse/Multiverse-Core/wiki) and [Usage Guide](https://github.com/Multiverse/Multiverse-Core/wiki/Basics) to get started. Feel free to hop onto our [Discord](https://discord.gg/NZtfKky) if you have any question or just want to have a chat with us!
|
||||
|
||||
## Amazing sub-modules available:
|
||||
|
||||
* [Multiverse-NetherPortals](https://github.com/Multiverse/Multiverse-NetherPortals) -> Have separate nether and end worlds for each of your overworlds!
|
||||
* [Multiverse-Portals](https://github.com/Multiverse/Multiverse-Portals) -> Make custom portals to go to any destination!
|
||||
* [Multiverse-Inventories](https://github.com/Multiverse/Multiverse-Inventories) -> Have separated players stats and inventories per world or per group of worlds.
|
||||
* [Multiverse-SignPortals](https://github.com/Multiverse/Multiverse-SignPortals) -> Signs as teleporters!
|
||||
|
||||
## Usage Guide
|
||||
|
||||
We have a cool new website hosting our Wiki: https://mvplugins.org
|
||||
|
||||
## Building
|
||||
Simply build the source with Gradle:
|
||||
```
|
||||
./gradlew build
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
**Want to help improve Multiverse?** There are several ways you can support and contribute to the project.
|
||||
* Take a look at our "Bug: Unconfirmed" issues, where you can find issues that need extra testing and investigation.
|
||||
* Want others to love Multiverse too? You can join the [Multiverse Discord community](https://discord.gg/NZtfKky) and help others with issues and setup!
|
||||
* A Multiverse guru? You can update our [Wiki](https://github.com/Multiverse/multiverse-web) with your latest tip, tricks and guides! The wiki open for all to edit and improve.
|
||||
* Love coding? You could look at ["State: Open to PR"](https://github.com/Multiverse/Multiverse-Core/labels/State%3A%20Open%20to%20PR) and ["Resolution: Accepted"](https://github.com/Multiverse/Multiverse-Core/labels/Resolution%3A%20Accepted) issues. We're always happy to receive bug fixes and feature additions as [pull requests](https://www.freecodecamp.org/news/how-to-make-your-first-pull-request-on-github-3/).
|
||||
* If you'd like to make a financial contribution to the project, do consider donating to our [Github Sponsors](https://github.com/sponsors/Multiverse) or [Open Collective](https://opencollective.com/multiverse-plugins)!
|
||||
|
||||
Additionally, we would like to give a big thanks to everyone that has supported Multiverse over the years, as well as those in the years to come. Thank you!
|
||||
|
||||
## License
|
||||
Multiverse-Core is licensed under BSD-3-Clause License. Please see [LICENSE.md](LICENSE.md) for more info.
|
||||
@@ -1,364 +0,0 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import groovy.util.Node
|
||||
import groovy.util.NodeList
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.credentials.PasswordCredentials
|
||||
import org.gradle.api.publish.maven.MavenPublication
|
||||
import org.gradle.api.tasks.SourceSetContainer
|
||||
import org.gradle.api.tasks.Sync
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
import org.gradle.api.tasks.javadoc.Javadoc
|
||||
import org.gradle.api.tasks.testing.Test
|
||||
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
|
||||
import org.gradle.external.javadoc.StandardJavadocDocletOptions
|
||||
import org.gradle.jvm.tasks.Jar
|
||||
import org.gradle.language.jvm.tasks.ProcessResources
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
eclipse
|
||||
`maven-publish`
|
||||
id("com.gradleup.shadow") version "8.3.9"
|
||||
kotlin("jvm") version "2.0.21"
|
||||
}
|
||||
|
||||
group = "org.mvplugins.multiverse.core"
|
||||
version = System.getenv("GITHUB_VERSION") ?: "5.3.4.17"
|
||||
description = "Multiverse-Core"
|
||||
|
||||
val sourceSets = extensions.getByType<SourceSetContainer>()
|
||||
|
||||
val serverApi: Configuration by configurations.creating
|
||||
val externalPlugin: Configuration by configurations.creating
|
||||
val shadowed: Configuration by configurations.creating
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
|
||||
maven {
|
||||
url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
|
||||
}
|
||||
|
||||
maven {
|
||||
url = uri("https://repo.onarandombox.com/content/groups/public")
|
||||
}
|
||||
|
||||
maven {
|
||||
url = uri("https://hub.spigotmc.org/nexus/content/groups/public/")
|
||||
}
|
||||
|
||||
maven {
|
||||
url = uri("https://jitpack.io")
|
||||
}
|
||||
|
||||
maven {
|
||||
url = uri("https://repo.minebench.de/")
|
||||
}
|
||||
|
||||
maven {
|
||||
url = uri("https://repo.maven.apache.org/maven2/")
|
||||
}
|
||||
|
||||
maven {
|
||||
name = "aikar repo"
|
||||
url = uri("https://repo.aikar.co/content/groups/aikar/")
|
||||
}
|
||||
|
||||
maven {
|
||||
name = "glaremasters repo"
|
||||
url = uri("https://repo.glaremasters.me/repository/towny/")
|
||||
}
|
||||
|
||||
maven {
|
||||
name = "helpchatRepoReleases"
|
||||
url = uri("https://repo.helpch.at/releases/")
|
||||
}
|
||||
|
||||
maven {
|
||||
name = "papermc repo"
|
||||
url = uri("https://repo.papermc.io/repository/maven-public/")
|
||||
}
|
||||
|
||||
// Purpur API
|
||||
maven("https://repo.purpurmc.org/snapshots")
|
||||
}
|
||||
|
||||
// Configuration wiring like in the Groovy build
|
||||
configurations["compileOnly"].extendsFrom(serverApi)
|
||||
configurations["runtimeClasspath"].extendsFrom(serverApi)
|
||||
|
||||
configurations["implementation"].extendsFrom(externalPlugin)
|
||||
|
||||
configurations["compileClasspath"].extendsFrom(shadowed)
|
||||
configurations["testCompileClasspath"].extendsFrom(shadowed)
|
||||
configurations["testRuntimeClasspath"].extendsFrom(shadowed)
|
||||
|
||||
dependencies {
|
||||
// Server API: Purpur 1.19.4
|
||||
serverApi("org.purpurmc.purpur:purpur-api:1.19.4-R0.1-SNAPSHOT")
|
||||
|
||||
// Economy
|
||||
externalPlugin("com.github.MilkBowl:VaultAPI:1.7.1") {
|
||||
exclude(group = "org.bukkit", module = "bukkit")
|
||||
}
|
||||
|
||||
// PlaceholderAPI
|
||||
externalPlugin("me.clip:placeholderapi:2.11.6")
|
||||
|
||||
// Command Framework
|
||||
shadowed("co.aikar:acf-paper:0.5.1-SNAPSHOT")
|
||||
|
||||
// Config
|
||||
shadowed("io.github.townyadvanced.commentedconfiguration:CommentedConfiguration:1.0.1") {
|
||||
exclude(group = "org.spigotmc", module = "spigot-api")
|
||||
}
|
||||
|
||||
// Utils
|
||||
shadowed("io.vavr:vavr:0.10.4")
|
||||
shadowed("org.glassfish.hk2:hk2-locator:3.0.3")
|
||||
shadowed("org.glassfish.hk2:hk2-inhabitant-generator:3.0.3") {
|
||||
exclude(group = "org.apache.maven", module = "maven-core")
|
||||
}
|
||||
shadowed("com.dumptruckman.minecraft:Logging:1.1.1") {
|
||||
exclude(group = "junit", module = "junit")
|
||||
}
|
||||
shadowed("de.themoep.idconverter:mappings:1.2-SNAPSHOT")
|
||||
shadowed("org.bstats:bstats-bukkit:3.1.0") {
|
||||
exclude(group = "org.bukkit", module = "bukkit")
|
||||
}
|
||||
shadowed("net.minidev:json-smart:2.4.9")
|
||||
shadowed("org.jetbrains:annotations:22.0.0")
|
||||
shadowed("io.papermc:paperlib:1.0.8")
|
||||
|
||||
// Tests
|
||||
testImplementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21")
|
||||
testImplementation("com.github.seeseemelk:MockBukkit-v1.19:3.1.0")
|
||||
testImplementation("com.googlecode.json-simple:json-simple:1.1.1") {
|
||||
exclude(group = "junit", module = "junit")
|
||||
}
|
||||
testImplementation("org.jetbrains.kotlin:kotlin-test")
|
||||
testImplementation("com.natpryce:hamkrest:1.8.0.1")
|
||||
testImplementation("org.mockito.kotlin:mockito-kotlin:4.1.0")
|
||||
|
||||
// Annotation Processors
|
||||
annotationProcessor("org.glassfish.hk2:hk2-metadata-generator:3.0.3")
|
||||
testAnnotationProcessor("org.glassfish.hk2:hk2-metadata-generator:3.0.3")
|
||||
}
|
||||
|
||||
java {
|
||||
// Plugin is compiled for Java 17 (GraalVM 17-friendly)
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
val bitlyAccessToken: String = System.getenv("BITLY_ACCESS_TOKEN") ?: "bitly-access-token"
|
||||
|
||||
// === Token-filtered source generation (prepareSource) ===
|
||||
val prepareSource by tasks.registering(Sync::class) {
|
||||
inputs.property("bitlyAccessToken", bitlyAccessToken)
|
||||
from(sourceSets["main"].java)
|
||||
// avoid deprecated buildDir getter
|
||||
into(layout.buildDirectory.dir("src"))
|
||||
filter<ReplaceTokens>(
|
||||
"tokens" to mapOf(
|
||||
"bitly-access-token" to bitlyAccessToken,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// Use ONLY the filtered sources for compileJava (fixes duplicate classes)
|
||||
tasks.named<JavaCompile>("compileJava") {
|
||||
dependsOn(prepareSource)
|
||||
source = prepareSource.get().outputs.files.asFileTree
|
||||
sourceCompatibility = JavaVersion.VERSION_17.toString()
|
||||
targetCompatibility = JavaVersion.VERSION_17.toString()
|
||||
}
|
||||
|
||||
tasks.named<JavaCompile>("compileTestJava") {
|
||||
sourceCompatibility = JavaVersion.VERSION_17.toString()
|
||||
targetCompatibility = JavaVersion.VERSION_17.toString()
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
options.encoding = "UTF-8"
|
||||
options.compilerArgs.add(
|
||||
"-Aorg.glassfish.hk2.metadata.location=META-INF/hk2-locator/Multiverse-Core",
|
||||
)
|
||||
}
|
||||
|
||||
tasks.withType<Javadoc>().configureEach {
|
||||
(options as StandardJavadocDocletOptions).encoding = "UTF-8"
|
||||
}
|
||||
|
||||
tasks.named<KotlinCompile>("compileTestKotlin") {
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_17)
|
||||
javaParameters.set(true)
|
||||
}
|
||||
}
|
||||
|
||||
// We're not using Kotlin in the plugin itself, just tests!
|
||||
tasks.named<KotlinCompile>("compileKotlin") {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
configurations
|
||||
.filterNot { it.name.startsWith("test") }
|
||||
.forEach {
|
||||
it.exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib-jdk8")
|
||||
}
|
||||
|
||||
tasks.named<ProcessResources>("processResources") {
|
||||
val props = mapOf("version" to project.version.toString())
|
||||
inputs.properties(props)
|
||||
filteringCharset = "UTF-8"
|
||||
filesMatching("plugin.yml") {
|
||||
expand(props)
|
||||
}
|
||||
// Never up-to-date: tests depend on fresh version expansion
|
||||
outputs.upToDateWhen { false }
|
||||
}
|
||||
|
||||
tasks.named<Javadoc>("javadoc") {
|
||||
source = sourceSets["main"].allJava
|
||||
classpath = configurations["compileClasspath"]
|
||||
}
|
||||
|
||||
// Removed: configurations["api"].isCanBeResolved = true (deprecated in Gradle 8/9)
|
||||
|
||||
val jarTask = tasks.named<Jar>("jar")
|
||||
val shadowJarTask = tasks.named<ShadowJar>("shadowJar")
|
||||
|
||||
listOf("apiElements", "runtimeElements").forEach { configurationName ->
|
||||
configurations.named(configurationName) {
|
||||
outgoing.artifacts.removeIf { artifact ->
|
||||
artifact.buildDependencies.getDependencies(null).contains(jarTask.get())
|
||||
}
|
||||
outgoing.artifact(shadowJarTask)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named<ShadowJar>("shadowJar") {
|
||||
relocate("co.aikar", "org.mvplugins.multiverse.external.acf")
|
||||
relocate("com.dumptruckman.minecraft.util.Logging", "org.mvplugins.multiverse.core.utils.CoreLogging")
|
||||
relocate("com.dumptruckman.minecraft.util.DebugLog", "org.mvplugins.multiverse.core.utils.DebugFileLogger")
|
||||
relocate("de.themoep.idconverter", "org.mvplugins.multiverse.external.idconverter")
|
||||
relocate("io.github.townyadvanced.commentedconfiguration", "org.mvplugins.multiverse.external.commentedconfiguration")
|
||||
relocate("me.main__.util", "org.mvplugins.multiverse.external.serializationconfig")
|
||||
relocate("org.bstats", "org.mvplugins.multiverse.external.bstats")
|
||||
relocate("com.sun", "org.mvplugins.multiverse.external.sun")
|
||||
relocate("net.minidev", "org.mvplugins.multiverse.external.minidev")
|
||||
relocate("org.objectweb", "org.mvplugins.multiverse.external.objectweb")
|
||||
relocate("io.vavr", "org.mvplugins.multiverse.external.vavr")
|
||||
relocate("jakarta", "org.mvplugins.multiverse.external.jakarta")
|
||||
relocate("javassist", "org.mvplugins.multiverse.external.javassist")
|
||||
relocate("org.aopalliance", "org.mvplugins.multiverse.external.aopalliance")
|
||||
relocate("org.glassfish", "org.mvplugins.multiverse.external.glassfish")
|
||||
relocate("org.jvnet", "org.mvplugins.multiverse.external.jvnet")
|
||||
relocate("org.intellij", "org.mvplugins.multiverse.external.intellij")
|
||||
relocate("org.jetbrains", "org.mvplugins.multiverse.external.jetbrains")
|
||||
relocate("io.papermc.lib", "org.mvplugins.multiverse.external.paperlib")
|
||||
|
||||
configurations = listOf(project.configurations["shadowed"])
|
||||
|
||||
archiveClassifier.set("")
|
||||
|
||||
dependencies {
|
||||
exclude { dependency ->
|
||||
dependency.moduleGroup == "org.jetbrains.kotlin"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named("build") {
|
||||
dependsOn("shadowJar")
|
||||
}
|
||||
|
||||
tasks.named<Jar>("jar") {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
tasks.named<Test>("test") {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
exceptionFormat = TestExceptionFormat.FULL
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
from(components["java"])
|
||||
|
||||
pom.withXml {
|
||||
val pomNode = asNode()
|
||||
|
||||
val dependenciesNode = (
|
||||
(pomNode.get("dependencies") as? NodeList)
|
||||
?.firstOrNull() as? Node
|
||||
) ?: (pomNode.appendNode("dependencies") as Node)
|
||||
|
||||
val dependencyNodes = dependenciesNode.children().filterIsInstance<Node>().toList()
|
||||
|
||||
// Remove Kotlin dependency
|
||||
dependencyNodes
|
||||
.filter { dependencyNode ->
|
||||
val groupIdNodes = dependencyNode.get("groupId") as? NodeList ?: return@filter false
|
||||
val groupId = (groupIdNodes.firstOrNull() as? Node)?.text()
|
||||
groupId == "org.jetbrains.kotlin"
|
||||
}
|
||||
.forEach { dependencyNode ->
|
||||
dependenciesNode.remove(dependencyNode)
|
||||
}
|
||||
|
||||
// Switch runtime deps to provided
|
||||
dependencyNodes.forEach { dependencyNode ->
|
||||
val scopeNodes = dependencyNode.get("scope") as? NodeList ?: return@forEach
|
||||
val scopeNode = scopeNodes.firstOrNull() as? Node ?: return@forEach
|
||||
if (scopeNode.text() == "runtime") {
|
||||
scopeNode.setValue("provided")
|
||||
}
|
||||
}
|
||||
|
||||
// Add server API (Purpur) to pom as provided
|
||||
configurations["serverApi"].allDependencies.forEach { dependency ->
|
||||
val depNode = dependenciesNode.appendNode("dependency")
|
||||
depNode.appendNode("groupId", dependency.group)
|
||||
depNode.appendNode("artifactId", dependency.name)
|
||||
depNode.appendNode("version", dependency.version)
|
||||
depNode.appendNode("scope", "provided")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
name = "GitHubPackages"
|
||||
url = uri("https://maven.pkg.github.com/Multiverse/Multiverse-Core")
|
||||
credentials {
|
||||
username = System.getenv("GITHUB_ACTOR")
|
||||
password = System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
maven {
|
||||
name = "multiverse"
|
||||
val releasesRepoUrl = uri("https://repo.dumptruckman.com/multiverse-releases")
|
||||
val snapshotsRepoUrl = uri("https://repo.dumptruckman.com/multiverse-snapshots")
|
||||
url = if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl
|
||||
credentials(PasswordCredentials::class)
|
||||
}
|
||||
|
||||
maven {
|
||||
// todo: remove before mv5 release
|
||||
name = "multiverseBeta"
|
||||
url = uri("https://repo.c0ding.party/multiverse-beta")
|
||||
credentials(PasswordCredentials::class)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
out.txt
|
||||
@@ -1,20 +0,0 @@
|
||||
filepath = "../src/main/resources/multiverse-core_en.properties"
|
||||
|
||||
enumList = []
|
||||
|
||||
with open(filepath) as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if len(line) == 0:
|
||||
enumList.append("")
|
||||
elif line.startswith("#"):
|
||||
enumList.append(line.replace("#", "//"))
|
||||
else:
|
||||
parts = line.split("=")
|
||||
if (len(parts) < 2):
|
||||
continue
|
||||
parts = parts[0].split(".")[1:]
|
||||
enumList.append("_".join([p.upper() for p in parts]) + ",")
|
||||
|
||||
with open("out.txt", "w") as f:
|
||||
f.write("\n".join(enumList))
|
||||
|
Before Width: | Height: | Size: 166 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 23 KiB |
@@ -1,665 +0,0 @@
|
||||
<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~ Multiverse 2 Copyright (c) the Multiverse Team 2011. ~
|
||||
~ Multiverse 2 is licensed under the BSD License. ~
|
||||
~ For more information please check the README.md file included ~
|
||||
~ with this project. ~
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
|
||||
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
|
||||
"https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||
<!-- Future reference: valid severity values are 'ignore', 'info', 'warning', 'error' -->
|
||||
<module name="Checker">
|
||||
<property name="charset" value="UTF-8"/>
|
||||
<property name="fileExtensions" value="java, properties, xml"/>
|
||||
<property name="severity" value="warning"/>
|
||||
|
||||
<!-- Javadoc Comments -->
|
||||
<module name="JavadocPackage"/><!-- require package-info.java file -->
|
||||
|
||||
<!-- Miscellaneous -->
|
||||
<module name="NewlineAtEndOfFile" />
|
||||
<module name="OrderedProperties"/>
|
||||
<module name="Translation"/>
|
||||
<module name="UniqueProperties"/>
|
||||
|
||||
<!-- Regexp -->
|
||||
<module name="RegexpSingleline">
|
||||
<property name="message" value="Line has trailing spaces."/>
|
||||
<property name="format" value="\s+$"/>
|
||||
</module>
|
||||
|
||||
<!-- Size Violations -->
|
||||
<module name="FileLength">
|
||||
<property name="max" value="2000"/>
|
||||
</module>
|
||||
<module name="LineLength">
|
||||
<property name="fileExtensions" value="java"/>
|
||||
<property name="max" value="120"/>
|
||||
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
|
||||
</module>
|
||||
|
||||
<!-- Whitespace -->
|
||||
<module name="FileTabCharacter">
|
||||
<property name="eachLine" value="true"/>
|
||||
</module>
|
||||
|
||||
<module name="TreeWalker">
|
||||
<!-- Make suppression possible -->
|
||||
<module name="SuppressWithNearbyCommentFilter">
|
||||
<property name="commentFormat" value="SUPPRESS CHECKSTYLE: (\w+)"/>
|
||||
<property name="checkFormat" value="$1"/>
|
||||
</module>
|
||||
<module name="SuppressionCommentFilter">
|
||||
<property name="offCommentFormat" value="BEGIN CHECKSTYLE-SUPPRESSION\: (\w+)"/>
|
||||
<property name="onCommentFormat" value="END CHECKSTYLE-SUPPRESSION\: (\w+)"/>
|
||||
<property name="checkFormat" value="$1"/>
|
||||
</module>
|
||||
<module name="SuppressionCommentFilter">
|
||||
<property name="offCommentFormat" value="BEGIN CHECKSTYLE-SUPPRESSION\: ALL"/>
|
||||
<property name="onCommentFormat" value="END CHECKSTYLE-SUPPRESSION\: ALL"/>
|
||||
</module>
|
||||
|
||||
<!-- Actual checks -->
|
||||
|
||||
<!-- Annotations -->
|
||||
<module name="AnnotationLocation">
|
||||
<property name="id" value="AnnotationLocationMostCases"/>
|
||||
<property name="tokens"
|
||||
value="CLASS_DEF, INTERFACE_DEF, PACKAGE_DEF, ENUM_CONSTANT_DEF,
|
||||
ENUM_DEF, METHOD_DEF, CTOR_DEF, RECORD_DEF, COMPACT_CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="AnnotationLocation">
|
||||
<property name="id" value="AnnotationLocationVariables"/>
|
||||
<property name="tokens" value="VARIABLE_DEF"/>
|
||||
<property name="allowSamelineMultipleAnnotations" value="true"/>
|
||||
</module>
|
||||
<module name="AnnotationLocation"/>
|
||||
<module name="AnnotationUseStyle"/>
|
||||
<module name="MissingDeprecated"/>
|
||||
<module name="MissingOverride"/>
|
||||
|
||||
<!-- Block Checks -->
|
||||
<module name="AvoidNestedBlocks"/>
|
||||
<module name="EmptyBlock">
|
||||
<property name="tokens"
|
||||
value="LITERAL_WHILE, LITERAL_TRY, LITERAL_FINALLY, LITERAL_DO, LITERAL_IF,
|
||||
LITERAL_ELSE, LITERAL_FOR, INSTANCE_INIT, STATIC_INIT, LITERAL_SWITCH,
|
||||
LITERAL_SYNCHRONIZED"/>
|
||||
</module>
|
||||
<module name="EmptyCatchBlock">
|
||||
<property name="exceptionVariableName" value="(ignore|expect)"/>
|
||||
</module>
|
||||
<module name="LeftCurly">
|
||||
<property name="ignoreEnums" value="false"/>
|
||||
<property name="tokens"
|
||||
value="ANNOTATION_DEF, CLASS_DEF, CTOR_DEF, ENUM_CONSTANT_DEF, ENUM_DEF,
|
||||
INTERFACE_DEF, LAMBDA, LITERAL_CASE, LITERAL_CATCH, LITERAL_DEFAULT,
|
||||
LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF,
|
||||
LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, METHOD_DEF,
|
||||
OBJBLOCK, STATIC_INIT, RECORD_DEF, COMPACT_CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="NeedBraces">
|
||||
<property name="id" value="SingleLineIf"/>
|
||||
<property name="tokens" value="LITERAL_IF"/>
|
||||
<property name="allowSingleLineStatement" value="true"/>
|
||||
</module>
|
||||
<module name="NeedBraces">
|
||||
<property name="id" value="NoSingleLineControl"/>
|
||||
<property name="tokens" value="LITERAL_DO, LITERAL_ELSE, LITERAL_FOR, LITERAL_WHILE"/>
|
||||
</module>
|
||||
<module name="RightCurly">
|
||||
<property name="id" value="RightCurlySame"/>
|
||||
<property name="tokens"
|
||||
value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE,
|
||||
LITERAL_DO"/>
|
||||
</module>
|
||||
<module name="RightCurly">
|
||||
<property name="id" value="RightCurlyAlone"/>
|
||||
<property name="option" value="alone"/>
|
||||
<property name="tokens"
|
||||
value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT,
|
||||
INSTANCE_INIT, ANNOTATION_DEF, ENUM_DEF, INTERFACE_DEF, RECORD_DEF,
|
||||
COMPACT_CTOR_DEF, LITERAL_SWITCH"/>
|
||||
</module>
|
||||
|
||||
<!-- Class Design -->
|
||||
<module name="DesignForExtension">
|
||||
<property name="severity" value="info"/>
|
||||
</module>
|
||||
<module name="FinalClass"/>
|
||||
<module name="HideUtilityClassConstructor"/>
|
||||
<module name="InnerTypeLast"/>
|
||||
<module name="InterfaceIsType"/>
|
||||
<module name="MutableException"/>
|
||||
<module name="OneTopLevelClass"/>
|
||||
<module name="ThrowsCount">
|
||||
<property name="max" value="2"/>
|
||||
</module>
|
||||
<module name="VisibilityModifier">
|
||||
<property name="protectedAllowed" value="true"/>
|
||||
</module>
|
||||
|
||||
<!-- Coding -->
|
||||
<module name="ArrayTrailingComma"/>
|
||||
<module name="AvoidDoubleBraceInitialization"/>
|
||||
<module name="AvoidNoArgumentSuperConstructorCall"/>
|
||||
<module name="CovariantEquals"/>
|
||||
<module name="DeclarationOrder">
|
||||
<!-- Doesn't respect static methods at top -->
|
||||
<property name="severity" value="ignore"/>
|
||||
</module>
|
||||
<module name="DefaultComesLast"/>
|
||||
<module name="EmptyStatement"/>
|
||||
<module name="EqualsAvoidNull"/>
|
||||
<module name="EqualsHashCode"/>
|
||||
<module name="FallThrough">
|
||||
<property name="checkLastCaseGroup" value="true"/>
|
||||
</module>
|
||||
<module name="HiddenField">
|
||||
<property name="ignoreConstructorParameter" value="true"/>
|
||||
<property name="ignoreSetter" value="true"/>
|
||||
<property name="setterCanReturnItsClass" value="true"/>
|
||||
<property name="ignoreAbstractMethods" value="true"/>
|
||||
<!-- Not smart enough -->
|
||||
<property name="severity" value="ignore"/>
|
||||
</module>
|
||||
<module name="IllegalCatch"/>
|
||||
<module name="IllegalThrows"/>
|
||||
<module name="IllegalToken"/>
|
||||
<module name="IllegalTokenText">
|
||||
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
|
||||
<property name="format"
|
||||
value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
|
||||
<property name="message"
|
||||
value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
|
||||
</module>
|
||||
<module name="IllegalType"/>
|
||||
<module name="InnerAssignment"/>
|
||||
<module name="MagicNumber">
|
||||
<property name="ignoreHashCodeMethod" value="true"/>
|
||||
<property name="ignoreAnnotationElementDefaults" value="true"/>
|
||||
</module>
|
||||
<module name="MissingSwitchDefault"/>
|
||||
<module name="ModifiedControlVariable"/>
|
||||
<module name="MultipleStringLiterals">
|
||||
|
||||
</module>
|
||||
<module name="MultipleVariableDeclarations"/>
|
||||
<module name="NestedForDepth">
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
<module name="NestedIfDepth"/>
|
||||
<module name="NestedTryDepth"/>
|
||||
<module name="NoClone"/>
|
||||
<module name="NoFinalizer"/>
|
||||
<module name="OneStatementPerLine"/>
|
||||
<module name="PackageDeclaration"/>
|
||||
<module name="ParameterAssignment"/>
|
||||
<module name="RequireThis"/>
|
||||
<module name="ReturnCount">
|
||||
<property name="severity" value="info"/>
|
||||
</module>
|
||||
<module name="SimplifyBooleanExpression"/>
|
||||
<module name="SimplifyBooleanReturn"/>
|
||||
<module name="StringLiteralEquality"/>
|
||||
<module name="SuperClone"/>
|
||||
<module name="SuperFinalize"/>
|
||||
<module name="UnnecessaryParentheses"/>
|
||||
<module name="UnnecessarySemicolonAfterOuterTypeDeclaration"/>
|
||||
<module name="UnnecessarySemicolonAfterTypeMemberDeclaration"/>
|
||||
<module name="UnnecessarySemicolonInEnumeration"/>
|
||||
<module name="UnnecessarySemicolonInTryWithResources"/>
|
||||
<module name="UnusedLocalVariable"/>
|
||||
<module name="VariableDeclarationUsageDistance">
|
||||
<property name="allowedDistance" value="3"/>
|
||||
<property name="validateBetweenScopes" value="false"/>
|
||||
</module>
|
||||
<module name="VariableDeclarationUsageDistance">
|
||||
<property name="allowedDistance" value="5"/>
|
||||
<property name="validateBetweenScopes" value="true"/>
|
||||
</module>
|
||||
|
||||
<!-- Imports -->
|
||||
<module name="AvoidStarImport"/>
|
||||
<module name="IllegalImport">
|
||||
<property name="illegalPkgs" value="sun"/>
|
||||
</module>
|
||||
<module name="ImportOrder">
|
||||
<property name="option" value="bottom"/>
|
||||
<property name="ordered" value="true"/>
|
||||
<property name="separated" value="true"/>
|
||||
<property name="separatedStaticGroups" value="true"/>
|
||||
<property name="caseSensitive" value="true"/>
|
||||
<property name="sortStaticImportsAlphabetically" value="true"/>
|
||||
<property name="groups"
|
||||
value="java,javax,*,org.mvplugins"/>
|
||||
<property name="staticGroups"
|
||||
value="/^.*$/"/>
|
||||
</module>
|
||||
<module name="RedundantImport"/>
|
||||
<module name="UnusedImports"/>
|
||||
|
||||
<!-- Javadoc Comments -->
|
||||
<module name="AtclauseOrder">
|
||||
<property name="target"
|
||||
value="CLASS_DEF, COMPACT_CTOR_DEF, CTOR_DEF, ENUM_DEF,
|
||||
INTERFACE_DEF, METHOD_DEF, RECORD_DEF, VARIABLE_DEF"/>
|
||||
</module>
|
||||
<module name="InvalidJavadocPosition"/>
|
||||
<module name="JavadocBlockTagLocation"/>
|
||||
<module name="JavadocContentLocationCheck"/>
|
||||
<module name="JavadocMethod">
|
||||
<property name="accessModifiers" value="public"/>
|
||||
<property name="allowMissingParamTags" value="true"/>
|
||||
<property name="allowMissingReturnTag" value="true"/>
|
||||
<property name="allowedAnnotations" value="Override, Test"/>
|
||||
<property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF, COMPACT_CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="JavadocMethod">
|
||||
<property name="accessModifiers" value="public"/>
|
||||
</module>
|
||||
<module name="JavadocMissingLeadingAsterisk"/>
|
||||
<module name="JavadocMissingWhitespaceAfterAsterisk"/>
|
||||
<module name="JavadocParagraph">
|
||||
<property name="allowNewlineParagraph" value="true"/>
|
||||
</module>
|
||||
<module name="JavadocStyle">
|
||||
<property name="scope" value="package"/>
|
||||
</module>
|
||||
<module name="JavadocTagContinuationIndentation"/>
|
||||
<module name="JavadocType"/>
|
||||
<module name="JavadocVariable">
|
||||
<property name="scope" value="package"/>
|
||||
</module>
|
||||
<module name="MissingJavadocMethod">
|
||||
<property name="scope" value="public"/>
|
||||
<property name="allowMissingPropertyJavadoc" value="true"/>
|
||||
</module>
|
||||
<module name="MissingJavadocMethod">
|
||||
<property name="scope" value="protected"/>
|
||||
<property name="excludeScope" value="public"/>
|
||||
<property name="allowMissingPropertyJavadoc" value="true"/>
|
||||
<property name="minLineCount" value="2"/>
|
||||
</module>
|
||||
<module name="MissingJavadocType">
|
||||
<property name="scope" value="protected"/>
|
||||
<property name="tokens"
|
||||
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
|
||||
RECORD_DEF, ANNOTATION_DEF"/>
|
||||
<property name="excludeScope" value="nothing"/>
|
||||
</module>
|
||||
<module name="NonEmptyAtclauseDescription"/>
|
||||
<module name="RequireEmptyLineBeforeBlockTagGroup"/>
|
||||
<module name="SingleLineJavadoc"/>
|
||||
<module name="SummaryJavadoc">
|
||||
<property name="forbiddenSummaryFragments"
|
||||
value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
|
||||
</module>
|
||||
<module name="WriteTag">
|
||||
<property name="tag" value="@author"/>
|
||||
<property name="tagFormat" value="\S"/>
|
||||
<property name="severity" value="ignore"/>
|
||||
<property name="tagSeverity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<!-- Metrics -->
|
||||
<module name="BooleanExpressionComplexity"/>
|
||||
<module name="ClassDataAbstractionCoupling">
|
||||
<property name="max" value="7"/>
|
||||
<property name="excludedClasses"
|
||||
value="ArrayIndexOutOfBoundsException, ArrayList, Boolean, Byte, Character,
|
||||
Class, Collection, Deprecated, Deque, Double, DoubleStream, EnumSet, Exception,
|
||||
Float, FunctionalInterface, HashMap, HashSet, IllegalArgumentException,
|
||||
IllegalStateException, IndexOutOfBoundsException, IntStream, Integer,
|
||||
LinkedHashMap, LinkedHashSet, LinkedList, List, Long, LongStream, Map,
|
||||
NullPointerException, Object, Optional, OptionalDouble, OptionalInt,
|
||||
OptionalLong, Override, Queue, RuntimeException, SafeVarargs, SecurityException,
|
||||
Set, Short, SortedMap, SortedSet, Stream, String, StringBuffer, StringBuilder,
|
||||
SuppressWarnings, Throwable, TreeMap, TreeSet, UnsupportedOperationException,
|
||||
Void, boolean, byte, char, double, float, int, long, short, var, void"/>
|
||||
</module>
|
||||
<module name="ClassFanOutComplexity">
|
||||
<property name="id" value="FanOutComplexityGettingTooHigh"/>
|
||||
<property name="max" value="20"/>
|
||||
<property name="excludedClasses"
|
||||
value="ArrayIndexOutOfBoundsException, ArrayList, Boolean, Byte, Character,
|
||||
Class, Collection, Deprecated, Deque, Double, DoubleStream, EnumSet, Exception,
|
||||
Float, FunctionalInterface, HashMap, HashSet, IllegalArgumentException,
|
||||
IllegalStateException, IndexOutOfBoundsException, IntStream, Integer,
|
||||
LinkedHashMap, LinkedHashSet, LinkedList, List, Long, LongStream, Map,
|
||||
NullPointerException, Object, Optional, OptionalDouble, OptionalInt,
|
||||
OptionalLong, Override, Queue, RuntimeException, SafeVarargs, SecurityException,
|
||||
Set, Short, SortedMap, SortedSet, Stream, String, StringBuffer, StringBuilder,
|
||||
SuppressWarnings, Throwable, TreeMap, TreeSet, UnsupportedOperationException,
|
||||
Void, boolean, byte, char, double, float, int, long, short, var, void"/>
|
||||
<property name="severity" value="info"/>
|
||||
</module>
|
||||
<module name="ClassFanOutComplexity">
|
||||
<property name="id" value="FanOutComplexityProbablyTooHigh"/>
|
||||
<property name="max" value="35"/>
|
||||
<property name="excludedClasses"
|
||||
value="ArrayIndexOutOfBoundsException, ArrayList, Boolean, Byte, Character,
|
||||
Class, Collection, Deprecated, Deque, Double, DoubleStream, EnumSet, Exception,
|
||||
Float, FunctionalInterface, HashMap, HashSet, IllegalArgumentException,
|
||||
IllegalStateException, IndexOutOfBoundsException, IntStream, Integer,
|
||||
LinkedHashMap, LinkedHashSet, LinkedList, List, Long, LongStream, Map,
|
||||
NullPointerException, Object, Optional, OptionalDouble, OptionalInt,
|
||||
OptionalLong, Override, Queue, RuntimeException, SafeVarargs, SecurityException,
|
||||
Set, Short, SortedMap, SortedSet, Stream, String, StringBuffer, StringBuilder,
|
||||
SuppressWarnings, Throwable, TreeMap, TreeSet, UnsupportedOperationException,
|
||||
Void, boolean, byte, char, double, float, int, long, short, var, void"/>
|
||||
</module>
|
||||
<module name="CyclomaticComplexity">
|
||||
<property name="max" value="7"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
<module name="JavaNCSS">
|
||||
<property name="methodMaximum" value="50"/>
|
||||
<property name="classMaximum" value="1500"/>
|
||||
<property name="fileMaximum" value="2000"/>
|
||||
<property name="recordMaximum" value="150"/>
|
||||
</module>
|
||||
<module name="NPathComplexity">
|
||||
<property name="max" value="200"/>
|
||||
</module>
|
||||
|
||||
<!-- Miscellaneous -->
|
||||
<module name="ArrayTypeStyle"/>
|
||||
<module name="AvoidEscapedUnicodeCharacters">
|
||||
<property name="allowEscapesForControlCharacters" value="true"/>
|
||||
<property name="allowNonPrintableEscapes" value="true"/>
|
||||
</module>
|
||||
<module name="CommentsIndentation">
|
||||
<property name="tokens" value="SINGLE_LINE_COMMENT, BLOCK_COMMENT_BEGIN"/>
|
||||
</module>
|
||||
<module name="Indentation">
|
||||
<property name="basicOffset" value="4"/>
|
||||
<property name="braceAdjustment" value="4"/>
|
||||
<property name="caseIndent" value="4"/>
|
||||
<property name="throwsIndent" value="8"/>
|
||||
<property name="arrayInitIndent" value="4"/>
|
||||
<property name="lineWrappingIndentation" value="8"/>
|
||||
<property name="forceStrictCondition" value="false"/>
|
||||
</module>
|
||||
<module name="NoCodeInFile"/>
|
||||
<module name="OuterTypeFilename"/>
|
||||
<module name="TodoComment">
|
||||
<property name="format" value="TODO"/>
|
||||
<!-- TODO change back to warning after MV5 -->
|
||||
<property name="severity" value="info"/>
|
||||
</module>
|
||||
<module name="TrailingComment">
|
||||
<property name="legalComment" value="^\sSUPPRESS CHECKSTYLE:"/>
|
||||
</module>
|
||||
<module name="UncommentedMain"/>
|
||||
<module name="UpperEll"/>
|
||||
|
||||
<!-- Modifiers -->
|
||||
<module name="ModifierOrder"/>
|
||||
<module name="RedundantModifier"/>
|
||||
|
||||
<!-- Naming Conventions -->
|
||||
<module name="AbbreviationAsWordInName">
|
||||
<property name="ignoreFinal" value="false"/>
|
||||
<property name="allowedAbbreviationLength" value="0"/>
|
||||
<property name="allowedAbbreviations" value="MV"/>
|
||||
<property name="tokens"
|
||||
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, ANNOTATION_DEF, ANNOTATION_FIELD_DEF,
|
||||
PARAMETER_DEF, VARIABLE_DEF, METHOD_DEF, PATTERN_VARIABLE_DEF, RECORD_DEF,
|
||||
RECORD_COMPONENT_DEF"/>
|
||||
</module>
|
||||
<module name="AbstractClassName">
|
||||
<property name="ignoreName" value="true"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Abstract class name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="CatchParameterName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="ClassTypeParameterName">
|
||||
<property name="format" value="^[A-Z]{1,3}$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Class type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="ConstantName">
|
||||
<message key="name.invalidPattern"
|
||||
value="Constant name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="InterfaceTypeParameterName">
|
||||
<property name="format" value="^[A-Z]{1,3}$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Interface type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="LambdaParameterName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Lambda parameter name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="LocalFinalVariableName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Local final variable name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="LocalVariableName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Local variable name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="MemberName">
|
||||
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$|^[A-Z][A-Z0-9_]*$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Member name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="MethodName">
|
||||
<message key="name.invalidPattern"
|
||||
value="Method name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="MethodTypeParameterName">
|
||||
<property name="format" value="^[A-Z]{1,3}$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Method type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="PackageName">
|
||||
<property name="severity" value="info"/>
|
||||
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Package name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="ParameterName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Parameter name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="PatternVariableName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Pattern variable name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="RecordComponentName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Record component name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="RecordTypeParameterName">
|
||||
<property name="format" value="^[A-Z]{1,3}$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Record type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="StaticVariableName">
|
||||
<message key="name.invalidPattern"
|
||||
value="Static variable name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="TypeName">
|
||||
<property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
|
||||
ANNOTATION_DEF, RECORD_DEF"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
|
||||
<!-- Size Violations -->
|
||||
<module name="AnonInnerLength">
|
||||
<property name="max" value="20"/>
|
||||
</module>
|
||||
<module name="ExecutableStatementCount">
|
||||
<property name="max" value="30"/>
|
||||
</module>
|
||||
<module name="LambdaBodyLength">
|
||||
<property name="id" value="LambdaGettingTooLong"/>
|
||||
<property name="max" value="10"/>
|
||||
<property name="severity" value="info"/>
|
||||
</module>
|
||||
<module name="LambdaBodyLength">
|
||||
<property name="id" value="LambdaProbablyTooLong"/>
|
||||
<property name="max" value="25"/>
|
||||
</module>
|
||||
<module name="MethodCount">
|
||||
<property name="maxTotal" value="100"/>
|
||||
<property name="maxPrivate" value="100"/>
|
||||
<property name="maxPackage" value="100"/>
|
||||
<property name="maxProtected" value="100"/>
|
||||
<property name="maxPublic" value="100"/>
|
||||
</module>
|
||||
<module name="MethodLength">
|
||||
<property name="max" value="50"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
<module name="OuterTypeNumber">
|
||||
<property name="max" value="1"/>
|
||||
</module>
|
||||
<module name="ParameterNumber">
|
||||
<property name="id" value="ConsiderLessMethodParameters"/>
|
||||
<property name="max" value="4"/>
|
||||
<property name="ignoreOverriddenMethods" value="true"/>
|
||||
<property name="severity" value="info"/>
|
||||
<property name="tokens" value="METHOD_DEF"/>
|
||||
</module>
|
||||
<module name="ParameterNumber">
|
||||
<property name="id" value="ProbablyTooManyMethodParameters"/>
|
||||
<property name="max" value="10"/>
|
||||
<property name="ignoreOverriddenMethods" value="true"/>
|
||||
<property name="tokens" value="METHOD_DEF"/>
|
||||
</module>
|
||||
<module name="ParameterNumber">
|
||||
<property name="id" value="ConsiderLessConstructorParameters"/>
|
||||
<property name="max" value="7"/>
|
||||
<property name="ignoreOverriddenMethods" value="true"/>
|
||||
<property name="severity" value="info"/>
|
||||
<property name="tokens" value="CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="ParameterNumber">
|
||||
<property name="id" value="ProbablyTooManyConstructorParameters"/>
|
||||
<property name="max" value="12"/>
|
||||
<property name="ignoreOverriddenMethods" value="true"/>
|
||||
<property name="tokens" value="CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="RecordComponentNumber">
|
||||
<property name="max" value="8"/>
|
||||
</module>
|
||||
|
||||
<!-- Whitespace -->
|
||||
<module name="EmptyForInitializerPad"/>
|
||||
<module name="EmptyForIteratorPad"/>
|
||||
<module name="EmptyLineSeparator">
|
||||
<property name="allowNoEmptyLineBetweenFields" value="true"/>
|
||||
<property name="allowMultipleEmptyLines" value="false"/>
|
||||
<property name="allowMultipleEmptyLinesInsideClassMembers" value="false"/>
|
||||
<property name="tokens"
|
||||
value="PACKAGE_DEF, IMPORT, STATIC_IMPORT, CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
|
||||
STATIC_INIT, INSTANCE_INIT, METHOD_DEF, CTOR_DEF, VARIABLE_DEF, RECORD_DEF,
|
||||
COMPACT_CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="GenericWhitespace">
|
||||
<message key="ws.followed"
|
||||
value="GenericWhitespace ''{0}'' is followed by whitespace."/>
|
||||
<message key="ws.preceded"
|
||||
value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
|
||||
<message key="ws.illegalFollow"
|
||||
value="GenericWhitespace ''{0}'' should followed by whitespace."/>
|
||||
<message key="ws.notPreceded"
|
||||
value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
|
||||
</module>
|
||||
<module name="MethodParamPad">
|
||||
<property name="tokens"
|
||||
value="CTOR_DEF, LITERAL_NEW, METHOD_CALL, METHOD_DEF,
|
||||
SUPER_CTOR_CALL, ENUM_CONSTANT_DEF, RECORD_DEF"/>
|
||||
</module>
|
||||
<module name="NoLineWrap">
|
||||
<property name="tokens" value="PACKAGE_DEF, IMPORT, STATIC_IMPORT"/>
|
||||
</module>
|
||||
<module name="NoWhitespaceAfter">
|
||||
<property name="tokens"
|
||||
value="AT, INC, DEC, UNARY_MINUS,UNARY_PLUS,BNOT,LNOT,DOT,ARRAY_DECLARATOR,INDEX_OP,LITERAL_SYNCHRONIZED,METHOD_REF"/>
|
||||
</module>
|
||||
<module name="NoWhitespaceBefore">
|
||||
<property name="id" value="AllowedWhitespaceBeforeWithoutLinebreak"/>
|
||||
<property name="tokens"
|
||||
value="COMMA, SEMI, POST_INC, POST_DEC, ELLIPSIS, LABELED_STAT"/>
|
||||
</module>
|
||||
<module name="NoWhitespaceBefore">
|
||||
<property name="id" value="AllowedWhitespaceBeforeWithLinebreak"/>
|
||||
<property name="tokens" value="DOT, METHOD_REF"/>
|
||||
<property name="allowLineBreaks" value="true"/>
|
||||
</module>
|
||||
<module name="NoWhitespaceBeforeCaseDefaultColon"/>
|
||||
<module name="OperatorWrap">
|
||||
<property name="tokens"
|
||||
value="QUESTION, COLON, EQUAL, NOT_EQUAL, DIV, PLUS, MINUS, STAR, MOD,
|
||||
SR, BSR, GE, GT, SL, LE, LT, BXOR, BOR, LOR, BAND, LAND, LITERAL_INSTANCEOF,
|
||||
TYPE_EXTENSION_AND, ASSIGN, DIV_ASSIGN, PLUS_ASSIGN, MINUS_ASSIGN,
|
||||
STAR_ASSIGN, MOD_ASSIGN, SR_ASSIGN, BSR_ASSIGN, SL_ASSIGN, BXOR_ASSIGN,
|
||||
BOR_ASSIGN, BAND_ASSIGN, METHOD_REF"/>
|
||||
</module>
|
||||
<module name="ParenPad">
|
||||
<property name="tokens"
|
||||
value="ANNOTATION, ANNOTATION_FIELD_DEF, CTOR_CALL, CTOR_DEF, DOT, ENUM_CONSTANT_DEF,
|
||||
EXPR, LITERAL_CATCH, LITERAL_DO, LITERAL_FOR, LITERAL_IF, LITERAL_NEW,
|
||||
LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_WHILE, METHOD_CALL,
|
||||
METHOD_DEF, QUESTION, RESOURCE_SPECIFICATION, SUPER_CTOR_CALL, LAMBDA,
|
||||
RECORD_DEF"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="id" value="SeparatorWrapNl"/>
|
||||
<property name="option" value="nl"/>
|
||||
<property name="tokens" value="DOT, AT, METHOD_REF"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="id" value="SeparatorWrapEol"/>
|
||||
<property name="option" value="eol"/>
|
||||
<property name="tokens"
|
||||
value="COMMA, SEMI, ELLIPSIS, RPAREN, ARRAY_DECLARATOR, RBRACK"/>
|
||||
</module>
|
||||
<module name="SingleSpaceSeparator"/>
|
||||
<module name="TypecastParenPad"/>
|
||||
<module name="WhitespaceAfter">
|
||||
<property name="tokens"
|
||||
value="COMMA, SEMI, TYPECAST, LITERAL_IF, LITERAL_ELSE, LITERAL_RETURN,
|
||||
LITERAL_WHILE, LITERAL_DO, LITERAL_FOR, LITERAL_FINALLY, DO_WHILE, ELLIPSIS,
|
||||
LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_CATCH, LAMBDA,
|
||||
LITERAL_YIELD, LITERAL_CASE"/>
|
||||
</module>
|
||||
<module name="WhitespaceAround">
|
||||
<property name="allowEmptyConstructors" value="true"/>
|
||||
<property name="allowEmptyLambdas" value="true"/>
|
||||
<property name="allowEmptyMethods" value="true"/>
|
||||
<property name="allowEmptyTypes" value="true"/>
|
||||
<property name="allowEmptyLoops" value="true"/>
|
||||
<property name="ignoreEnhancedForColon" value="false"/>
|
||||
<property name="tokens"
|
||||
value="ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR,
|
||||
BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, DO_WHILE, EQUAL, GE, GT, LAMBDA, LAND,
|
||||
LCURLY, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY,
|
||||
LITERAL_FOR, LITERAL_IF, LITERAL_RETURN, LITERAL_SWITCH, LITERAL_SYNCHRONIZED,
|
||||
LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN,
|
||||
NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION, RCURLY, SL, SLIST, SL_ASSIGN, SR,
|
||||
SR_ASSIGN, STAR, STAR_ASSIGN, LITERAL_ASSERT, TYPE_EXTENSION_AND"/>
|
||||
<message key="ws.notFollowed"
|
||||
value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks
|
||||
may only be represented as '{}' when not part of a multi-block statement"/>
|
||||
<message key="ws.notPreceded"
|
||||
value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
|
||||
</module>
|
||||
</module>
|
||||
</module>
|
||||
@@ -1,7 +0,0 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -1,252 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
@@ -1,94 +0,0 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,71 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta http-equiv="X-UA-Compatible" content="chrome=1">
|
||||
<link href='https://fonts.googleapis.com/css?family=Chivo:900' rel='stylesheet' type='text/css'>
|
||||
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen" />
|
||||
<link rel="stylesheet" type="text/css" href="stylesheets/pygment_trac.css" media="screen" />
|
||||
<link rel="stylesheet" type="text/css" href="stylesheets/print.css" media="print" />
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<title>Multiverse-Core by Multiverse</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
<div class="inner">
|
||||
|
||||
<header>
|
||||
<h1>Multiverse-core</h1>
|
||||
<h2>The original Bukkit Multi-World Plugin! </h2>
|
||||
</header>
|
||||
|
||||
<section id="downloads" class="clearfix">
|
||||
<a href="https://github.com/Multiverse/Multiverse-Core/zipball/master" id="download-zip" class="button"><span>Download .zip</span></a>
|
||||
<a href="https://github.com/Multiverse/Multiverse-Core/tarball/master" id="download-tar-gz" class="button"><span>Download .tar.gz</span></a>
|
||||
<a href="https://github.com/Multiverse/Multiverse-Core" id="view-on-github" class="button"><span>View on GitHub</span></a>
|
||||
</section>
|
||||
|
||||
<hr>
|
||||
|
||||
<section id="main_content">
|
||||
<h3>Welcome to GitHub Pages.</h3>
|
||||
|
||||
<p>This automatic page generator is the easiest way to create beautiful pages for all of your projects. Author your page content here using GitHub Flavored Markdown, select a template crafted by a designer, and publish. After your page is generated, you can check out the new branch:</p>
|
||||
|
||||
<pre><code>$ cd your_repo_root/repo_name
|
||||
$ git fetch origin
|
||||
$ git checkout gh-pages
|
||||
</code></pre>
|
||||
|
||||
<p>If you're using the GitHub for Mac, simply sync your repository and you'll see the new branch.</p>
|
||||
|
||||
<h3>Designer Templates</h3>
|
||||
|
||||
<p>We've crafted some handsome templates for you to use. Go ahead and continue to layouts to browse through them. You can easily go back to edit your page before publishing. After publishing your page, you can revisit the page generator and switch to another theme. Your Page content will be preserved if it remained markdown format.</p>
|
||||
|
||||
<h3>Rather Drive Stick?</h3>
|
||||
|
||||
<p>If you prefer to not use the automatic generator, push a branch named <code>gh-pages</code> to your repository to create a page manually. In addition to supporting regular HTML content, GitHub Pages support Jekyll, a simple, blog aware static site generator written by our own Tom Preston-Werner. Jekyll makes it easy to create site-wide headers and footers without having to copy them across every page. It also offers intelligent blog support and other advanced templating features.</p>
|
||||
|
||||
<h3>Authors and Contributors</h3>
|
||||
|
||||
<p>You can <a href="https://github.com/blog/821" class="user-mention">@mention</a> a GitHub username to generate a link to their profile. The resulting <code><a></code> element will link to the contributor's GitHub Profile. For example: In 2007, Chris Wanstrath (<a href="https://github.com/defunkt" class="user-mention">@defunkt</a>), PJ Hyett (<a href="https://github.com/pjhyett" class="user-mention">@pjhyett</a>), and Tom Preston-Werner (<a href="https://github.com/mojombo" class="user-mention">@mojombo</a>) founded GitHub.</p>
|
||||
|
||||
<h3>Support or Contact</h3>
|
||||
|
||||
<p>Having trouble with Pages? Check out the documentation at <a href="http://help.github.com/pages">http://help.github.com/pages</a> or contact <a href="mailto:support@github.com">support@github.com</a> and we’ll help you sort it out.</p>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
Multiverse-core is maintained by <a href="https://github.com/Multiverse">Multiverse</a><br>
|
||||
This page was generated by <a href="http://pages.github.com">GitHub Pages</a>. Tactile theme by <a href="http://twitter.com/jasonlong">Jason Long</a>.
|
||||
</footer>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
console.log('This would be the main JS file.');
|
||||
@@ -0,0 +1 @@
|
||||
{"tagline":"The original Bukkit Multi-World Plugin! ","body":"### Welcome to GitHub Pages.\r\nThis automatic page generator is the easiest way to create beautiful pages for all of your projects. Author your page content here using GitHub Flavored Markdown, select a template crafted by a designer, and publish. After your page is generated, you can check out the new branch:\r\n\r\n```\r\n$ cd your_repo_root/repo_name\r\n$ git fetch origin\r\n$ git checkout gh-pages\r\n```\r\n\r\nIf you're using the GitHub for Mac, simply sync your repository and you'll see the new branch.\r\n\r\n### Designer Templates\r\nWe've crafted some handsome templates for you to use. Go ahead and continue to layouts to browse through them. You can easily go back to edit your page before publishing. After publishing your page, you can revisit the page generator and switch to another theme. Your Page content will be preserved if it remained markdown format.\r\n\r\n### Rather Drive Stick?\r\nIf you prefer to not use the automatic generator, push a branch named `gh-pages` to your repository to create a page manually. In addition to supporting regular HTML content, GitHub Pages support Jekyll, a simple, blog aware static site generator written by our own Tom Preston-Werner. Jekyll makes it easy to create site-wide headers and footers without having to copy them across every page. It also offers intelligent blog support and other advanced templating features.\r\n\r\n### Authors and Contributors\r\nYou can @mention a GitHub username to generate a link to their profile. The resulting `<a>` element will link to the contributor's GitHub Profile. For example: In 2007, Chris Wanstrath (@defunkt), PJ Hyett (@pjhyett), and Tom Preston-Werner (@mojombo) founded GitHub.\r\n\r\n### Support or Contact\r\nHaving trouble with Pages? Check out the documentation at http://help.github.com/pages or contact support@github.com and we’ll help you sort it out.","note":"Don't delete this file! It's used internally to help with page regeneration.","google":"","name":"Multiverse-core"}
|
||||
@@ -1,11 +0,0 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
maven {
|
||||
url = uri("https://repo.onarandombox.com/multiverse-releases")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "Multiverse-Core"
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
package org.mvplugins.multiverse.core;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.inject.Inject;
|
||||
import org.apache.commons.lang3.text.WordUtils;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bstats.charts.AdvancedPie;
|
||||
import org.bstats.charts.SingleLineChart;
|
||||
import org.bukkit.World;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.utils.REPatterns;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
|
||||
/**
|
||||
* Helper class that registers and sends metrics to <a href="https://bstats.org">bstats website</a>.
|
||||
*/
|
||||
@Service
|
||||
final class BstatsMetricsConfigurator {
|
||||
|
||||
private static final int PLUGIN_ID = 7765;
|
||||
private static final String NO_GENERATOR_NAME = "N/A";
|
||||
|
||||
private final WorldManager worldManager;
|
||||
private final Metrics metrics;
|
||||
|
||||
@Inject
|
||||
private BstatsMetricsConfigurator(MultiverseCore plugin, WorldManager worldManager) {
|
||||
this.worldManager = worldManager;
|
||||
this.metrics = new Metrics(plugin, PLUGIN_ID);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
private void initMetrics() {
|
||||
try {
|
||||
addCustomGeneratorsMetric();
|
||||
addEnvironmentsMetric();
|
||||
addWorldCountMetric();
|
||||
|
||||
Logging.fine("Metrics enabled.");
|
||||
} catch (Exception e) {
|
||||
Logging.warning("There was an issue while enabling metrics:");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void addCustomGeneratorsMetric() {
|
||||
addAdvancedPieMetric("custom_generators", map -> {
|
||||
for (MultiverseWorld w : worldManager.getLoadedWorlds()) {
|
||||
incrementCount(map, getGeneratorName(w));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String getGeneratorName(MultiverseWorld world) {
|
||||
String gen = world.getGenerator();
|
||||
return (gen != null && !gen.equalsIgnoreCase("null"))
|
||||
? REPatterns.COLON.split(gen)[0]
|
||||
: NO_GENERATOR_NAME;
|
||||
}
|
||||
|
||||
private void addEnvironmentsMetric() {
|
||||
addAdvancedPieMetric("environments", map -> {
|
||||
for (MultiverseWorld w : worldManager.getLoadedWorlds()) {
|
||||
incrementCount(map, titleCaseEnv(w.getEnvironment()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String titleCaseEnv(World.Environment env) {
|
||||
String envName = env.name().replaceAll("_+", " ");
|
||||
return WordUtils.capitalizeFully(envName);
|
||||
}
|
||||
|
||||
private void addWorldCountMetric() {
|
||||
addLineMetric("worlds", () -> worldManager.getWorlds().size());
|
||||
}
|
||||
|
||||
private void addAdvancedPieMetric(String chartId, Consumer<Map<String, Integer>> metricsFunc) {
|
||||
metrics.addCustomChart(createAdvancedPieChart(chartId, metricsFunc));
|
||||
}
|
||||
|
||||
private void addLineMetric(String chartId, Callable<Integer> metricsFunc) {
|
||||
metrics.addCustomChart(createLineChart(chartId, metricsFunc));
|
||||
}
|
||||
|
||||
private void incrementCount(Map<String, Integer> map, String key) {
|
||||
Integer count = map.getOrDefault(key, 0);
|
||||
map.put(key, count + 1);
|
||||
}
|
||||
|
||||
private AdvancedPie createAdvancedPieChart(String chartId, Consumer<Map<String, Integer>> metricsFunc) {
|
||||
Map<String, Integer> map = new HashMap<>();
|
||||
metricsFunc.accept(map);
|
||||
return new AdvancedPie(chartId, () -> map);
|
||||
}
|
||||
|
||||
private SingleLineChart createLineChart(String chartId, Callable<Integer> metricsFunc) {
|
||||
return new SingleLineChart(chartId, metricsFunc);
|
||||
}
|
||||
}
|
||||
@@ -1,299 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Multiverse 2 Copyright (c) the Multiverse Team 2011. *
|
||||
* Multiverse 2 is licensed under the BSD License. *
|
||||
* For more information please check the README.md file included *
|
||||
* with this project. *
|
||||
******************************************************************************/
|
||||
|
||||
package org.mvplugins.multiverse.core;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import io.vavr.control.Try;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Provider;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerialization;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.anchor.AnchorManager;
|
||||
import org.mvplugins.multiverse.core.destination.Destination;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationsProvider;
|
||||
import org.mvplugins.multiverse.core.commands.CoreCommand;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.economy.MVEconomist;
|
||||
import org.mvplugins.multiverse.core.listeners.CoreListener;
|
||||
import org.mvplugins.multiverse.core.inject.PluginServiceLocatorFactory;
|
||||
import org.mvplugins.multiverse.core.module.MultiverseModule;
|
||||
import org.mvplugins.multiverse.core.utils.StringFormatter;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.location.NullSpawnLocation;
|
||||
import org.mvplugins.multiverse.core.world.location.SpawnLocation;
|
||||
import org.mvplugins.multiverse.core.world.location.UnloadedWorldLocation;
|
||||
|
||||
/**
|
||||
* The start of the Multiverse-Core plugin
|
||||
*/
|
||||
@Service
|
||||
public class MultiverseCore extends MultiverseModule {
|
||||
|
||||
@Inject
|
||||
private Provider<CoreConfig> configProvider;
|
||||
@Inject
|
||||
private Provider<WorldManager> worldManagerProvider;
|
||||
@Inject
|
||||
private Provider<AnchorManager> anchorManagerProvider;
|
||||
@Inject
|
||||
private Provider<DestinationsProvider> destinationsProviderProvider;
|
||||
@Inject
|
||||
private Provider<BstatsMetricsConfigurator> metricsConfiguratorProvider;
|
||||
@Inject
|
||||
private Provider<MVEconomist> economistProvider;
|
||||
|
||||
/**
|
||||
* This is the constructor for the MultiverseCore.
|
||||
*/
|
||||
public MultiverseCore() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
// Setup our Logging
|
||||
Logging.init(this);
|
||||
|
||||
// Create our DataFolder
|
||||
if (!getDataFolder().exists() && !getDataFolder().mkdirs()) {
|
||||
Logging.severe("Failed to create data folder!");
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
// Register our config classes
|
||||
ConfigurationSerialization.registerClass(NullSpawnLocation.class);
|
||||
ConfigurationSerialization.registerClass(SpawnLocation.class);
|
||||
ConfigurationSerialization.registerClass(UnloadedWorldLocation.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
initializeDependencyInjection(new MultiverseCorePluginBinder(this));
|
||||
|
||||
// Load our configs first as we need them for everything else.
|
||||
var config = configProvider.get();
|
||||
var loadSuccess = config.load().andThenTry(config::save).isSuccess();
|
||||
if (!loadSuccess || !config.isLoaded()) {
|
||||
Logging.severe("Your configs were not loaded.");
|
||||
Logging.severe("Please check your configs and restart the server.");
|
||||
this.getServer().getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
Logging.setShowingConfig(shouldShowConfig());
|
||||
|
||||
// Initialize the worlds
|
||||
worldManagerProvider.get().initAllWorlds().andThenTry(() -> {
|
||||
loadEconomist(); // Setup economy here so vault is loaded
|
||||
loadAnchors();
|
||||
registerDynamicListeners(CoreListener.class);
|
||||
setUpLocales();
|
||||
registerCommands(CoreCommand.class);
|
||||
registerDestinations();
|
||||
setupMetrics();
|
||||
loadPlaceholderApiIntegration();
|
||||
loadApiService();
|
||||
saveAllConfigs();
|
||||
logEnableMessage();
|
||||
}).onFailure(e -> {
|
||||
Logging.severe("Failed to multiverse core! Disabling...");
|
||||
e.printStackTrace();
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onDisable() {
|
||||
super.onDisable();
|
||||
MultiverseCoreApi.shutdown();
|
||||
shutdownDependencyInjection();
|
||||
PluginServiceLocatorFactory.get().shutdown();
|
||||
Logging.shutdown();
|
||||
}
|
||||
|
||||
private boolean shouldShowConfig() {
|
||||
return !configProvider.get().getSilentStart();
|
||||
}
|
||||
|
||||
private void loadEconomist() {
|
||||
Try.run(() -> economistProvider.get())
|
||||
.onFailure(e -> {
|
||||
Logging.severe("Failed to load economy integration");
|
||||
e.printStackTrace();
|
||||
});
|
||||
}
|
||||
|
||||
private void loadAnchors() {
|
||||
Try.of(() -> anchorManagerProvider.get())
|
||||
.flatMap(AnchorManager::loadAnchors)
|
||||
.onFailure(e -> {
|
||||
Logging.severe("Failed to load anchors");
|
||||
e.printStackTrace();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all the destinations.
|
||||
*/
|
||||
private void registerDestinations() {
|
||||
Try.of(() -> destinationsProviderProvider.get())
|
||||
.andThenTry(destinationsProvider -> {
|
||||
serviceLocator.getAllServices(Destination.class)
|
||||
.forEach(destinationsProvider::registerDestination);
|
||||
})
|
||||
.onFailure(e -> {
|
||||
Logging.severe("Failed to register destinations");
|
||||
e.printStackTrace();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup bstats Metrics.
|
||||
*/
|
||||
private void setupMetrics() {
|
||||
if (TestingMode.isDisabled()) {
|
||||
// Load metrics
|
||||
Try.of(() -> metricsConfiguratorProvider.get())
|
||||
.onFailure(e -> {
|
||||
Logging.severe("Failed to setup metrics");
|
||||
e.printStackTrace();
|
||||
});
|
||||
} else {
|
||||
Logging.info("Metrics are disabled in testing mode.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup placeholder api hook
|
||||
*/
|
||||
private void loadPlaceholderApiIntegration() {
|
||||
if (configProvider.get().isRegisterPapiHook()
|
||||
&& getServer().getPluginManager().getPlugin("PlaceholderAPI") != null) {
|
||||
Try.run(() -> serviceLocator.getService(PlaceholderExpansionHook.class))
|
||||
.onFailure(e -> {
|
||||
Logging.severe("Failed to load PlaceholderAPI integration.");
|
||||
e.printStackTrace();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the api service for {@link MultiverseCoreApi}
|
||||
*/
|
||||
private void loadApiService() {
|
||||
Try.run(() -> MultiverseCoreApi.init(this))
|
||||
.onSuccess(ignore -> Logging.info("API service loaded!"))
|
||||
.onFailure(e -> {
|
||||
Logging.severe("Failed to load API service!");
|
||||
e.printStackTrace();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Save config.yml, worlds.yml, and anchors.yml.
|
||||
*
|
||||
* @return {@link Try#isSuccess()} true if all configs were successfully saved
|
||||
*/
|
||||
private Try<Void> saveAllConfigs() {
|
||||
return configProvider.get().save()
|
||||
.andThenTry(() -> worldManagerProvider.get().saveWorldsConfig())
|
||||
.andThenTry(() -> anchorManagerProvider.get().saveAllAnchors())
|
||||
.onFailure(e ->
|
||||
Logging.severe("Failed to save all configs, things may not work as expected. %s",
|
||||
e.getLocalizedMessage()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the enable message.
|
||||
*/
|
||||
private void logEnableMessage() {
|
||||
Logging.config("\u001B[32mVersion %s (API v%s) Enabled - By %s\u001B[39m",
|
||||
this.getDescription().getVersion(), getVersionAsNumber(), StringFormatter.joinAnd(getDescription().getAuthors()));
|
||||
|
||||
if (configProvider.get().isShowingDonateMessage()) {
|
||||
Logging.config("\u001B[32mLoving Multiverse-Core? Please consider supporting the project with a small donation: https://github.com/sponsors/Multiverse\u001B[39m");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MultiverseCoreApi
|
||||
*
|
||||
* @return The MultiverseCoreApi
|
||||
*
|
||||
* @deprecated Use {@link MultiverseCoreApi#get()} directly.
|
||||
*/
|
||||
@Deprecated(since = "5.1", forRemoval = true)
|
||||
@ApiStatus.ScheduledForRemoval(inVersion = "6.0")
|
||||
public MultiverseCoreApi getApi() {
|
||||
return MultiverseCoreApi.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public double getTargetCoreVersion() {
|
||||
return getVersionAsNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
return Logging.getLogger();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public @NotNull FileConfiguration getConfig() {
|
||||
CoreConfig coreConfig = this.configProvider.get();
|
||||
var config = coreConfig.getConfig();
|
||||
if (config != null && coreConfig.isLoaded()) {
|
||||
return config;
|
||||
}
|
||||
|
||||
var loadSuccess = coreConfig.load().isSuccess();
|
||||
if (!loadSuccess || !coreConfig.isLoaded()) {
|
||||
throw new RuntimeException("Failed to load configs");
|
||||
}
|
||||
return coreConfig.getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
this.configProvider.get().load();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void saveConfig() {
|
||||
this.configProvider.get().save();
|
||||
}
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
package org.mvplugins.multiverse.core;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.mvplugins.multiverse.core.anchor.AnchorManager;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationsProvider;
|
||||
import org.mvplugins.multiverse.core.economy.MVEconomist;
|
||||
import org.mvplugins.multiverse.core.inject.PluginServiceLocator;
|
||||
import org.mvplugins.multiverse.core.teleportation.AsyncSafetyTeleporter;
|
||||
import org.mvplugins.multiverse.core.teleportation.BlockSafety;
|
||||
import org.mvplugins.multiverse.core.teleportation.LocationManipulation;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.biomeprovider.BiomeProviderFactory;
|
||||
import org.mvplugins.multiverse.core.world.generators.GeneratorProvider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Provides access to the MultiverseCore API.
|
||||
*/
|
||||
public class MultiverseCoreApi {
|
||||
|
||||
private static MultiverseCoreApi instance;
|
||||
private static final List<Consumer<MultiverseCoreApi>> whenLoadedCallbacks = new ArrayList<>();
|
||||
|
||||
static void init(@NotNull MultiverseCore multiverseCore) {
|
||||
if (instance != null) {
|
||||
throw new IllegalStateException("MultiverseCoreApi has already been initialized!");
|
||||
}
|
||||
instance = new MultiverseCoreApi(multiverseCore.getServiceLocator());
|
||||
Bukkit.getServicesManager().register(MultiverseCoreApi.class, instance, multiverseCore, ServicePriority.Normal);
|
||||
|
||||
whenLoadedCallbacks.forEach(c -> c.accept(instance));
|
||||
whenLoadedCallbacks.clear();
|
||||
}
|
||||
|
||||
static void shutdown() {
|
||||
Bukkit.getServicesManager().unregister(instance);
|
||||
instance = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook your plugin into the MultiverseCoreApi here to ensure you only start using the API after it has been initialized.
|
||||
* Use this if you know your plugin may load before Multiverse-Core is fully initialized.
|
||||
* <br/>
|
||||
* This handy method removes the need for you to check with plugin manager or listen to plugin enable event.
|
||||
* <br/>
|
||||
* Callback will be called immediately if the MultiverseCoreApi has already been initialized.
|
||||
*
|
||||
* @param consumer The callback to execute when the MultiverseCoreApi has been initialized.
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public static void whenLoaded(@NotNull Consumer<MultiverseCoreApi> consumer) {
|
||||
if (instance != null) {
|
||||
consumer.accept(instance);
|
||||
} else {
|
||||
whenLoadedCallbacks.add(consumer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the MultiverseCoreApi has been initialized.
|
||||
*
|
||||
* @return True if the MultiverseCoreApi has been initialized, false otherwise
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public static boolean isLoaded() {
|
||||
return instance != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MultiverseCoreApi. This will throw an exception if the Multiverse-Core has not been initialized.
|
||||
* <br/>
|
||||
* You can check if the MultiverseCoreApi has been initialized with {@link #isLoaded()} before using this method.
|
||||
* <br/>
|
||||
* Alternatively, you can use {@link #whenLoaded(Consumer)} to hook into the MultiverseCoreApi if your plugin may
|
||||
* load before Multiverse-Core is fully initialized.
|
||||
*
|
||||
* @return The MultiverseCoreApi
|
||||
* @throws IllegalStateException if the MultiverseCoreApi has not been initialized
|
||||
*/
|
||||
public static @NotNull MultiverseCoreApi get() {
|
||||
if (instance == null) {
|
||||
throw new IllegalStateException("MultiverseCoreApi has not been initialized!");
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private final PluginServiceLocator serviceLocator;
|
||||
|
||||
private MultiverseCoreApi(@NotNull PluginServiceLocator serviceProvider) {
|
||||
this.serviceLocator = serviceProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of AnchorManager.
|
||||
*
|
||||
* @return The AnchorManager instance
|
||||
*/
|
||||
public @NotNull AnchorManager getAnchorManager() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(AnchorManager.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of BiomeProviderFactory.
|
||||
*
|
||||
* @return The BiomeProviderFactory instance
|
||||
*/
|
||||
public @NotNull BiomeProviderFactory getBiomeProviderFactory() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(BiomeProviderFactory.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of BlockSafety.
|
||||
*
|
||||
* @return The BlockSafety instance
|
||||
*/
|
||||
public @NotNull BlockSafety getBlockSafety() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(BlockSafety.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of CoreConfig.
|
||||
*
|
||||
* @return The CoreConfig instance
|
||||
*/
|
||||
public @NotNull CoreConfig getCoreConfig() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(CoreConfig.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of DestinationsProvider.
|
||||
*
|
||||
* @return The DestinationsProvider instance
|
||||
*/
|
||||
public @NotNull DestinationsProvider getDestinationsProvider() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(DestinationsProvider.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of GeneratorProvider.
|
||||
*
|
||||
* @return The GeneratorProvider instance
|
||||
*/
|
||||
public @NotNull GeneratorProvider getGeneratorProvider() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(GeneratorProvider.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of LocationManipulation.
|
||||
*
|
||||
* @return The LocationManipulation instance
|
||||
*/
|
||||
public @NotNull LocationManipulation getLocationManipulation() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(LocationManipulation.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of MVEconomist.
|
||||
*
|
||||
* @return The MVEconomist instance
|
||||
*/
|
||||
public @NotNull MVEconomist getMVEconomist() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(MVEconomist.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of SafetyTeleporter.
|
||||
*
|
||||
* @return The SafetyTeleporter instance
|
||||
*/
|
||||
public @NotNull AsyncSafetyTeleporter getSafetyTeleporter() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(AsyncSafetyTeleporter.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of WorldManager.
|
||||
*
|
||||
* @return The WorldManager instance
|
||||
*/
|
||||
public @NotNull WorldManager getWorldManager() {
|
||||
return Objects.requireNonNull(serviceLocator.getActiveService(WorldManager.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of Multiverse-Core's PluginServiceLocator.
|
||||
* <br/>
|
||||
* You can use this to hook into the hk2 dependency injection system used by Multiverse-Core.
|
||||
*
|
||||
* @return The Multiverse-Core's PluginServiceLocator
|
||||
*/
|
||||
public @NotNull PluginServiceLocator getServiceLocator() {
|
||||
return serviceLocator;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package org.mvplugins.multiverse.core;
|
||||
|
||||
import org.glassfish.hk2.utilities.binding.ScopedBindingBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.mvplugins.multiverse.core.module.MultiverseModuleBinder;
|
||||
|
||||
final class MultiverseCorePluginBinder extends MultiverseModuleBinder<MultiverseCore> {
|
||||
|
||||
MultiverseCorePluginBinder(@NotNull MultiverseCore plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScopedBindingBuilder<MultiverseCore> bindPluginClass(
|
||||
ScopedBindingBuilder<MultiverseCore> bindingBuilder) {
|
||||
return super.bindPluginClass(bindingBuilder).to(MultiverseCore.class);
|
||||
}
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
package org.mvplugins.multiverse.core;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.inject.Inject;
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.SpawnCategory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.economy.MVEconomist;
|
||||
import org.mvplugins.multiverse.core.utils.MinecraftTimeFormatter;
|
||||
import org.mvplugins.multiverse.core.utils.REPatterns;
|
||||
import org.mvplugins.multiverse.core.utils.StringFormatter;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@Service
|
||||
final class PlaceholderExpansionHook extends PlaceholderExpansion {
|
||||
|
||||
private final MultiverseCore plugin;
|
||||
private final WorldManager worldManager;
|
||||
private final MVEconomist economist;
|
||||
|
||||
@Inject
|
||||
public PlaceholderExpansionHook(MultiverseCore plugin, WorldManager worldManager, MVEconomist economist) {
|
||||
this.plugin = plugin;
|
||||
this.worldManager = worldManager;
|
||||
this.economist = economist;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
@Override
|
||||
public boolean register() {
|
||||
return super.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getIdentifier() {
|
||||
return "multiverse-core";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getAuthor() {
|
||||
return StringFormatter.joinAnd(plugin.getDescription().getAuthors());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getVersion() {
|
||||
return plugin.getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean persist() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Placeholder implementation, format: %multiverse-core_<placeholder>_[world]% world is optional.
|
||||
*
|
||||
* @param offlinePlayer Player to get the placeholder for
|
||||
* @param params Placeholder to get
|
||||
* @return Placeholder value
|
||||
*/
|
||||
@Override
|
||||
public @Nullable String onRequest(OfflinePlayer offlinePlayer, @NotNull String params) {
|
||||
// Split string in to an Array with underscores
|
||||
List<String> paramsArray = Lists.newArrayList(REPatterns.UNDERSCORE.split(params));
|
||||
|
||||
// No placeholder defined
|
||||
if (paramsArray.isEmpty()) {
|
||||
warning("No placeholder key defined");
|
||||
return null;
|
||||
}
|
||||
|
||||
final var placeholder = paramsArray.remove(0);
|
||||
|
||||
String worldName = parseWorldName(offlinePlayer, paramsArray);
|
||||
if (worldName == null) return null;
|
||||
|
||||
return worldManager.getLoadedWorld(worldName)
|
||||
.onEmpty(() -> warning("Multiverse World not found: " + worldName))
|
||||
.map(world -> getWorldPlaceHolderValue(placeholder, paramsArray, world))
|
||||
.getOrNull();
|
||||
}
|
||||
|
||||
private @Nullable String parseWorldName(OfflinePlayer offlinePlayer, List<String> paramsArray) {
|
||||
// No world defined, get from player
|
||||
if (paramsArray.isEmpty()) {
|
||||
if (offlinePlayer instanceof Player player) {
|
||||
return player.getWorld().getName();
|
||||
} else {
|
||||
warning("You must specify a world name for non-player placeholders");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Try get from params
|
||||
String paramWorldName = paramsArray.get(paramsArray.size() - 1);
|
||||
if (worldManager.isLoadedWorld(paramWorldName)) {
|
||||
paramsArray.remove(paramsArray.size() - 1);
|
||||
return paramWorldName;
|
||||
}
|
||||
|
||||
// Param not a world, fallback to player
|
||||
if (offlinePlayer instanceof Player player) {
|
||||
return player.getWorld().getName();
|
||||
}
|
||||
warning("Multiverse World not found: " + paramWorldName);
|
||||
return null;
|
||||
}
|
||||
|
||||
private @Nullable String getWorldPlaceHolderValue(@NotNull String placeholder,
|
||||
@NotNull List<String> placeholderParams,
|
||||
@NotNull LoadedMultiverseWorld world) {
|
||||
// Switch to find what specific placeholder we want
|
||||
switch (placeholder.toLowerCase(Locale.ENGLISH)) {
|
||||
case "alias" -> {
|
||||
return world.getAliasOrName();
|
||||
}
|
||||
case "animalspawn" -> {
|
||||
return String.valueOf(world.getEntitySpawnConfig().getSpawnCategoryConfig(SpawnCategory.ANIMAL).isSpawn());
|
||||
}
|
||||
case "autoheal" -> {
|
||||
return String.valueOf(world.getAutoHeal());
|
||||
}
|
||||
case "blacklist" -> {
|
||||
return String.join(", ", world.getWorldBlacklist());
|
||||
}
|
||||
case "currency" -> {
|
||||
return String.valueOf(world.getCurrency());
|
||||
}
|
||||
case "difficulty" -> {
|
||||
return world.getDifficulty().toString();
|
||||
}
|
||||
case "entryfee" -> {
|
||||
return economist.formatPrice(world.getPrice(), world.getCurrency());
|
||||
}
|
||||
case "environment" -> {
|
||||
return world.getEnvironment().toString().toLowerCase();
|
||||
}
|
||||
case "flight" -> {
|
||||
return String.valueOf(world.isAllowFlight());
|
||||
}
|
||||
case "gamemode" -> {
|
||||
return world.getGameMode().toString().toLowerCase();
|
||||
}
|
||||
case "generator" -> {
|
||||
return world.getGenerator();
|
||||
}
|
||||
case "hunger" -> {
|
||||
return String.valueOf(world.isHunger());
|
||||
}
|
||||
case "monstersspawn" -> {
|
||||
return String.valueOf(world.getEntitySpawnConfig().getSpawnCategoryConfig(SpawnCategory.MONSTER).isSpawn());
|
||||
}
|
||||
case "name" -> {
|
||||
return world.getName();
|
||||
}
|
||||
case "playercount" -> {
|
||||
return String.valueOf(world.getBukkitWorld()
|
||||
.map(World::getPlayers)
|
||||
.map(List::size)
|
||||
.getOrElse(-1));
|
||||
}
|
||||
case "playerlimit" -> {
|
||||
return String.valueOf(world.getPlayerLimit());
|
||||
}
|
||||
case "price" -> {
|
||||
return String.valueOf(world.getPrice());
|
||||
}
|
||||
case "pvp" -> {
|
||||
return String.valueOf(world.getPvp());
|
||||
}
|
||||
case "seed" -> {
|
||||
return String.valueOf(world.getSeed());
|
||||
}
|
||||
case "time" -> {
|
||||
String timeFormat = !placeholderParams.isEmpty() ? placeholderParams.get(0) : "";
|
||||
long time = world.getBukkitWorld().map(World::getTime).getOrElse(0L);
|
||||
switch (timeFormat) {
|
||||
case "" -> {
|
||||
return String.valueOf(time);
|
||||
}
|
||||
case "12h" -> {
|
||||
return MinecraftTimeFormatter.format12h(time);
|
||||
}
|
||||
case "24h" -> {
|
||||
return MinecraftTimeFormatter.format24h(time);
|
||||
}
|
||||
default -> {
|
||||
return MinecraftTimeFormatter.formatTime(time, timeFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
case "type" -> {
|
||||
return world.getBukkitWorld().map(World::getWorldType).map(Enum::name).getOrElse("null");
|
||||
}
|
||||
case "weather" -> {
|
||||
return String.valueOf(world.isAllowWeather());
|
||||
}
|
||||
default -> {
|
||||
warning("Unknown placeholder: " + placeholder);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package org.mvplugins.multiverse.core;
|
||||
|
||||
/**
|
||||
* A utility class that enables automated tests to flag Multiverse for testing. This allows Multiverse to not perform
|
||||
* certain behaviors such as enabled stats uploads.
|
||||
*/
|
||||
final class TestingMode {
|
||||
|
||||
private static boolean enabled = false;
|
||||
|
||||
private TestingMode() {
|
||||
// No instantiation
|
||||
}
|
||||
|
||||
static void enable() {
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
static boolean isDisabled() {
|
||||
return !enabled;
|
||||
}
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Multiverse 2 Copyright (c) the Multiverse Team 2011. *
|
||||
* Multiverse 2 is licensed under the BSD License. *
|
||||
* For more information please check the README.md file included *
|
||||
* with this project. *
|
||||
******************************************************************************/
|
||||
|
||||
package org.mvplugins.multiverse.core.anchor;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import io.vavr.control.Option;
|
||||
import io.vavr.control.Try;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.MultiverseCore;
|
||||
import org.mvplugins.multiverse.core.teleportation.LocationManipulation;
|
||||
import org.mvplugins.multiverse.core.utils.result.Result;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.entrycheck.WorldEntryCheckerProvider;
|
||||
import org.mvplugins.multiverse.core.world.location.UnloadedWorldLocation;
|
||||
|
||||
/**
|
||||
* Manages anchors and it's location.
|
||||
*/
|
||||
@Service
|
||||
public final class AnchorManager {
|
||||
|
||||
private static final String ANCHORS_FILE = "anchors.yml";
|
||||
private static final String ANCHORS_CONFIG_SECTION = "anchors";
|
||||
|
||||
private final Map<String, MultiverseAnchor> anchors;
|
||||
private FileConfiguration anchorConfig;
|
||||
|
||||
private final Plugin plugin;
|
||||
private final LocationManipulation locationManipulation;
|
||||
private final WorldEntryCheckerProvider entryCheckerProvider;
|
||||
private final WorldManager worldManager;
|
||||
|
||||
@Inject
|
||||
AnchorManager(
|
||||
MultiverseCore plugin,
|
||||
LocationManipulation locationManipulation,
|
||||
WorldEntryCheckerProvider entryCheckerProvider,
|
||||
WorldManager worldManager
|
||||
) {
|
||||
this.plugin = plugin;
|
||||
this.locationManipulation = locationManipulation;
|
||||
this.entryCheckerProvider = entryCheckerProvider;
|
||||
this.worldManager = worldManager;
|
||||
|
||||
this.anchors = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all anchors.
|
||||
*/
|
||||
public Try<Void> loadAnchors() {
|
||||
anchors.clear();
|
||||
return Try.run(() -> {
|
||||
anchorConfig = YamlConfiguration.loadConfiguration(new File(plugin.getDataFolder(), ANCHORS_FILE));
|
||||
parseAnchorsFromConfig();
|
||||
});
|
||||
}
|
||||
|
||||
private void parseAnchorsFromConfig() {
|
||||
var anchorsSection = getAnchorsConfigSection();
|
||||
Set<String> anchorKeys = anchorsSection.getKeys(false);
|
||||
for (String key : anchorKeys) {
|
||||
//world:x,y,z:pitch:yaw
|
||||
Location anchorLocation = locationManipulation.stringToLocation(anchorsSection.getString(key, ""));
|
||||
if (anchorLocation != null) {
|
||||
Logging.config("Loading anchor: '%s'...", key);
|
||||
anchors.put(key, new MultiverseAnchor(key, UnloadedWorldLocation.fromLocation(anchorLocation)));
|
||||
} else {
|
||||
Logging.warning("The location for anchor '%s' is INVALID.", key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ConfigurationSection getAnchorsConfigSection() {
|
||||
var anchorsConfigSection = anchorConfig.getConfigurationSection(ANCHORS_CONFIG_SECTION);
|
||||
if (anchorsConfigSection == null) {
|
||||
anchorsConfigSection = anchorConfig.createSection(ANCHORS_CONFIG_SECTION);
|
||||
}
|
||||
return anchorsConfigSection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves all anchors.
|
||||
*
|
||||
* @return True if all anchors were successfully saved.
|
||||
*/
|
||||
public Try<Void> saveAllAnchors() {
|
||||
return Try.run(() -> anchorConfig.save(new File(plugin.getDataFolder(), ANCHORS_FILE)))
|
||||
.onFailure(failure ->
|
||||
Logging.severe("Failed to save anchors.yml. Please check your file permissions."));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Location} associated with an anchor.
|
||||
*
|
||||
* @param anchorName The name of the anchor.
|
||||
* @return The {@link Location}.
|
||||
*/
|
||||
public Option<MultiverseAnchor> getAnchor(String anchorName) {
|
||||
return Option.of(anchors.get(anchorName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new location for an anchor. Creates a new anchor if it doesn't exist.
|
||||
*
|
||||
* @param anchorName The name of the anchor.
|
||||
* @param location The location of the anchor as string (world:x,y,z:pitch:yaw).
|
||||
* @return True if the anchor was successfully saved.
|
||||
*/
|
||||
public Try<Void> setAnchor(@NotNull String anchorName, @NotNull String location) {
|
||||
Location parsed = locationManipulation.stringToLocation(location);
|
||||
if (parsed == null) {
|
||||
return Try.failure(new IllegalArgumentException("The location for anchor '" + anchorName + "' is INVALID."));
|
||||
}
|
||||
return setAnchor(anchorName, parsed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new location for an anchor. Creates a new anchor if it doesn't exist.
|
||||
*
|
||||
* @param anchorName The name of the anchor.
|
||||
* @param location The {@link Location} of the anchor.
|
||||
* @return True if the anchor was successfully saved.
|
||||
*/
|
||||
public Try<Void> setAnchor(@NotNull String anchorName, @NotNull Location location) {
|
||||
Option.of(anchors.get(anchorName))
|
||||
.peek(anchor -> anchor.setLocation(UnloadedWorldLocation.fromLocation(location)))
|
||||
.onEmpty(() -> anchors.put(anchorName, new MultiverseAnchor(anchorName, UnloadedWorldLocation.fromLocation(location))));
|
||||
getAnchorsConfigSection().set(anchorName, locationManipulation.locationToString(location));
|
||||
return saveAllAnchors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all anchors.
|
||||
*
|
||||
* @return An unmodifiable {@link List} containing all anchors.
|
||||
*/
|
||||
public List<MultiverseAnchor> getAllAnchors() {
|
||||
return anchors.values().stream().toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all anchors that the specified {@link Player} can access.
|
||||
*
|
||||
* @param player The {@link Player}.
|
||||
* @return An unmodifiable {@link List} containing all anchors the specified {@link Player} can access.
|
||||
*/
|
||||
public List<MultiverseAnchor> getAnchors(@Nullable Player player) {
|
||||
if (player == null) {
|
||||
return getAllAnchors();
|
||||
} else {
|
||||
return getAnchorsForPlayer(player);
|
||||
}
|
||||
}
|
||||
|
||||
private List<MultiverseAnchor> getAnchorsForPlayer(@NotNull Player player) {
|
||||
return anchors.values().stream()
|
||||
.filter(anchor -> shouldIncludeAnchorForPlayer(anchor, player))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private boolean shouldIncludeAnchorForPlayer(MultiverseAnchor anchor, Player player) {
|
||||
return worldManager.getWorld(anchor.getLocationWorld())
|
||||
.map(mvWorld -> entryCheckerProvider.forSender(player).canAccessWorld(mvWorld))
|
||||
.peek(result -> Logging.finer("Result for %s can access anchor %s: %s", player.getName(), anchor.getName(), result))
|
||||
.map(Result::isSuccess)
|
||||
.getOrElse(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the specified anchor.
|
||||
*
|
||||
* @param anchor The anchor to delete.
|
||||
* @return True if the anchor was successfully deleted.
|
||||
*/
|
||||
public Try<Void> deleteAnchor(@NotNull MultiverseAnchor anchor) {
|
||||
if (anchors.containsKey(anchor.getName())) {
|
||||
anchors.remove(anchor.getName());
|
||||
getAnchorsConfigSection().set(anchor.getName(), null);
|
||||
return saveAllAnchors();
|
||||
}
|
||||
return Try.failure(new IllegalArgumentException("Anchor does not exist"));
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.anchor;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.mvplugins.multiverse.core.world.location.UnloadedWorldLocation;
|
||||
|
||||
/**
|
||||
* Represents a single anchor location.
|
||||
*/
|
||||
public final class MultiverseAnchor {
|
||||
|
||||
private final String name;
|
||||
private UnloadedWorldLocation location;
|
||||
|
||||
MultiverseAnchor(String name, UnloadedWorldLocation location) {
|
||||
this.name = name;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the anchor.
|
||||
*
|
||||
* @return The name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a copy of the anchor's location.
|
||||
*
|
||||
* @return The location.
|
||||
*/
|
||||
public Location getLocation() {
|
||||
return location.toBukkitLocation();
|
||||
}
|
||||
|
||||
void setLocation(Location location) {
|
||||
this.location = new UnloadedWorldLocation(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world of the anchor's location.
|
||||
*
|
||||
* @return The world.
|
||||
*/
|
||||
@Nullable World getLocationWorld() {
|
||||
if (location == null) {
|
||||
return null;
|
||||
}
|
||||
return location.getWorld();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* this package contains the classes that are used for the anchor system.
|
||||
*/
|
||||
package org.mvplugins.multiverse.core.anchor;
|
||||
@@ -1,7 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
/**
|
||||
* Extends a command class to add legacy alias annotations.
|
||||
*/
|
||||
public interface LegacyAliasCommand {
|
||||
}
|
||||
@@ -1,364 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import co.aikar.commands.BukkitCommandCompletionContext;
|
||||
import co.aikar.commands.CommandIssuer;
|
||||
import co.aikar.commands.PaperCommandCompletions;
|
||||
import co.aikar.commands.RegisteredCommand;
|
||||
import co.aikar.commands.RootCommand;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import io.vavr.control.Option;
|
||||
import io.vavr.control.Try;
|
||||
import jakarta.inject.Inject;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Difficulty;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.GameRule;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.SpawnCategory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.anchor.AnchorManager;
|
||||
import org.mvplugins.multiverse.core.anchor.MultiverseAnchor;
|
||||
import org.mvplugins.multiverse.core.command.context.issueraware.IssuerAwareValue;
|
||||
import org.mvplugins.multiverse.core.command.context.issueraware.MultiverseWorldValue;
|
||||
import org.mvplugins.multiverse.core.command.context.issueraware.PlayerArrayValue;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.config.node.functions.DefaultSuggesterProvider;
|
||||
import org.mvplugins.multiverse.core.config.handle.PropertyModifyAction;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationInstance;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationSuggestionPacket;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationsProvider;
|
||||
import org.mvplugins.multiverse.core.destination.core.WorldDestination;
|
||||
import org.mvplugins.multiverse.core.permissions.CorePermissionsChecker;
|
||||
import org.mvplugins.multiverse.core.utils.REPatterns;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.generators.GeneratorPlugin;
|
||||
import org.mvplugins.multiverse.core.world.generators.GeneratorProvider;
|
||||
|
||||
import static org.mvplugins.multiverse.core.utils.StringFormatter.addonToCommaSeperated;
|
||||
|
||||
@Service
|
||||
public class MVCommandCompletions extends PaperCommandCompletions {
|
||||
|
||||
private final MVCommandManager commandManager;
|
||||
private final WorldManager worldManager;
|
||||
private final DestinationsProvider destinationsProvider;
|
||||
private final CoreConfig config;
|
||||
private final CorePermissionsChecker corePermissionsChecker;
|
||||
private final AnchorManager anchorManager;
|
||||
private final GeneratorProvider generatorProvider;
|
||||
|
||||
@Inject
|
||||
MVCommandCompletions(
|
||||
@NotNull MVCommandManager mvCommandManager,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull DestinationsProvider destinationsProvider,
|
||||
@NotNull CoreConfig config,
|
||||
@NotNull CorePermissionsChecker corePermissionsChecker,
|
||||
@NotNull AnchorManager anchorManager,
|
||||
@NotNull GeneratorProvider generatorProvider
|
||||
) {
|
||||
super(mvCommandManager);
|
||||
this.commandManager = mvCommandManager;
|
||||
this.worldManager = worldManager;
|
||||
this.destinationsProvider = destinationsProvider;
|
||||
this.config = config;
|
||||
this.corePermissionsChecker = corePermissionsChecker;
|
||||
this.anchorManager = anchorManager;
|
||||
this.generatorProvider = generatorProvider;
|
||||
|
||||
registerAsyncCompletion("anchornames", this::suggestAnchorNames);
|
||||
registerAsyncCompletion("commands", this::suggestCommands);
|
||||
registerAsyncCompletion("destinations", this::suggestDestinations);
|
||||
registerStaticCompletion("difficulties", suggestEnums(Difficulty.class));
|
||||
registerStaticCompletion("environments", List.of("normal", "nether", "the_end")); // Don't tab complete the "custom" environment
|
||||
registerAsyncCompletion("flags", this::suggestFlags);
|
||||
registerStaticCompletion("gamemodes", suggestEnums(GameMode.class));
|
||||
registerStaticCompletion("gamerules", this::suggestGamerules);
|
||||
registerAsyncCompletion("gamerulesvalues", this::suggestGamerulesValues);
|
||||
registerAsyncCompletion("generatorplugins", this::suggestGeneratorPlugins);
|
||||
registerStaticCompletion("materials", suggestEnums(Material.class));
|
||||
registerStaticCompletion("mvconfigs", config.getStringPropertyHandle().getAllPropertyNames());
|
||||
registerAsyncCompletion("mvconfigvalues", this::suggestMVConfigValues);
|
||||
registerAsyncCompletion("mvworlds", this::suggestMVWorlds);
|
||||
registerAsyncCompletion("mvworldpropsname", this::suggestMVWorldPropsName);
|
||||
registerAsyncCompletion("mvworldpropsvalue", this::suggestMVWorldPropsValue);
|
||||
registerCompletion("playersarray", this::suggestPlayersArray); // getting online players cannot be async
|
||||
registerStaticCompletion("propsmodifyaction", suggestEnums(PropertyModifyAction.class));
|
||||
registerStaticCompletion("spawncategories", suggestEnums(SpawnCategory.class));
|
||||
registerAsyncCompletion("spawncategorypropsname", this::suggestSpawnCategoryPropsName);
|
||||
registerAsyncCompletion("spawncategorypropsvalue", this::suggestSpawnCategoryPropsValue);
|
||||
|
||||
setDefaultCompletion("destinations", DestinationInstance.class);
|
||||
setDefaultCompletion("difficulties", Difficulty.class);
|
||||
setDefaultCompletion("environments", World.Environment.class);
|
||||
setDefaultCompletion("flags", String[].class);
|
||||
setDefaultCompletion("gamemodes", GameMode.class);
|
||||
setDefaultCompletion("gamerules", GameRule.class);
|
||||
setDefaultCompletion("mvworlds", LoadedMultiverseWorld.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<BukkitCommandCompletionContext> handler) {
|
||||
return super.registerCompletion(id, context ->
|
||||
completeWithPreconditions(context, handler));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<BukkitCommandCompletionContext> handler) {
|
||||
return super.registerAsyncCompletion(id, context ->
|
||||
completeWithPreconditions(context, handler));
|
||||
}
|
||||
|
||||
private Collection<String> completeWithPreconditions(
|
||||
BukkitCommandCompletionContext context,
|
||||
CommandCompletionHandler<BukkitCommandCompletionContext> handler) {
|
||||
if (context.hasConfig("playerOnly") && !context.getIssuer().isPlayer()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (context.hasConfig("byIssuerForArg")) {
|
||||
Boolean byIssuerForArg = Try.of(() -> context.getContextValueByName(IssuerAwareValue.class, context.getConfig("byIssuerForArg")))
|
||||
.map(IssuerAwareValue::isByIssuer)
|
||||
.getOrElse(false);
|
||||
if (!byIssuerForArg) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
if (context.hasConfig("notByIssuerForArg")) {
|
||||
Boolean byIssuerForArg = Try.of(() -> context.getContextValueByName(IssuerAwareValue.class, context.getConfig("notByIssuerForArg")))
|
||||
.map(IssuerAwareValue::isByIssuer)
|
||||
.getOrElse(false);
|
||||
if (byIssuerForArg) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
if (context.hasConfig("resolveUntil")) {
|
||||
if (!Try.run(() -> context.getContextValueByName(Object.class, context.getConfig("resolveUntil"))).isSuccess()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
if (context.hasConfig("checkPermissions")) {
|
||||
for (String permission : REPatterns.SEMICOLON.split(context.getConfig("checkPermissions"))) {
|
||||
if (!commandManager.getCommandPermissions().hasPermission(context.getIssuer(), permission)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (context.hasConfig("multiple")) {
|
||||
return addonToCommaSeperated(context.getInput(), handler.getCompletions(context));
|
||||
}
|
||||
return handler.getCompletions(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to suggest enums values
|
||||
*
|
||||
* @param enumClass The enum class with values
|
||||
* @return A collection of possible string values
|
||||
* @param <T> The enum type
|
||||
*/
|
||||
public <T extends Enum<T>> Collection<String> suggestEnums(Class<T> enumClass) {
|
||||
return EnumSet.allOf(enumClass).stream()
|
||||
.map(Enum::name)
|
||||
.map(name -> name.toLowerCase(Locale.ENGLISH))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private Collection<String> suggestAnchorNames(BukkitCommandCompletionContext context) {
|
||||
return anchorManager.getAnchors(context.getPlayer()).stream()
|
||||
.map(MultiverseAnchor::getName)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private Collection<String> suggestCommands(BukkitCommandCompletionContext context) {
|
||||
String rootCmdName = context.getConfig();
|
||||
if (rootCmdName == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
RootCommand rootCommand = this.commandManager.getRegisteredRootCommands().stream()
|
||||
.unordered()
|
||||
.filter(c -> c.getCommandName().equals(rootCmdName))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (rootCommand == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return rootCommand.getSubCommands().entries().stream()
|
||||
.filter(entry -> checkPerms(context.getIssuer(), entry.getValue()))
|
||||
.map(Map.Entry::getKey)
|
||||
.filter(cmdName -> !cmdName.startsWith("__"))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private boolean checkPerms(CommandIssuer issuer, RegisteredCommand<?> command) {
|
||||
return this.commandManager.hasPermission(issuer, command.getRequiredPermissions());
|
||||
}
|
||||
|
||||
private Collection<String> suggestDestinations(BukkitCommandCompletionContext context) {
|
||||
return Try.of(() -> context.getContextValue(PlayerArrayValue.class))
|
||||
.map(PlayerArrayValue::value)
|
||||
.recover(IllegalStateException.class, e -> context.getContextValue(Player[].class))
|
||||
.recover(IllegalStateException.class, e -> new Player[]{context.getContextValue(Player.class)})
|
||||
.map(players -> {
|
||||
if (players.length == 0) {
|
||||
// Most likely console did not specify a player
|
||||
return Collections.<String>emptyList();
|
||||
}
|
||||
CommandSender sender = context.getIssuer().getIssuer();
|
||||
if (context.hasConfig("othersOnly") && (players.length == 1 && players[0].equals(sender))) {
|
||||
return Collections.<String>emptyList();
|
||||
}
|
||||
return suggestDestinationsWithPerms(sender, Arrays.asList(players), context.getInput());
|
||||
})
|
||||
.getOrElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private Collection<String> suggestDestinationsWithPerms(CommandSender teleporter, List<Entity> teleportees, String deststring) {
|
||||
return destinationsProvider.suggestDestinations(teleporter, deststring).stream()
|
||||
.filter(packet -> !config.getSimplifiedDestinationTabCompletion()
|
||||
|| packet.destination() instanceof WorldDestination
|
||||
|| deststring.startsWith(packet.destination().getIdentifier() + ":"))
|
||||
.filter(packet -> corePermissionsChecker
|
||||
.checkDestinationPacketPermission(teleporter, teleportees, packet))
|
||||
.map(DestinationSuggestionPacket::parsableString)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private Collection<String> suggestFlags(@NotNull BukkitCommandCompletionContext context) {
|
||||
String groupName = context.getConfig("groupName", "");
|
||||
|
||||
return Try.of(() -> context.getContextValue(String[].class))
|
||||
.map(flags -> commandManager.getFlagsManager().suggest(groupName, flags))
|
||||
.getOrElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private Collection<String> suggestGamerules() {
|
||||
return Arrays.stream(GameRule.values()).map(GameRule::getName).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Collection<String> suggestGamerulesValues(BukkitCommandCompletionContext context) {
|
||||
return Try.of(() -> context.getContextValue(GameRule.class))
|
||||
// Just use our suggester from configuration lib since gamerules are only boolean or int
|
||||
.mapTry(gamerule -> Option.of(DefaultSuggesterProvider.getDefaultSuggester(gamerule.getType()))
|
||||
.map(s -> s.suggest(context.getInput())).getOrElse(Collections.emptyList()))
|
||||
.getOrElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private Collection<String> suggestGeneratorPlugins(BukkitCommandCompletionContext context) {
|
||||
return generatorProvider.getRegisteredGeneratorPlugins().stream()
|
||||
.map(GeneratorPlugin::getPluginName)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private Collection<String> suggestMVConfigValues(BukkitCommandCompletionContext context) {
|
||||
return Try.of(() -> context.getContextValue(String.class))
|
||||
.map(propertyName -> config.getStringPropertyHandle()
|
||||
.getSuggestedPropertyValue(propertyName, context.getInput(), PropertyModifyAction.SET, context.getSender()))
|
||||
.getOrElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private Collection<String> suggestMVWorlds(BukkitCommandCompletionContext context) {
|
||||
String scope = context.getConfig("scope", "loaded");
|
||||
switch (scope) {
|
||||
case "both" -> {
|
||||
return worldManager.getWorlds().stream()
|
||||
.map(MultiverseWorld::getTabCompleteName)
|
||||
.toList();
|
||||
}
|
||||
case "loaded" -> {
|
||||
return worldManager.getLoadedWorlds().stream()
|
||||
.map(MultiverseWorld::getTabCompleteName)
|
||||
.toList();
|
||||
}
|
||||
case "unloaded" -> {
|
||||
return worldManager.getUnloadedWorlds().stream()
|
||||
.map(MultiverseWorld::getTabCompleteName)
|
||||
.toList();
|
||||
}
|
||||
case "potential" -> {
|
||||
return worldManager.getPotentialWorlds();
|
||||
}
|
||||
}
|
||||
Logging.severe("Invalid MVWorld scope: " + scope);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private Collection<String> suggestMVWorldPropsName(BukkitCommandCompletionContext context) {
|
||||
return Try.of(() -> {
|
||||
MultiverseWorld world = context.getContextValue(MultiverseWorldValue.class).value();
|
||||
PropertyModifyAction action = context.getContextValue(PropertyModifyAction.class);
|
||||
return world.getStringPropertyHandle().getModifiablePropertyNames(action);
|
||||
}).getOrElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private Collection<String> suggestMVWorldPropsValue(BukkitCommandCompletionContext context) {
|
||||
return Try.of(() -> {
|
||||
MultiverseWorld world = context.getContextValue(MultiverseWorldValue.class).value();
|
||||
PropertyModifyAction action = context.getContextValue(PropertyModifyAction.class);
|
||||
String propertyName = context.getContextValue(String.class);
|
||||
return world.getStringPropertyHandle().getSuggestedPropertyValue(propertyName, context.getInput(), action, context.getSender());
|
||||
}).getOrElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private Collection<String> suggestPlayersArray(BukkitCommandCompletionContext context) {
|
||||
CommandSender sender = context.getSender();
|
||||
Validate.notNull(sender, "Sender cannot be null");
|
||||
Player senderPlayer = sender instanceof Player ? (Player)sender : null;
|
||||
List<String> matchedPlayers = new ArrayList<>();
|
||||
|
||||
for(Player player : Bukkit.getOnlinePlayers()) {
|
||||
String name = player.getName();
|
||||
if ((senderPlayer == null || senderPlayer.canSee(player))
|
||||
&& (!context.hasConfig("excludeSelf") || !player.equals(senderPlayer))) {
|
||||
matchedPlayers.add(name);
|
||||
}
|
||||
}
|
||||
return addonToCommaSeperated(context.getInput(), matchedPlayers);
|
||||
}
|
||||
|
||||
private Collection<String> suggestSpawnCategoryPropsName(BukkitCommandCompletionContext context) {
|
||||
return Try.of(() -> {
|
||||
MultiverseWorld world = context.getContextValue(MultiverseWorld.class);
|
||||
SpawnCategory spawnCategory = context.getContextValue(SpawnCategory.class);
|
||||
PropertyModifyAction action = context.getContextValue(PropertyModifyAction.class);
|
||||
return world.getEntitySpawnConfig()
|
||||
.getSpawnCategoryConfig(spawnCategory)
|
||||
.getStringPropertyHandle()
|
||||
.getModifiablePropertyNames(action);
|
||||
}).getOrElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private Collection<String> suggestSpawnCategoryPropsValue(BukkitCommandCompletionContext context) {
|
||||
return Try.of(() -> {
|
||||
MultiverseWorld world = context.getContextValue(MultiverseWorld.class);
|
||||
SpawnCategory spawnCategory = context.getContextValue(SpawnCategory.class);
|
||||
PropertyModifyAction action = context.getContextValue(PropertyModifyAction.class);
|
||||
String propertyName = context.getContextValue(String.class);
|
||||
return world.getEntitySpawnConfig()
|
||||
.getSpawnCategoryConfig(spawnCategory)
|
||||
.getStringPropertyHandle()
|
||||
.getSuggestedPropertyValue(propertyName, context.getInput(), action, context.getSender());
|
||||
}).getOrElse(Collections.emptyList());
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import co.aikar.commands.BukkitCommandExecutionContext;
|
||||
import co.aikar.commands.BukkitCommandIssuer;
|
||||
import co.aikar.commands.BukkitConditionContext;
|
||||
import co.aikar.commands.CommandConditions;
|
||||
import co.aikar.commands.ConditionContext;
|
||||
import co.aikar.commands.ConditionFailedException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.helpers.WorldNameChecker;
|
||||
|
||||
public class MVCommandConditions {
|
||||
static void load(
|
||||
@NotNull MVCommandManager commandManager,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull WorldNameChecker worldNameChecker) {
|
||||
MVCommandConditions mvCommandConditions = new MVCommandConditions(commandManager, worldManager, worldNameChecker);
|
||||
mvCommandConditions.registerConditions();
|
||||
}
|
||||
|
||||
private final WorldManager worldManager;
|
||||
private final MVCommandManager commandManager;
|
||||
private final WorldNameChecker worldNameChecker;
|
||||
|
||||
private MVCommandConditions(
|
||||
@NotNull MVCommandManager commandManager,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull WorldNameChecker worldNameChecker) {
|
||||
this.worldManager = worldManager;
|
||||
this.commandManager = commandManager;
|
||||
this.worldNameChecker = worldNameChecker;
|
||||
}
|
||||
|
||||
private void registerConditions() {
|
||||
CommandConditions<BukkitCommandIssuer, BukkitCommandExecutionContext, BukkitConditionContext> conditions
|
||||
= commandManager.getCommandConditions();
|
||||
|
||||
conditions.addCondition(String.class, "worldname", this::checkWorldname);
|
||||
}
|
||||
|
||||
private void checkWorldname(
|
||||
ConditionContext<BukkitCommandIssuer> context,
|
||||
BukkitCommandExecutionContext executionContext,
|
||||
String worldName) {
|
||||
String scope = context.getConfigValue("scope", "loaded");
|
||||
|
||||
switch (scope) {
|
||||
// Worlds that are loaded
|
||||
case "loaded":
|
||||
if (!this.worldManager.isLoadedWorld(worldName)) {
|
||||
throw new ConditionFailedException("World with name '" + worldName + "' does not exist or is not loaded!");
|
||||
}
|
||||
break;
|
||||
// Worlds that are unloaded
|
||||
case "unloaded":
|
||||
if (!this.worldManager.isUnloadedWorld(worldName)) {
|
||||
if (this.worldManager.isLoadedWorld(worldName)) {
|
||||
throw new ConditionFailedException("World with name '" + worldName + "' is loaded already!");
|
||||
}
|
||||
throw new ConditionFailedException("World with name '" + worldName + "' does not exist!");
|
||||
}
|
||||
break;
|
||||
// World that are loaded or unloaded
|
||||
case "both":
|
||||
if (!this.worldManager.isWorld(worldName)) {
|
||||
throw new ConditionFailedException("World with name '" + worldName + "' does not exist!");
|
||||
}
|
||||
break;
|
||||
// World that are does not exist
|
||||
case "new":
|
||||
if (this.worldManager.isWorld(worldName)) {
|
||||
throw new ConditionFailedException("World with name '" + worldName + "' already exists!");
|
||||
}
|
||||
switch (worldNameChecker.checkName(worldName)) {
|
||||
case INVALID_CHARS ->
|
||||
throw new ConditionFailedException("World name '" + worldName + "' contains invalid characters!");
|
||||
case BLACKLISTED ->
|
||||
throw new ConditionFailedException("World name '" + worldName + "' is used for critical server operations and is blacklisted!");
|
||||
}
|
||||
break;
|
||||
// Probably a typo happened here
|
||||
default:
|
||||
throw new ConditionFailedException("Unknown scope '" + scope + "'!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,396 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import co.aikar.commands.ACFUtil;
|
||||
import co.aikar.commands.BukkitCommandExecutionContext;
|
||||
import co.aikar.commands.BukkitCommandIssuer;
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import co.aikar.commands.MinecraftMessageKeys;
|
||||
import co.aikar.commands.PaperCommandContexts;
|
||||
import co.aikar.commands.contexts.ContextResolver;
|
||||
import com.google.common.base.Strings;
|
||||
import io.vavr.control.Option;
|
||||
import io.vavr.control.Try;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameRule;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.BlockCommandSender;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.SpawnCategory;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.anchor.AnchorManager;
|
||||
import org.mvplugins.multiverse.core.anchor.MultiverseAnchor;
|
||||
import org.mvplugins.multiverse.core.command.context.GameRuleValue;
|
||||
import org.mvplugins.multiverse.core.command.context.issueraware.IssuerAwareContextBuilder;
|
||||
import org.mvplugins.multiverse.core.command.context.PlayerLocation;
|
||||
import org.mvplugins.multiverse.core.command.context.issueraware.MultiverseWorldValue;
|
||||
import org.mvplugins.multiverse.core.command.context.issueraware.PlayerArrayValue;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationInstance;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationsProvider;
|
||||
import org.mvplugins.multiverse.core.display.filters.ContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.filters.DefaultContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.filters.RegexContentFilter;
|
||||
import org.mvplugins.multiverse.core.exceptions.command.MVInvalidCommandArgument;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
import org.mvplugins.multiverse.core.utils.PlayerFinder;
|
||||
import org.mvplugins.multiverse.core.utils.REPatterns;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.generators.GeneratorPlugin;
|
||||
import org.mvplugins.multiverse.core.world.generators.GeneratorProvider;
|
||||
|
||||
@Service
|
||||
public class MVCommandContexts extends PaperCommandContexts {
|
||||
|
||||
private final MVCommandManager mvCommandManager;
|
||||
private final DestinationsProvider destinationsProvider;
|
||||
private final WorldManager worldManager;
|
||||
private final CoreConfig config;
|
||||
private final AnchorManager anchorManager;
|
||||
private final GeneratorProvider generatorProvider;
|
||||
|
||||
@Inject
|
||||
MVCommandContexts(
|
||||
MVCommandManager mvCommandManager,
|
||||
DestinationsProvider destinationsProvider,
|
||||
WorldManager worldManager,
|
||||
CoreConfig config,
|
||||
AnchorManager anchorManager,
|
||||
GeneratorProvider generatorProvider
|
||||
) {
|
||||
super(mvCommandManager);
|
||||
this.mvCommandManager = mvCommandManager;
|
||||
this.destinationsProvider = destinationsProvider;
|
||||
this.worldManager = worldManager;
|
||||
this.config = config;
|
||||
this.anchorManager = anchorManager;
|
||||
this.generatorProvider = generatorProvider;
|
||||
|
||||
registerIssuerOnlyContext(BukkitCommandIssuer.class, BukkitCommandExecutionContext::getIssuer);
|
||||
registerIssuerOnlyContext(MVCommandIssuer.class, this::parseMVCommandIssuer);
|
||||
registerOptionalContext(ContentFilter.class, this::parseContentFilter);
|
||||
registerContext(DestinationInstance.class, this::parseDestination);
|
||||
registerContext(GameRule.class, this::parseGameRule);
|
||||
registerContext(GameRuleValue.class, this::parseGameRuleValue);
|
||||
registerContext(GeneratorPlugin.class, this::parseGeneratorPlugin);
|
||||
registerIssuerAwareContext(LoadedMultiverseWorld.class, loadedMultiverseWorldContextBuilder().generateContext());
|
||||
registerIssuerAwareContext(LoadedMultiverseWorld[].class, loadedMultiverseWorldArrayContextBuilder().generateContext());
|
||||
registerIssuerAwareContext(MultiverseWorld.class, multiverseWorldContextBuilder().generateContext());
|
||||
registerIssuerAwareContext(MultiverseWorldValue.class, multiverseWorldContextBuilder().generateContext(MultiverseWorldValue::new));
|
||||
registerIssuerAwareContext(MultiverseWorld[].class, multiverseWorldArrayContextBuilder().generateContext());
|
||||
registerContext(MultiverseAnchor.class, this::parseMultiverseAnchor);
|
||||
registerIssuerAwareContext(Player.class, playerContextBuilder().generateContext());
|
||||
registerIssuerAwareContext(Player[].class, playerArrayContextBuilder().generateContext());
|
||||
registerIssuerAwareContext(PlayerArrayValue.class, playerArrayContextBuilder().generateContext(PlayerArrayValue::new));
|
||||
registerIssuerAwareContext(PlayerLocation.class, this::parsePlayerLocation);
|
||||
registerContext(SpawnCategory[].class, this::parseSpawnCategories);
|
||||
}
|
||||
|
||||
private MVCommandIssuer parseMVCommandIssuer(BukkitCommandExecutionContext context) {
|
||||
if (context.getIssuer() instanceof MVCommandIssuer) {
|
||||
return (MVCommandIssuer) context.getIssuer();
|
||||
}
|
||||
return mvCommandManager.getCommandIssuer(context.getSender());
|
||||
}
|
||||
|
||||
private ContentFilter parseContentFilter(BukkitCommandExecutionContext context) {
|
||||
if (Strings.isNullOrEmpty(context.getFirstArg())) {
|
||||
return DefaultContentFilter.get();
|
||||
}
|
||||
String filterString = context.popFirstArg();
|
||||
return RegexContentFilter.fromString(filterString);
|
||||
}
|
||||
|
||||
private DestinationInstance<?, ?> parseDestination(BukkitCommandExecutionContext context) {
|
||||
String destination = context.popFirstArg();
|
||||
if (Strings.isNullOrEmpty(destination)) {
|
||||
throw new InvalidCommandArgument("No destination specified.");
|
||||
}
|
||||
|
||||
return destinationsProvider.parseDestination(context.getSender(), destination)
|
||||
.getOrThrow(failure ->
|
||||
new InvalidCommandArgument(failure.getFailureMessage().formatted(context.getIssuer())));
|
||||
}
|
||||
|
||||
private GameRule<?> parseGameRule(BukkitCommandExecutionContext context) {
|
||||
String gameRuleName = context.popFirstArg();
|
||||
if (Strings.isNullOrEmpty(gameRuleName)) {
|
||||
throw new InvalidCommandArgument("No game rule specified.");
|
||||
}
|
||||
|
||||
GameRule<?> gameRule = GameRule.getByName(gameRuleName);
|
||||
if (gameRule == null) {
|
||||
throw new InvalidCommandArgument("The game rule " + gameRuleName + " is not valid.");
|
||||
}
|
||||
|
||||
return gameRule;
|
||||
}
|
||||
|
||||
private GameRuleValue parseGameRuleValue(BukkitCommandExecutionContext context) {
|
||||
GameRule<?> gameRule = (GameRule<?>) context.getResolvedArg(GameRule.class);
|
||||
if (gameRule == null) {
|
||||
throw new InvalidCommandArgument("No game rule specified.");
|
||||
}
|
||||
String valueString = context.getFirstArg();
|
||||
if (Strings.isNullOrEmpty(valueString)) {
|
||||
throw new InvalidCommandArgument("No game rule value specified.");
|
||||
}
|
||||
|
||||
ContextResolver<?, BukkitCommandExecutionContext> resolver = getResolver(gameRule.getType());
|
||||
if (resolver == null) {
|
||||
return new GameRuleValue(valueString);
|
||||
}
|
||||
|
||||
Object resolvedValue = resolver.getContext(context);
|
||||
if (resolvedValue == null) {
|
||||
throw new InvalidCommandArgument("The game rule value " + valueString + " is not valid for game rule " + gameRule.getName() + ".");
|
||||
}
|
||||
|
||||
return new GameRuleValue(resolvedValue);
|
||||
}
|
||||
|
||||
private GeneratorPlugin parseGeneratorPlugin(BukkitCommandExecutionContext context) {
|
||||
GeneratorPlugin generatorPlugin = generatorProvider.getGeneratorPlugin(context.popFirstArg());
|
||||
if (generatorPlugin == null) {
|
||||
throw new InvalidCommandArgument("Invalid generator plugin: " + context.getFirstArg());
|
||||
}
|
||||
return generatorPlugin;
|
||||
}
|
||||
|
||||
|
||||
private IssuerAwareContextBuilder<LoadedMultiverseWorld> loadedMultiverseWorldContextBuilder() {
|
||||
return new IssuerAwareContextBuilder<LoadedMultiverseWorld>()
|
||||
.fromPlayer((context, player) -> worldManager.getLoadedWorld(player.getWorld()).getOrNull())
|
||||
.fromInput((context, input) -> getLoadedMultiverseWorld(input))
|
||||
.issuerOnlyFailMessage((context) -> Message.of("This command can only be used by a player in a loaded Multiverse World."))
|
||||
.issuerAwarePlayerFailMessage((context, player) -> Message.of("You are not in a loaded multiverse world. Either specify a multiverse world name or use this command in a loaded multiverse world."))
|
||||
.issuerAwareInputFailMessage((context, input) -> Message.of("World '" + input + "' is not a loaded multiverse world. Remember to specify the world name when using this command in console."))
|
||||
.inputOnlyFailMessage((context, input) -> Message.of("World " + input + " is not a loaded multiverse world."));
|
||||
}
|
||||
|
||||
private IssuerAwareContextBuilder<LoadedMultiverseWorld[]> loadedMultiverseWorldArrayContextBuilder() {
|
||||
return new IssuerAwareContextBuilder<LoadedMultiverseWorld[]>()
|
||||
.fromPlayer((context, player) -> worldManager.getLoadedWorld(player.getWorld())
|
||||
.map(world -> new LoadedMultiverseWorld[]{world})
|
||||
.getOrNull())
|
||||
.fromInput((context, input) -> {
|
||||
String[] worldNames = input == null ? new String[0] : REPatterns.COMMA.split(input);
|
||||
Set<LoadedMultiverseWorld> worlds = new HashSet<>(worldNames.length);
|
||||
for (String worldName : worldNames) {
|
||||
if ("*".equals(worldName)) {
|
||||
worlds.addAll(worldManager.getLoadedWorlds());
|
||||
break;
|
||||
}
|
||||
LoadedMultiverseWorld world = getLoadedMultiverseWorld(worldName);
|
||||
if (world == null) {
|
||||
throw new InvalidCommandArgument("World " + worldName + " is not a loaded multiverse world.");
|
||||
}
|
||||
worlds.add(world);
|
||||
}
|
||||
return worlds.isEmpty() ? null : worlds.toArray(new LoadedMultiverseWorld[0]);
|
||||
})
|
||||
.issuerOnlyFailMessage((context) -> Message.of("This command can only be used by a player in a loaded Multiverse World."))
|
||||
.issuerAwarePlayerFailMessage((context, player) -> Message.of("You are not in a loaded multiverse world. Either specify a multiverse world name or use this command in a loaded multiverse world."))
|
||||
.issuerAwareInputFailMessage((context, input) -> Message.of("World '" + input + "' is not a loaded multiverse world. Remember to specify the world name when using this command in console."))
|
||||
.inputOnlyFailMessage((context, input) -> Message.of("World " + input + " is not a loaded multiverse world."));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private LoadedMultiverseWorld getLoadedMultiverseWorld(String worldName) {
|
||||
return config.getResolveAliasName()
|
||||
? worldManager.getLoadedWorldByNameOrAlias(worldName).getOrNull()
|
||||
: worldManager.getLoadedWorld(worldName).getOrNull();
|
||||
}
|
||||
|
||||
private IssuerAwareContextBuilder<MultiverseWorld> multiverseWorldContextBuilder() {
|
||||
return new IssuerAwareContextBuilder<MultiverseWorld>()
|
||||
.fromPlayer((context, player) -> worldManager.getWorld(player.getWorld()).getOrNull())
|
||||
.fromInput((context, input) -> getMultiverseWorld(input))
|
||||
.issuerOnlyFailMessage((context) -> Message.of("This command can only be used by a player in a Multiverse World."))
|
||||
.issuerAwarePlayerFailMessage((context, player) -> Message.of("You are not in a multiverse world. Either specify a multiverse world name or use this command in a multiverse world."))
|
||||
.issuerAwareInputFailMessage((context, input) -> Message.of("World '" + input + "' is not a multiverse world. Remember to specify the world name when using this command in console."))
|
||||
.inputOnlyFailMessage((context, input) -> Message.of("World " + input + " is not a multiverse world."));
|
||||
}
|
||||
|
||||
private IssuerAwareContextBuilder<MultiverseWorld[]> multiverseWorldArrayContextBuilder() {
|
||||
return new IssuerAwareContextBuilder<MultiverseWorld[]>()
|
||||
.fromPlayer((context, player) -> worldManager.getWorld(player.getWorld())
|
||||
.map(world -> new MultiverseWorld[]{world})
|
||||
.getOrNull())
|
||||
.fromInput((context, input) -> {
|
||||
String[] worldNames = input == null ? new String[0] : REPatterns.COMMA.split(input);
|
||||
Set<MultiverseWorld> worlds = new HashSet<>(worldNames.length);
|
||||
for (String worldName : worldNames) {
|
||||
if ("*".equals(worldName)) {
|
||||
worlds.addAll(worldManager.getWorlds());
|
||||
break;
|
||||
}
|
||||
MultiverseWorld world = getMultiverseWorld(worldName);
|
||||
if (world == null) {
|
||||
throw new InvalidCommandArgument("World " + worldName + " is not a multiverse world.");
|
||||
}
|
||||
worlds.add(world);
|
||||
}
|
||||
return worlds.isEmpty() ? null : worlds.toArray(new MultiverseWorld[0]);
|
||||
})
|
||||
.issuerOnlyFailMessage((context) -> Message.of("This command can only be used by a player in a Multiverse World."))
|
||||
.issuerAwarePlayerFailMessage((context, player) -> Message.of("You are not in a multiverse world. Either specify a multiverse world name or use this command in a multiverse world."))
|
||||
.issuerAwareInputFailMessage((context, input) -> Message.of("World '" + input + "' is not a multiverse world. Remember to specify the world name when using this command in console."))
|
||||
.inputOnlyFailMessage((context, input) -> Message.of("World " + input + " is not a multiverse world."));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private MultiverseWorld getMultiverseWorld(String worldName) {
|
||||
return config.getResolveAliasName()
|
||||
? worldManager.getWorldByNameOrAlias(worldName).getOrNull()
|
||||
: worldManager.getWorld(worldName).getOrNull();
|
||||
}
|
||||
|
||||
private MultiverseAnchor parseMultiverseAnchor(BukkitCommandExecutionContext context) {
|
||||
String anchorName = context.popFirstArg();
|
||||
return anchorManager.getAnchor(anchorName)
|
||||
.getOrElseThrow(() -> new InvalidCommandArgument("The anchor '" +anchorName + "' does not exist."));
|
||||
}
|
||||
|
||||
private IssuerAwareContextBuilder<Player> playerContextBuilder() {
|
||||
return new IssuerAwareContextBuilder<Player>()
|
||||
.fromPlayer((context, player) -> player)
|
||||
.fromInput((context, input) -> PlayerFinder.get(input, context.getSender()))
|
||||
.issuerOnlyFailMessage((context) -> Message.of("This command can only be used by a player."))
|
||||
.issuerAwareInputFailMessage((context, input) -> Message.of("Invalid player: " + input + ". Either specify an online player or use this command as a player."))
|
||||
.inputOnlyFailMessage((context, input) -> Message.of("Player " + input + " not found."));
|
||||
}
|
||||
|
||||
private IssuerAwareContextBuilder<Player[]> playerArrayContextBuilder() {
|
||||
return new IssuerAwareContextBuilder<Player[]>()
|
||||
.fromPlayer((context, player) -> new Player[]{player})
|
||||
.fromInput((context, input) -> PlayerFinder
|
||||
.tryGetMulti(input, context.getSender())
|
||||
.map(list -> list.toArray(new Player[0]))
|
||||
.map(arr -> (arr.length == 0) ? null : arr)
|
||||
.getOrElseThrow(failure -> {
|
||||
if (failure instanceof MVInvalidCommandArgument mvFailure) {
|
||||
throw mvFailure;
|
||||
}
|
||||
throw new InvalidCommandArgument(failure.getLocalizedMessage() + " "
|
||||
+ Option.of(failure.getCause()).map(Throwable::getLocalizedMessage).getOrElse(""));
|
||||
}))
|
||||
.issuerOnlyFailMessage((context) -> Message.of("This command can only be used by a player."))
|
||||
.issuerAwareInputFailMessage((context, input) -> Message.of("Invalid player: " + input + ". Either specify an online player or use this command as a player."))
|
||||
.inputOnlyFailMessage((context, input) -> {
|
||||
if (PlayerFinder.isSelector(input)) {
|
||||
return Message.of("No player(s) matched selector: " + input + ".");
|
||||
}
|
||||
return Message.of("Player(s) " + input + " not found.");
|
||||
});
|
||||
}
|
||||
|
||||
private PlayerLocation parsePlayerLocation(BukkitCommandExecutionContext context) {
|
||||
Try<Location> location = Try.of(() -> parseLocationFromInput(context.getFirstArg(), context.getSender()));
|
||||
|
||||
if (location.isSuccess()) {
|
||||
context.popFirstArg();
|
||||
return new PlayerLocation(location.get());
|
||||
}
|
||||
if (context.getPlayer() != null) {
|
||||
return new PlayerLocation(context.getPlayer().getLocation());
|
||||
}
|
||||
if (context.getFirstArg() == null) {
|
||||
throw new InvalidCommandArgument("You must specify a world location when using this command in console.");
|
||||
}
|
||||
if (location.getCause() instanceof InvalidCommandArgument) {
|
||||
throw (InvalidCommandArgument)location.getCause();
|
||||
}
|
||||
throw new RuntimeException(location.getCause());
|
||||
}
|
||||
|
||||
// copied from ACF
|
||||
private Location parseLocationFromInput(String input, CommandSender sender) {
|
||||
String[] split = REPatterns.COLON.split(input, 2);
|
||||
if (split.length == 0) {
|
||||
throw new InvalidCommandArgument(true);
|
||||
} else if (split.length < 2 && !(sender instanceof Player) && !(sender instanceof BlockCommandSender)) {
|
||||
throw new InvalidCommandArgument(MinecraftMessageKeys.LOCATION_PLEASE_SPECIFY_WORLD, new String[0]);
|
||||
} else {
|
||||
Location sourceLoc = null;
|
||||
String world;
|
||||
String rest;
|
||||
if (split.length == 2) {
|
||||
world = split[0];
|
||||
rest = split[1];
|
||||
} else if (sender instanceof Player) {
|
||||
sourceLoc = ((Player)sender).getLocation();
|
||||
world = sourceLoc.getWorld().getName();
|
||||
rest = split[0];
|
||||
} else {
|
||||
if (!(sender instanceof BlockCommandSender)) {
|
||||
throw new InvalidCommandArgument(true);
|
||||
}
|
||||
|
||||
sourceLoc = ((BlockCommandSender)sender).getBlock().getLocation();
|
||||
world = sourceLoc.getWorld().getName();
|
||||
rest = split[0];
|
||||
}
|
||||
|
||||
boolean rel = rest.startsWith("~");
|
||||
split = REPatterns.COMMA.split(rel ? rest.substring(1) : rest);
|
||||
if (split.length < 3) {
|
||||
throw new InvalidCommandArgument(MinecraftMessageKeys.LOCATION_PLEASE_SPECIFY_XYZ, new String[0]);
|
||||
} else {
|
||||
Double x = ACFUtil.parseDouble(split[0], rel ? (double)0.0F : null);
|
||||
Double y = ACFUtil.parseDouble(split[1], rel ? (double)0.0F : null);
|
||||
Double z = ACFUtil.parseDouble(split[2], rel ? (double)0.0F : null);
|
||||
if (sourceLoc != null && rel) {
|
||||
x = x + sourceLoc.getX();
|
||||
y = y + sourceLoc.getY();
|
||||
z = z + sourceLoc.getZ();
|
||||
} else if (rel) {
|
||||
throw new InvalidCommandArgument(MinecraftMessageKeys.LOCATION_CONSOLE_NOT_RELATIVE, new String[0]);
|
||||
}
|
||||
|
||||
if (x != null && y != null && z != null) {
|
||||
World worldObj = Bukkit.getWorld(world);
|
||||
if (worldObj == null) {
|
||||
throw new InvalidCommandArgument(MinecraftMessageKeys.INVALID_WORLD, new String[0]);
|
||||
} else if (split.length >= 5) {
|
||||
Float yaw = ACFUtil.parseFloat(split[3]);
|
||||
Float pitch = ACFUtil.parseFloat(split[4]);
|
||||
if (pitch != null && yaw != null) {
|
||||
return new Location(worldObj, x, y, z, yaw, pitch);
|
||||
} else {
|
||||
throw new InvalidCommandArgument(MinecraftMessageKeys.LOCATION_PLEASE_SPECIFY_XYZ, new String[0]);
|
||||
}
|
||||
} else {
|
||||
return new Location(worldObj, x, y, z);
|
||||
}
|
||||
} else {
|
||||
throw new InvalidCommandArgument(MinecraftMessageKeys.LOCATION_PLEASE_SPECIFY_XYZ, new String[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SpawnCategory[] parseSpawnCategories(BukkitCommandExecutionContext context) {
|
||||
if (context.isOptional() && context.getArgs().isEmpty()) {
|
||||
return new SpawnCategory[0];
|
||||
}
|
||||
Set<SpawnCategory> categories = new HashSet<>();
|
||||
String[] split = REPatterns.COMMA.split(context.popFirstArg());
|
||||
for (String category : split) {
|
||||
SpawnCategory spawnCategory = ACFUtil.simpleMatch(SpawnCategory.class, category);
|
||||
if (spawnCategory != null) {
|
||||
categories.add(spawnCategory);
|
||||
}
|
||||
}
|
||||
return categories.toArray(new SpawnCategory[0]);
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import co.aikar.commands.BukkitCommandIssuer;
|
||||
import co.aikar.commands.MessageType;
|
||||
import co.aikar.locales.MessageKeyProvider;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement;
|
||||
import org.mvplugins.multiverse.core.utils.text.ChatTextFormatter;
|
||||
|
||||
public class MVCommandIssuer extends BukkitCommandIssuer {
|
||||
|
||||
private final MVCommandManager commandManager;
|
||||
|
||||
MVCommandIssuer(@NotNull MVCommandManager commandManager, @NotNull CommandSender sender) {
|
||||
super(commandManager, sender);
|
||||
this.commandManager = commandManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MVCommandManager getManager() {
|
||||
return commandManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessageInternal(String message) {
|
||||
ChatTextFormatter.sendFormattedMessage(getIssuer(), message);
|
||||
}
|
||||
|
||||
public void sendError(String message, MessageReplacement... replacements) {
|
||||
sendMessage(MessageType.ERROR, message, replacements);
|
||||
}
|
||||
|
||||
public void sendSyntax(String message, MessageReplacement... replacements) {
|
||||
sendMessage(MessageType.SYNTAX, message, replacements);
|
||||
}
|
||||
|
||||
public void sendInfo(String message, MessageReplacement... replacements) {
|
||||
sendMessage(MessageType.INFO, message, replacements);
|
||||
}
|
||||
|
||||
public void sendMessage(String message, MessageReplacement... replacements) {
|
||||
sendMessage(null, Message.of(message, replacements));
|
||||
}
|
||||
|
||||
public void sendMessage(MessageType type, String message, MessageReplacement... replacements) {
|
||||
sendMessage(type, Message.of(message, replacements));
|
||||
}
|
||||
|
||||
public void sendMessage(MessageType messageType, String message) {
|
||||
var formatter = getManager().getFormat(messageType);
|
||||
if (formatter != null) {
|
||||
sendMessage(formatter.format(message));
|
||||
} else {
|
||||
sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendError(MessageKeyProvider key) {
|
||||
sendMessage(MessageType.ERROR, key, new String[0]);
|
||||
}
|
||||
|
||||
public void sendSyntax(MessageKeyProvider key) {
|
||||
sendMessage(MessageType.SYNTAX, key, new String[0]);
|
||||
}
|
||||
|
||||
public void sendInfo(MessageKeyProvider key) {
|
||||
sendMessage(MessageType.INFO, key, new String[0]);
|
||||
}
|
||||
|
||||
public void sendError(MessageKeyProvider key, MessageReplacement... replacements) {
|
||||
sendMessage(MessageType.ERROR, key, replacements);
|
||||
}
|
||||
|
||||
public void sendSyntax(MessageKeyProvider key, MessageReplacement... replacements) {
|
||||
sendMessage(MessageType.SYNTAX, key, replacements);
|
||||
}
|
||||
|
||||
public void sendInfo(MessageKeyProvider key, MessageReplacement... replacements) {
|
||||
sendMessage(MessageType.INFO, key, replacements);
|
||||
}
|
||||
public void sendMessage(MessageKeyProvider key, MessageReplacement... replacements) {
|
||||
sendMessage(null, Message.of(key, replacements));
|
||||
}
|
||||
|
||||
public void sendMessage(MessageType messageType, MessageKeyProvider key, MessageReplacement... replacements) {
|
||||
sendMessage(messageType, Message.of(key, replacements));
|
||||
}
|
||||
|
||||
public void sendError(Message message) {
|
||||
sendMessage(MessageType.ERROR, message);
|
||||
}
|
||||
|
||||
public void sendSyntax(Message message) {
|
||||
sendMessage(MessageType.SYNTAX, message);
|
||||
}
|
||||
|
||||
public void sendInfo(Message message) {
|
||||
sendMessage(MessageType.INFO, message);
|
||||
}
|
||||
|
||||
public void sendMessage(Message message) {
|
||||
sendMessage(null, message);
|
||||
}
|
||||
|
||||
public void sendMessage(MessageType messageType, Message message) {
|
||||
if (message instanceof MessageKeyProvider) {
|
||||
sendMessage(messageType, (MessageKeyProvider) message,
|
||||
message.getReplacements(getManager().getLocales(), this));
|
||||
} else {
|
||||
var formatter = getManager().getFormat(messageType);
|
||||
if (formatter != null) {
|
||||
sendMessage(formatter.format(message.formatted(getManager().getLocales(), this)));
|
||||
} else {
|
||||
sendMessage(message.formatted(getManager().getLocales(), this));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import co.aikar.commands.CommandCompletions;
|
||||
import co.aikar.commands.CommandContexts;
|
||||
import co.aikar.commands.CommandHelp;
|
||||
import co.aikar.commands.CommandIssuer;
|
||||
import co.aikar.commands.HelpEntry;
|
||||
import co.aikar.commands.LogLevel;
|
||||
import co.aikar.commands.PaperCommandManager;
|
||||
import co.aikar.commands.RootCommand;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Provider;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.MultiverseCore;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.queue.CommandQueueManager;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.locale.PluginLocales;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.helpers.WorldNameChecker;
|
||||
|
||||
/**
|
||||
* Main class to manage permissions.
|
||||
*/
|
||||
@Service
|
||||
public class MVCommandManager extends PaperCommandManager {
|
||||
|
||||
private final CommandFlagsManager flagsManager;
|
||||
private final CommandQueueManager commandQueueManager;
|
||||
private final Provider<MVCommandContexts> commandContextsProvider;
|
||||
private final Provider<MVCommandCompletions> commandCompletionsProvider;
|
||||
private final MVCommandPermissions commandPermissions;
|
||||
private final CoreConfig config;
|
||||
private final PluginLocales pluginLocales;
|
||||
|
||||
@Inject
|
||||
MVCommandManager(
|
||||
@NotNull MultiverseCore plugin,
|
||||
@NotNull CommandFlagsManager flagsManager,
|
||||
@NotNull CommandQueueManager commandQueueManager,
|
||||
@NotNull Provider<MVCommandContexts> commandContextsProvider,
|
||||
@NotNull Provider<MVCommandCompletions> commandCompletionsProvider,
|
||||
@NotNull WorldManager worldManager,
|
||||
@NotNull WorldNameChecker worldNameChecker,
|
||||
@NotNull MVCommandPermissions commandPermissions,
|
||||
@NotNull CoreConfig config
|
||||
) {
|
||||
super(plugin);
|
||||
this.flagsManager = flagsManager;
|
||||
this.commandQueueManager = commandQueueManager;
|
||||
this.commandContextsProvider = commandContextsProvider;
|
||||
this.commandCompletionsProvider = commandCompletionsProvider;
|
||||
this.commandPermissions = commandPermissions;
|
||||
this.config = config;
|
||||
this.pluginLocales = new PluginLocales(this);
|
||||
this.locales = this.pluginLocales;
|
||||
this.pluginLocales.loadLanguages();
|
||||
|
||||
MVCommandConditions.load(this, worldManager, worldNameChecker);
|
||||
this.enableUnstableAPI("help");
|
||||
this.setDefaultExceptionHandler(new MVDefaultExceptionHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a list of commands and handles {@link LegacyAliasCommand} based on config option.
|
||||
* @param commands The commands to register
|
||||
* @param <T> The type of the commands
|
||||
*/
|
||||
public <T extends BaseCommand> void registerAllCommands(List<T> commands) {
|
||||
List<T> noLegacy = commands.stream().filter(command -> !(command instanceof LegacyAliasCommand)).toList();
|
||||
if (!config.getShowLegacyAliases()) {
|
||||
noLegacy.forEach(this::registerCommand);
|
||||
return;
|
||||
}
|
||||
|
||||
List<T> legacy = commands.stream().filter(command -> command instanceof LegacyAliasCommand).toList();
|
||||
List<T> noLegacyInheritance = noLegacy.stream()
|
||||
.filter(command -> legacy.stream().noneMatch(
|
||||
legacyAliasCommand -> command.getClass().isAssignableFrom(legacyAliasCommand.getClass())))
|
||||
.toList();
|
||||
|
||||
legacy.forEach(this::registerCommand);
|
||||
noLegacyInheritance.forEach(this::registerCommand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommand(BaseCommand command, boolean force) {
|
||||
if (command instanceof LegacyAliasCommand && !config.getShowLegacyAliases()) {
|
||||
return;
|
||||
}
|
||||
super.registerCommand(command, force);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public PluginLocales getLocales() {
|
||||
return this.pluginLocales;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets class responsible for flag handling.
|
||||
*
|
||||
* @return A not-null {@link CommandFlagsManager}.
|
||||
*/
|
||||
public synchronized @NotNull CommandFlagsManager getFlagsManager() {
|
||||
return flagsManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manager for command that requires /mv confirm before execution.
|
||||
*
|
||||
* @return A non-null {@link CommandQueueManager}.
|
||||
*/
|
||||
public synchronized @NotNull CommandQueueManager getCommandQueueManager() {
|
||||
return commandQueueManager;
|
||||
}
|
||||
|
||||
public synchronized @NotNull MVCommandPermissions getCommandPermissions() {
|
||||
return commandPermissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets class responsible for parsing string args into objects.
|
||||
*
|
||||
* @return A not-null {@link CommandContexts}.
|
||||
*/
|
||||
@Override
|
||||
public synchronized @NotNull MVCommandContexts getCommandContexts() {
|
||||
if (this.contexts == null) {
|
||||
this.contexts = commandContextsProvider.get();
|
||||
}
|
||||
return (MVCommandContexts) this.contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets class responsible for tab-completion handling.
|
||||
*
|
||||
* @return A not-null {@link CommandCompletions}.
|
||||
*/
|
||||
@Override
|
||||
public synchronized @NotNull MVCommandCompletions getCommandCompletions() {
|
||||
if (this.completions == null) {
|
||||
this.completions = commandCompletionsProvider.get();
|
||||
}
|
||||
return (MVCommandCompletions) this.completions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandIssuer issuer, String permission) {
|
||||
return commandPermissions.hasPermission(issuer, permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standardise usage command formatting for all mv modules.
|
||||
*
|
||||
* @param help The target {@link CommandHelp}.
|
||||
*/
|
||||
public void showUsage(@NotNull CommandHelp help) {
|
||||
List<HelpEntry> entries = help.getHelpEntries();
|
||||
if (entries.size() == 1) {
|
||||
getHelpFormatter().showDetailedHelp(help, entries.get(0));
|
||||
return;
|
||||
}
|
||||
help.showHelp();
|
||||
}
|
||||
|
||||
public @NotNull MVCommandIssuer getConsoleCommandIssuer() {
|
||||
return getCommandIssuer(Bukkit.getConsoleSender());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull MVCommandIssuer getCommandIssuer(Object issuer) {
|
||||
if (!(issuer instanceof CommandSender)) {
|
||||
throw new IllegalArgumentException(issuer.getClass().getName() + " is not a Command Issuer.");
|
||||
} else {
|
||||
return new MVCommandIssuer(this, (CommandSender)issuer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RootCommand createRootCommand(String cmd) {
|
||||
return new MVRootCommand(this, cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(LogLevel level, String message, Throwable throwable) {
|
||||
Logging.finer("[%s] %s", level, message);
|
||||
if (throwable != null) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import co.aikar.commands.CommandIssuer;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import io.vavr.control.Option;
|
||||
import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
import org.mvplugins.multiverse.core.permissions.CorePermissionsChecker;
|
||||
import org.mvplugins.multiverse.core.permissions.PermissionUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static org.mvplugins.multiverse.core.permissions.CorePermissionsChecker.*;
|
||||
|
||||
/**
|
||||
* Maps permission checking to custom logic for commands, to allow more complex permission checking.
|
||||
*/
|
||||
@Service
|
||||
public class MVCommandPermissions {
|
||||
private final Map<String, Predicate<CommandIssuer>> permissionsCheckMap;
|
||||
|
||||
@Inject
|
||||
MVCommandPermissions(@NotNull CorePermissionsChecker permissionsChecker) {
|
||||
this.permissionsCheckMap = new HashMap<>();
|
||||
|
||||
registerPermissionChecker("mvteleport", issuer -> permissionsChecker.hasAnyTeleportPermission(issuer.getIssuer()));
|
||||
registerPermissionChecker("mvteleportother", issuer -> permissionsChecker.hasAnyTeleportPermission(issuer.getIssuer(), Scope.OTHER));
|
||||
registerPermissionChecker("mvspawn", issuer -> permissionsChecker.hasAnySpawnPermission(issuer.getIssuer()));
|
||||
registerPermissionChecker("mvspawnother", issuer -> permissionsChecker.hasAnySpawnPermission(issuer.getIssuer(), Scope.OTHER));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a custom permission checker callback. Use `@id-name` in {@link CommandPermission} decorator to use
|
||||
* the callback instead of the default permission string checking.
|
||||
*
|
||||
* @param id The permission id
|
||||
* @param checker The permission checker callback
|
||||
*/
|
||||
public void registerPermissionChecker(String id, Predicate<CommandIssuer> checker) {
|
||||
permissionsCheckMap.put(prepareId(id), checker);
|
||||
}
|
||||
|
||||
private static @NotNull String prepareId(String id) {
|
||||
return (id.startsWith("@") ? "" : "@") + id.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the issuer has the given permission.
|
||||
* @param issuer The issuer
|
||||
* @param permission The permission to check
|
||||
* @return True if the issuer has the permission
|
||||
*/
|
||||
boolean hasPermission(CommandIssuer issuer, String permission) {
|
||||
return Option.of(permissionsCheckMap.get(permission))
|
||||
.map(checker -> checker.test(issuer))
|
||||
.getOrElse(() -> PermissionUtils.hasPermission(issuer.getIssuer(), permission));
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import co.aikar.commands.CommandIssuer;
|
||||
import co.aikar.commands.ExceptionHandler;
|
||||
import co.aikar.commands.RegisteredCommand;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Default handler that will print the stack trace when the command throws an exception.
|
||||
*/
|
||||
public class MVDefaultExceptionHandler implements ExceptionHandler {
|
||||
@Override
|
||||
public boolean execute(BaseCommand command, RegisteredCommand registeredCommand, CommandIssuer sender, List<String> args, Throwable t) {
|
||||
Logging.severe("Failed to execute command /%s %s %s",
|
||||
registeredCommand.getCommand(), registeredCommand.getPrefSubCommand(), String.join(" ", args));
|
||||
t.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import co.aikar.commands.BukkitCommandManager;
|
||||
import co.aikar.commands.BukkitRootCommand;
|
||||
import co.aikar.commands.CommandIssuer;
|
||||
import org.mvplugins.multiverse.core.utils.StringFormatter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MVRootCommand extends BukkitRootCommand {
|
||||
protected MVRootCommand(BukkitCommandManager manager, String name) {
|
||||
super(manager, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseCommand execute(CommandIssuer sender, String commandLabel, String[] args) {
|
||||
String[] quoteFormatedArgs = StringFormatter.parseQuotesInArgs(args).toArray(String[]::new);
|
||||
return super.execute(sender, commandLabel, quoteFormatedArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getTabCompletions(CommandIssuer sender, String alias, String[] args, boolean commandsOnly, boolean isAsync) {
|
||||
String[] quoteFormatedArgs = StringFormatter.parseQuotesInArgs(args).toArray(String[]::new);
|
||||
return super.getTabCompletions(sender, alias, quoteFormatedArgs, commandsOnly, isAsync)
|
||||
.stream()
|
||||
.map(StringFormatter::quoteMultiWordString)
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Contract;
|
||||
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagGroup;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
|
||||
/**
|
||||
* Base class for all Multiverse commands.
|
||||
*/
|
||||
@Contract
|
||||
public abstract class MultiverseCommand extends BaseCommand {
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.context;
|
||||
|
||||
/**
|
||||
* Simple wrapper for game rule value, as they may be different types.
|
||||
*/
|
||||
public record GameRuleValue(Object value) {
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.context;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Wrapper for context that get location from player if executed by player,
|
||||
* else requires user input of location coordinates.
|
||||
*
|
||||
* @param value The location
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public record PlayerLocation(Location value) {
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.context.issueraware;
|
||||
|
||||
import co.aikar.commands.BukkitCommandExecutionContext;
|
||||
import co.aikar.commands.BukkitCommandIssuer;
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import co.aikar.commands.contexts.IssuerAwareContextResolver;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Reusable logic of issuer only and issuer aware context resolvers
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public final class IssuerAwareContextBuilder<T> {
|
||||
|
||||
private BiFunction<BukkitCommandExecutionContext, Player, T> fromPlayer;
|
||||
private BiFunction<BukkitCommandExecutionContext, String, T> fromInput;
|
||||
private Function<BukkitCommandExecutionContext, Message> issuerOnlyFailMessage = context -> Message.of("This command can only be used by a player.");
|
||||
private BiFunction<BukkitCommandExecutionContext, Player, Message> issuerAwarePlayerFailMessage = (context, player) -> Message.of("Unable to resolve context for player '" + player.getName() + "'.");
|
||||
private BiFunction<BukkitCommandExecutionContext, String, Message> issuerAwareInputFailMessage = (context, input) -> Message.of("Unable to resolve context for input '" + input + "'.");
|
||||
private BiFunction<BukkitCommandExecutionContext, String, Message> inputOnlyFailMessage = (context, input) -> Message.of("Unable to resolve context for input '" + input + "'.");
|
||||
|
||||
public IssuerAwareContextBuilder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse value from player itself.
|
||||
*
|
||||
* @param fromInput the parsing function
|
||||
* @return The same builder for chaining
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public IssuerAwareContextBuilder<T> fromPlayer(BiFunction<BukkitCommandExecutionContext, Player, T> fromInput) {
|
||||
this.fromPlayer = fromInput;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse value from command input string.
|
||||
*
|
||||
* @param fromInput the parsing function
|
||||
* @return The same builder for chaining
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public IssuerAwareContextBuilder<T> fromInput(BiFunction<BukkitCommandExecutionContext, String, T> fromInput) {
|
||||
this.fromInput = fromInput;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* When getting value fails as issuer is not a player.
|
||||
*
|
||||
* @param issuerOnlyFailMessage The message
|
||||
* @return The same builder for chaining
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public IssuerAwareContextBuilder<T> issuerOnlyFailMessage(Function<BukkitCommandExecutionContext, Message> issuerOnlyFailMessage) {
|
||||
this.issuerOnlyFailMessage = issuerOnlyFailMessage;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* When getting value fails as player cannot parse the value.
|
||||
*
|
||||
* @param issuerAwarePlayerFailMessage The message
|
||||
* @return The same builder for chaining
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public IssuerAwareContextBuilder<T> issuerAwarePlayerFailMessage(BiFunction<BukkitCommandExecutionContext, Player, Message> issuerAwarePlayerFailMessage) {
|
||||
this.issuerAwarePlayerFailMessage = issuerAwarePlayerFailMessage;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* When getting value fails as input cannot parse the value.
|
||||
*
|
||||
* @param issuerAwareInputFailMessage The message
|
||||
* @return The same builder for chaining
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public IssuerAwareContextBuilder<T> issuerAwareInputFailMessage(BiFunction<BukkitCommandExecutionContext, String, Message> issuerAwareInputFailMessage) {
|
||||
this.issuerAwareInputFailMessage = issuerAwareInputFailMessage;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* When getting value fails as input cannot parse the value.
|
||||
*
|
||||
* @param inputOnlyFailMessage The message
|
||||
* @return The same builder for chaining
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public IssuerAwareContextBuilder<T> inputOnlyFailMessage(BiFunction<BukkitCommandExecutionContext, String, Message> inputOnlyFailMessage) {
|
||||
this.inputOnlyFailMessage = inputOnlyFailMessage;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the issuer aware context resolver logic.
|
||||
*
|
||||
* @return The generated context resolver
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public IssuerAwareContextResolver<T, BukkitCommandExecutionContext> generateContext() {
|
||||
validateRequiredVariables();
|
||||
return context -> resolveValue(context, GenericIssuerAwareValue::new).value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the issuer aware context resolver logic, with marking of whether the value was resolved from player or input.
|
||||
*
|
||||
* @param createValue The function to create the {@link IssuerAwareValue} value
|
||||
* @param <I> The type of the value
|
||||
* @return The generated context resolver
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public <I extends IssuerAwareValue> IssuerAwareContextResolver<I, BukkitCommandExecutionContext> generateContext(BiFunction<Boolean, T, I> createValue) {
|
||||
validateRequiredVariables();
|
||||
return context -> resolveValue(context, createValue);
|
||||
}
|
||||
|
||||
private void validateRequiredVariables() {
|
||||
Objects.requireNonNull(fromPlayer);
|
||||
Objects.requireNonNull(fromInput);
|
||||
Objects.requireNonNull(issuerOnlyFailMessage);
|
||||
Objects.requireNonNull(issuerAwarePlayerFailMessage);
|
||||
Objects.requireNonNull(issuerAwareInputFailMessage);
|
||||
Objects.requireNonNull(inputOnlyFailMessage);
|
||||
}
|
||||
|
||||
private <I extends IssuerAwareValue> I resolveValue(BukkitCommandExecutionContext context, BiFunction<Boolean, T, I> createValue) {
|
||||
BukkitCommandIssuer issuer = context.getIssuer();
|
||||
String resolve = context.getFlagValue("resolve", "");
|
||||
|
||||
if (resolve.equals("issuerOnly")) {
|
||||
if (issuer.isPlayer()) {
|
||||
T result = fromPlayer.apply(context, issuer.getPlayer());
|
||||
if (result != null) {
|
||||
return createValue.apply(true, result);
|
||||
}
|
||||
}
|
||||
throw new InvalidCommandArgument(issuerOnlyFailMessage.apply(context).formatted(issuer));
|
||||
}
|
||||
|
||||
String input = context.getFirstArg();
|
||||
T result = fromInput.apply(context, input);
|
||||
if (result != null) {
|
||||
context.popFirstArg();
|
||||
return createValue.apply(false, result);
|
||||
}
|
||||
|
||||
int maxArgForAware = context.getFlagValue("maxArgForAware", Integer.MAX_VALUE);
|
||||
long argLengthWithoutFlags = context.getArgs().stream()
|
||||
.takeWhile(value -> !value.startsWith("-") && !value.isEmpty()) // ignore the flags
|
||||
.count();
|
||||
|
||||
if (resolve.equals("issuerAware") && argLengthWithoutFlags <= maxArgForAware) {
|
||||
if (issuer.isPlayer()) {
|
||||
Player player = issuer.getPlayer();
|
||||
result = fromPlayer.apply(context, player);
|
||||
if (result != null) {
|
||||
return createValue.apply(true, result);
|
||||
}
|
||||
throw new InvalidCommandArgument(issuerAwarePlayerFailMessage.apply(context, player).formatted(issuer));
|
||||
}
|
||||
throw new InvalidCommandArgument(issuerAwareInputFailMessage.apply(context, input).formatted(issuer));
|
||||
}
|
||||
|
||||
throw new InvalidCommandArgument(inputOnlyFailMessage.apply(context, input).formatted(issuer));
|
||||
}
|
||||
|
||||
private static class GenericIssuerAwareValue<T> extends IssuerAwareValue {
|
||||
private final T value;
|
||||
|
||||
public GenericIssuerAwareValue(boolean byIssuer, T value) {
|
||||
super(byIssuer);
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.context.issueraware;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Base class for issuer aware values
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public abstract class IssuerAwareValue {
|
||||
protected final boolean byIssuer;
|
||||
|
||||
/**
|
||||
* Constructor to create an issuer aware value
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
protected IssuerAwareValue(boolean byIssuer) {
|
||||
this.byIssuer = byIssuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the value is by issuer or input
|
||||
*
|
||||
* @return true if by issuer, false if by input
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public boolean isByIssuer() {
|
||||
return byIssuer;
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.context.issueraware;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
|
||||
/**
|
||||
* Issuer aware value wrapper for {@link MultiverseWorld}
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public final class MultiverseWorldValue extends IssuerAwareValue {
|
||||
|
||||
private final MultiverseWorld world;
|
||||
|
||||
/**
|
||||
* Constructor for issuer aware value
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public MultiverseWorldValue(boolean byIssuer, MultiverseWorld world) {
|
||||
super(byIssuer);
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
/**
|
||||
* The containing world wrapped
|
||||
*
|
||||
* @return wrapped world
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public MultiverseWorld value() {
|
||||
return world;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.context.issueraware;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Issuer aware value wrapper for {@link Player} array
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public final class PlayerArrayValue extends IssuerAwareValue {
|
||||
|
||||
private final Player[] players;
|
||||
|
||||
/**
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public PlayerArrayValue(boolean byIssuer, Player[] players) {
|
||||
super(byIssuer);
|
||||
this.players = players;
|
||||
}
|
||||
|
||||
/**
|
||||
* The containing player array wrapped
|
||||
*
|
||||
* @return wrapped player array
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.1")
|
||||
public Player[] value() {
|
||||
return players;
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.context;
|
||||
@@ -1,105 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.flag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a flag.
|
||||
*/
|
||||
public class CommandFlag {
|
||||
/**
|
||||
* A builder for a flag.
|
||||
*
|
||||
* @param key The key for the new flag.
|
||||
* @return The builder.
|
||||
*/
|
||||
public static @NotNull Builder<?> builder(@NotNull String key){
|
||||
return new Builder<>(key);
|
||||
}
|
||||
|
||||
private final String key;
|
||||
private final List<String> aliases;
|
||||
|
||||
/**
|
||||
* Creates a new flag.
|
||||
*
|
||||
* @param key The key for the new flag.
|
||||
* @param aliases The aliases that also refer to this flag.
|
||||
*/
|
||||
protected CommandFlag(@NotNull String key, @NotNull List<String> aliases) {
|
||||
this.key = key;
|
||||
this.aliases = aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key of this flag.
|
||||
*
|
||||
* @return The key of this flag.
|
||||
*/
|
||||
public @NotNull String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the aliases of this flag.
|
||||
*
|
||||
* @return The aliases of this flag.
|
||||
*/
|
||||
public @NotNull List<String> getAliases() {
|
||||
return aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Builder{"
|
||||
+ "key='" + key + '\''
|
||||
+ ", aliases=" + aliases
|
||||
+ '}';
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for a flag.
|
||||
*
|
||||
* @param <S> The type of the builder.
|
||||
*/
|
||||
public static class Builder<S extends Builder<?>> {
|
||||
protected final String key;
|
||||
protected final List<String> aliases;
|
||||
|
||||
/**
|
||||
* Create a new builder.
|
||||
*
|
||||
* @param key The key for the new flag.
|
||||
*/
|
||||
public Builder(@NotNull String key) {
|
||||
this.key = key;
|
||||
aliases = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add one or more alias to the flag.
|
||||
*
|
||||
* @param alias The alias to add.
|
||||
* @return The builder.
|
||||
*/
|
||||
public @NotNull S addAlias(@NotNull String...alias){
|
||||
Collections.addAll(this.aliases, alias);
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the flag.
|
||||
*
|
||||
* @return The flag.
|
||||
*/
|
||||
public @NotNull CommandFlag build(){
|
||||
return new CommandFlag(key, aliases);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.flag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A group of flags.
|
||||
*/
|
||||
public class CommandFlagGroup {
|
||||
/**
|
||||
* A builder for a flag group.
|
||||
*
|
||||
* @param name The name of the group.
|
||||
* @return The builder.
|
||||
*/
|
||||
public static @NotNull Builder builder(@NotNull String name) {
|
||||
return new Builder(name);
|
||||
}
|
||||
|
||||
private final String name;
|
||||
private final List<String> keys;
|
||||
private final Map<String, CommandFlag> keysFlagMap;
|
||||
|
||||
/**
|
||||
* Creates a new flag group.
|
||||
*
|
||||
* @param builder The builder.
|
||||
*/
|
||||
protected CommandFlagGroup(@NotNull Builder builder) {
|
||||
name = builder.name;
|
||||
keys = builder.keys;
|
||||
keysFlagMap = builder.keysFlagMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this group.
|
||||
*
|
||||
* @return The name of this group.
|
||||
*/
|
||||
public @NotNull String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this group contains a flag with the given key. Works with alias keys.
|
||||
*
|
||||
* @param key The key to check.
|
||||
* @return True if the group contains a flag with the given key, false otherwise.
|
||||
*/
|
||||
public boolean hasKey(@Nullable String key) {
|
||||
return keysFlagMap.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the remaining keys after the given flags have been removed. Works with alias keys.
|
||||
*
|
||||
* @param flags The flags to remove.
|
||||
* @return The remaining keys.
|
||||
*/
|
||||
public @NotNull Set<String> getRemainingKeys(@NotNull String[] flags) {
|
||||
Set<String> keysRemaining = new HashSet<>(this.keys);
|
||||
for (String flag : flags) {
|
||||
CommandFlag mvFlag = this.getFlagByKey(flag);
|
||||
if (mvFlag != null) {
|
||||
keysRemaining.remove(mvFlag.getKey());
|
||||
}
|
||||
}
|
||||
return keysRemaining;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a flag by its key. Alias keys are supported as well.
|
||||
*
|
||||
* @param key The key of the flag.
|
||||
* @return The flag if found, null otherwise.
|
||||
*/
|
||||
public @Nullable CommandFlag getFlagByKey(String key) {
|
||||
return keysFlagMap.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for {@link CommandFlagGroup}.
|
||||
*/
|
||||
public static class Builder {
|
||||
private final String name;
|
||||
private final List<String> keys;
|
||||
private final Map<String, CommandFlag> keysFlagMap;
|
||||
|
||||
/**
|
||||
* Creates a new builder.
|
||||
*
|
||||
* @param name The name of the flag group.
|
||||
*/
|
||||
public Builder(@NotNull String name) {
|
||||
this.name = name;
|
||||
this.keys = new ArrayList<>();
|
||||
this.keysFlagMap = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a flag to the group.
|
||||
*
|
||||
* @param flag The flag to add.
|
||||
* @return The builder.
|
||||
*/
|
||||
public @NotNull Builder add(CommandFlag flag) {
|
||||
keys.add(flag.getKey());
|
||||
keysFlagMap.put(flag.getKey(), flag);
|
||||
flag.getAliases().forEach((alias) -> keysFlagMap.put(alias, flag));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the flag group.
|
||||
*
|
||||
* @return The flag group.
|
||||
*/
|
||||
public @NotNull CommandFlagGroup build() {
|
||||
return new CommandFlagGroup(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.flag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
/**
|
||||
* Manages all the flag groups and parsing.
|
||||
*/
|
||||
@Service
|
||||
public class CommandFlagsManager {
|
||||
private final Map<String, CommandFlagGroup> flagGroupMap;
|
||||
|
||||
/**
|
||||
* Creates a new FlagsManager.
|
||||
*/
|
||||
public CommandFlagsManager() {
|
||||
flagGroupMap = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a flag group.
|
||||
*
|
||||
* @param flagGroup The target flag group to register.
|
||||
*/
|
||||
public void registerFlagGroup(@NotNull CommandFlagGroup flagGroup) {
|
||||
flagGroupMap.put(flagGroup.getName(), flagGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a flag group by name.
|
||||
*
|
||||
* @param groupName The target flag group name.
|
||||
* @return The flag group if found, null otherwise.
|
||||
*/
|
||||
public @Nullable CommandFlagGroup getFlagGroup(@Nullable String groupName) {
|
||||
return this.flagGroupMap.get(groupName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Autocompletes suggestions for flags.
|
||||
*
|
||||
* @param groupName The target flag group name.
|
||||
* @param flags The current flags so far.
|
||||
* @return The list of suggestions.
|
||||
*/
|
||||
public @NotNull Collection<String> suggest(@Nullable String groupName, @NotNull String[] flags) {
|
||||
CommandFlagGroup flagGroup = this.getFlagGroup(groupName);
|
||||
if (flagGroup == null) {
|
||||
Logging.warning("Unknown flag group: " + groupName);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Collection<String> suggestions = new ArrayList<>();
|
||||
CommandFlag currentFlag = (flags.length <= 1) ? null : flagGroup.getFlagByKey(flags[flags.length - 2]);
|
||||
|
||||
if (currentFlag instanceof CommandValueFlag<?> valueFlag) {
|
||||
if (valueFlag.getCompletion() != null) {
|
||||
suggestions.addAll(valueFlag.getCompletion().apply(flags[flags.length - 1]));
|
||||
}
|
||||
if (valueFlag.isOptional()) {
|
||||
suggestions.addAll(flagGroup.getRemainingKeys(flags));
|
||||
}
|
||||
} else {
|
||||
suggestions.addAll(flagGroup.getRemainingKeys(flags));
|
||||
}
|
||||
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the flags.
|
||||
*
|
||||
* @param groupName The target flag group name.
|
||||
* @param flags The flags to parse.
|
||||
* @return The parsed flags.
|
||||
*
|
||||
* @throws InvalidCommandArgument If the flags are invalid.
|
||||
*/
|
||||
public @NotNull ParsedCommandFlags parse(@Nullable String groupName, @NotNull String[] flags) {
|
||||
CommandFlagGroup flagGroup = this.getFlagGroup(groupName);
|
||||
if (flagGroup == null) {
|
||||
return ParsedCommandFlags.EMPTY;
|
||||
}
|
||||
|
||||
return new CommandFlagsParser(this.getFlagGroup(groupName), flags).parse();
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.flag;
|
||||
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
|
||||
/**
|
||||
* Parses flags from a string array. Each parser should only be used once.
|
||||
*/
|
||||
public class CommandFlagsParser {
|
||||
private final CommandFlagGroup flagGroup;
|
||||
private final String[] flags;
|
||||
|
||||
private ParsedCommandFlags parsedFlags;
|
||||
private boolean nextArgMayBeKey;
|
||||
private boolean nextArgMayBeValue;
|
||||
private CommandFlag currentFlag;
|
||||
|
||||
/**
|
||||
* Creates a new CommandFlagsParser.
|
||||
*
|
||||
* @param flagGroup The flag group to parse flags for.
|
||||
* @param flags The flags to parse.
|
||||
*/
|
||||
public CommandFlagsParser(CommandFlagGroup flagGroup, String[] flags) {
|
||||
this.flagGroup = flagGroup;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the flags.
|
||||
*
|
||||
* @return The parsed flags.
|
||||
*/
|
||||
public ParsedCommandFlags parse() {
|
||||
parsedFlags = new ParsedCommandFlags();
|
||||
|
||||
// First argument is always a key
|
||||
this.nextArgMayBeKey = true;
|
||||
this.nextArgMayBeValue = false;
|
||||
|
||||
for (String flag : flags) {
|
||||
if (this.nextArgMayBeKey) {
|
||||
if (parseKey(flag)) continue;
|
||||
}
|
||||
if (this.nextArgMayBeValue) {
|
||||
if (parseValue(flag)) continue;
|
||||
}
|
||||
throw new InvalidCommandArgument(flag + " is not a valid flag.");
|
||||
}
|
||||
|
||||
if (!this.nextArgMayBeKey && this.nextArgMayBeValue) {
|
||||
throw new InvalidCommandArgument(currentFlag.getKey() + " requires a value!");
|
||||
}
|
||||
|
||||
return parsedFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a key.
|
||||
*
|
||||
* @param flag The flag to parse.
|
||||
* @return True if the flag was parsed as a key, false otherwise.
|
||||
*/
|
||||
private boolean parseKey(String flag) {
|
||||
CommandFlag potentialFlag = flagGroup.getFlagByKey(flag);
|
||||
if (potentialFlag == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.currentFlag = potentialFlag;
|
||||
|
||||
if (this.currentFlag instanceof CommandValueFlag<?> valueFlag) {
|
||||
if (valueFlag.isOptional()) {
|
||||
parsedFlags.addFlagResult(valueFlag.getKey(), valueFlag.getDefaultValue());
|
||||
this.nextArgMayBeKey = true;
|
||||
this.nextArgMayBeValue = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
this.nextArgMayBeKey = false;
|
||||
this.nextArgMayBeValue = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
parsedFlags.addFlagResult(this.currentFlag.getKey(), null);
|
||||
this.nextArgMayBeKey = true;
|
||||
this.nextArgMayBeValue = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a value.
|
||||
*
|
||||
* @param flag The flag to parse.
|
||||
* @return True if the flag was parsed as a value, false otherwise.
|
||||
*/
|
||||
private boolean parseValue(String flag) {
|
||||
if (this.currentFlag == null) {
|
||||
throw new InvalidCommandArgument("Some flag logic error occurred at '" + flag + "'!");
|
||||
}
|
||||
if (flagGroup.hasKey(flag)) {
|
||||
throw new InvalidCommandArgument(currentFlag.getKey() + " requires a value!");
|
||||
}
|
||||
|
||||
Object flagValue;
|
||||
CommandValueFlag<?> valueFlag = (CommandValueFlag<?>) this.currentFlag;
|
||||
flagValue = valueFlag.getContext() != null ? valueFlag.getContext().apply(flag) : flag;
|
||||
parsedFlags.addFlagResult(valueFlag.getKey(), flagValue);
|
||||
|
||||
// After a value, the next argument must be a key
|
||||
this.nextArgMayBeKey = true;
|
||||
this.nextArgMayBeValue = false;
|
||||
this.currentFlag = null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,270 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.flag;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Function;
|
||||
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a flag with a value.
|
||||
*
|
||||
* @param <T> The type of the value.
|
||||
*/
|
||||
public class CommandValueFlag<T> extends CommandFlag {
|
||||
/**
|
||||
* A builder for a flag.
|
||||
*
|
||||
* @param key The key for the new flag.
|
||||
* @param type The type of the value.
|
||||
* @return The builder.
|
||||
*/
|
||||
public static @NotNull <T> Builder<T, ?> builder(@NotNull String key, @NotNull Class<T> type) {
|
||||
return new Builder<>(key, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for a flag with enum value.
|
||||
*
|
||||
* @param key The key for the new flag.
|
||||
* @param type The type of the value, must be enum.
|
||||
* @return The builder.
|
||||
*/
|
||||
public static @NotNull <T extends Enum<T>> EnumBuilder<T, ?> enumBuilder(@NotNull String key, @NotNull Class<T> type) {
|
||||
return new EnumBuilder<>(key, type);
|
||||
}
|
||||
|
||||
private final Class<T> type;
|
||||
private final boolean optional;
|
||||
private final T defaultValue;
|
||||
private final Function<String, T> context;
|
||||
private final Function<String, Collection<String>> completion;
|
||||
|
||||
/**
|
||||
* Creates a new flag.
|
||||
*
|
||||
* @param key The key for the new flag.
|
||||
* @param aliases The aliases that also refer to this flag.
|
||||
* @param type The type of the value.
|
||||
* @param optional Allow for flag without value.
|
||||
* @param defaultValue The default value if optional is true and user does not specify a value.
|
||||
* @param context Function to parse string into value type.
|
||||
* @param completion Function to get completion for this flag.
|
||||
*/
|
||||
protected CommandValueFlag(
|
||||
@NotNull String key,
|
||||
@NotNull List<String> aliases,
|
||||
@NotNull Class<T> type,
|
||||
boolean optional,
|
||||
@Nullable T defaultValue,
|
||||
@Nullable Function<String, T> context,
|
||||
@Nullable Function<String, Collection<String>> completion
|
||||
) {
|
||||
super(key, aliases);
|
||||
this.type = type;
|
||||
this.optional = optional;
|
||||
this.defaultValue = defaultValue;
|
||||
this.context = context;
|
||||
this.completion = completion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of the value.
|
||||
*
|
||||
* @return The type of the value.
|
||||
*/
|
||||
public @NotNull Class<T> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if it is optional for users to specify a value.
|
||||
*
|
||||
* @return True if the value is optional, false otherwise.
|
||||
*/
|
||||
public boolean isOptional() {
|
||||
return optional;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default value. May be null.
|
||||
*
|
||||
* @return The default value.
|
||||
*/
|
||||
public @Nullable T getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the context. May be null for {@link String} value type.
|
||||
*
|
||||
* @return The context.
|
||||
*/
|
||||
public @Nullable Function<String, T> getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the completion. May be null.
|
||||
*
|
||||
* @return The completion.
|
||||
*/
|
||||
public @Nullable Function<String, Collection<String>> getCompletion() {
|
||||
return completion;
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for a flag.
|
||||
*
|
||||
* @param <T> The type of the value.
|
||||
* @param <S> The type of the builder.
|
||||
*/
|
||||
public static class Builder<T, S extends Builder<T, S>> extends CommandFlag.Builder<S> {
|
||||
protected final Class<T> type;
|
||||
protected boolean optional = false;
|
||||
protected T defaultValue = null;
|
||||
protected Function<String, T> context = null;
|
||||
protected Function<String, Collection<String>> completion = null;
|
||||
|
||||
/**
|
||||
* Create a new builder.
|
||||
*
|
||||
* @param key The key for the new flag.
|
||||
* @param type The type of the value.
|
||||
*/
|
||||
public Builder(@NotNull String key, @NotNull Class<T> type) {
|
||||
super(key);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flag as optional for users to specify a value.
|
||||
*
|
||||
* @return The builder.
|
||||
*/
|
||||
public @NotNull S optional() {
|
||||
this.optional = true;
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default value. Used if optional is true and user does not specify a value.
|
||||
*
|
||||
* @param defaultValue The default value.
|
||||
* @return The builder.
|
||||
*/
|
||||
public @NotNull S defaultValue(@NotNull T defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the context callback for parsing string into value type.
|
||||
*
|
||||
* @param context The context.
|
||||
* @return The builder.
|
||||
*/
|
||||
public @NotNull S context(@NotNull Function<String, T> context) {
|
||||
this.context = context;
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the completion callback for autocomplete.
|
||||
*
|
||||
* @param completion The completion. Input is the current input string, and output is the list of suggestions.
|
||||
* @return The builder.
|
||||
*/
|
||||
public @NotNull S completion(@NotNull Function<String, Collection<String>> completion) {
|
||||
this.completion = completion;
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the flag.
|
||||
*
|
||||
* @return The flag.
|
||||
*/
|
||||
@Override
|
||||
public @NotNull CommandValueFlag<T> build() {
|
||||
if (context == null && !String.class.equals(type)) {
|
||||
throw new IllegalStateException("Context is required for non-string value flags");
|
||||
}
|
||||
return new CommandValueFlag<>(key, aliases, type, optional, defaultValue, context, completion);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specific builder for a flag with enum value.
|
||||
*
|
||||
* @param <T> The type of the value.
|
||||
* @param <S> The type of the builder.
|
||||
*/
|
||||
public static class EnumBuilder<T extends Enum<T>, S extends EnumBuilder<T, S>> extends CommandFlag.Builder<S> {
|
||||
protected final Class<T> type;
|
||||
protected boolean optional = false;
|
||||
protected T defaultValue = null;
|
||||
protected Function<String, T> context = null;
|
||||
protected Function<String, Collection<String>> completion = null;
|
||||
|
||||
public EnumBuilder(@NotNull String key, @NotNull Class<T> type) {
|
||||
super(key);
|
||||
this.type = type;
|
||||
setEnumContext();
|
||||
setEnumCompletion();
|
||||
}
|
||||
|
||||
private void setEnumContext() {
|
||||
this.context = (String value) -> {
|
||||
try {
|
||||
return Enum.valueOf(type, value.toUpperCase(Locale.ENGLISH));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new InvalidCommandArgument("Invalid value for argument " + key + ": " + value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void setEnumCompletion() {
|
||||
List<String> types = Arrays.stream(type.getEnumConstants())
|
||||
.map(typeClass -> typeClass.name().toLowerCase(Locale.ENGLISH))
|
||||
.toList();
|
||||
|
||||
this.completion = (input) -> types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flag as optional for users to specify a value.
|
||||
*
|
||||
* @return The builder.
|
||||
*/
|
||||
public @NotNull S optional() {
|
||||
this.optional = true;
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default value. Used if optional is true and user does not specify a value.
|
||||
*
|
||||
* @param defaultValue The default value.
|
||||
* @return The builder.
|
||||
*/
|
||||
public @NotNull S defaultValue(@NotNull T defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the flag.
|
||||
*
|
||||
* @return The flag.
|
||||
*/
|
||||
@Override
|
||||
public @NotNull CommandValueFlag<T> build() {
|
||||
return new CommandValueFlag<>(key, aliases, type, optional, defaultValue, context, completion);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.flag;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Contract;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Builds and registers a flag group on initialization. Flags should be final fields that calls {@link #flag(CommandFlag)}.
|
||||
*/
|
||||
@Contract
|
||||
public abstract class FlagBuilder {
|
||||
|
||||
private final String name;
|
||||
private final CommandFlagsManager flagsManager;
|
||||
private final List<CommandFlag> flags;
|
||||
|
||||
protected FlagBuilder(@NotNull String name, @NotNull CommandFlagsManager flagsManager) {
|
||||
this.name = name;
|
||||
this.flagsManager = flagsManager;
|
||||
this.flags = new ArrayList<>();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
private void postConstruct() {
|
||||
CommandFlagGroup.Builder flagGroupBuilder = CommandFlagGroup.builder(name);
|
||||
flags.forEach(flagGroupBuilder::add);
|
||||
registerFlagGroup(flagGroupBuilder.build());
|
||||
}
|
||||
|
||||
private void registerFlagGroup(@NotNull CommandFlagGroup flagGroup) {
|
||||
flagsManager.registerFlagGroup(flagGroup);
|
||||
Logging.finer("Registered flag group: " + flagGroup.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new flag to the flag builder.
|
||||
*
|
||||
* @param flag The flag to add.
|
||||
* @param <T> The type of the flag.
|
||||
* @return The flag.
|
||||
*/
|
||||
protected <T extends CommandFlag> T flag(T flag) {
|
||||
flags.add(flag);
|
||||
Logging.finer("Added flag: " + flag);
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses flags.
|
||||
*
|
||||
* @param flags The raw string array to parse into flags.
|
||||
* @return The parsed flags.
|
||||
*/
|
||||
public @NotNull ParsedCommandFlags parse(@NotNull String[] flags) {
|
||||
return flagsManager.parse(name, flags);
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.flag;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Object to contain the results of the flags present and its values.
|
||||
*/
|
||||
public class ParsedCommandFlags
|
||||
{
|
||||
public static final ParsedCommandFlags EMPTY = new ParsedCommandFlags();
|
||||
|
||||
private final Map<String, Object> flagValues;
|
||||
|
||||
ParsedCommandFlags() {
|
||||
flagValues = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a flag result to the parsed flags.
|
||||
*
|
||||
* @param key The key of the flag.
|
||||
* @param value The value of the flag.
|
||||
*/
|
||||
void addFlagResult(@NotNull String key, @Nullable Object value) {
|
||||
flagValues.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a flag is present.
|
||||
*
|
||||
* @param flag The flag to check.
|
||||
* @return True if the flag is present, false otherwise.
|
||||
*/
|
||||
public boolean hasFlag(@NotNull CommandFlag flag) {
|
||||
return hasFlag(flag.getKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a flag is present.
|
||||
*
|
||||
* @param key The key of the flag.
|
||||
* @return True if the flag is present, false otherwise.
|
||||
*/
|
||||
public boolean hasFlag(@Nullable String key) {
|
||||
return this.flagValues.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a flag is present and has a value.
|
||||
*
|
||||
* @param key The key of the flag.
|
||||
* @return True if the flag is present and has a value, false otherwise.
|
||||
*/
|
||||
public boolean hasFlagValue(@Nullable String key) {
|
||||
return flagValue(key, Object.class) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a flag.
|
||||
*
|
||||
* @param <T> The type of the value.
|
||||
* @param flag The flag to get the value of.
|
||||
* @param type The type of the value.
|
||||
* @return The value of the flag, null if flag does not exist or no value.
|
||||
*/
|
||||
public @Nullable <T> T flagValue(@NotNull CommandFlag flag, @NotNull Class<T> type) {
|
||||
return flagValue(flag.getKey(), type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a flag.
|
||||
*
|
||||
* @param key The key of the flag to get the value of.
|
||||
* @param type The type of the value.
|
||||
* @return The value of the flag, null if flag does not exist or no value.
|
||||
*/
|
||||
public @Nullable <T> T flagValue(@Nullable String key, @NotNull Class<T> type) {
|
||||
Object value = this.flagValues.get(key);
|
||||
return (T) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a flag.
|
||||
*
|
||||
* @param <T> The type of the value.
|
||||
* @param flag The flag to get the value of.
|
||||
* @return The value of the flag, default value if flag does not exist or no value.
|
||||
*/
|
||||
public @Nullable <T> T flagValue(@NotNull CommandValueFlag<T> flag) {
|
||||
return flagValue(flag.getKey(), flag.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a flag.
|
||||
*
|
||||
* @param <T> The type of the value.
|
||||
* @param flag The flag to get the value of.
|
||||
* @param defaultValue The default value if flag does not exist or no value.
|
||||
* @return The value of the flag, default value if flag does not exist or no value.
|
||||
*/
|
||||
public @NotNull <T> T flagValue(@NotNull CommandValueFlag<T> flag, @NotNull T defaultValue) {
|
||||
return flagValue(flag.getKey(), defaultValue, flag.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a flag.
|
||||
*
|
||||
* @param <T> The type of the value.
|
||||
* @param key The key of the flag to get the value of.
|
||||
* @param defaultValue The default value if flag does not exist or no value.
|
||||
* @param type The type of the value.
|
||||
* @return The value of the flag, default value if flag does not exist or no value.
|
||||
*/
|
||||
public @NotNull <T> T flagValue(@Nullable String key, @NotNull T defaultValue, @NotNull Class<T> type) {
|
||||
T value = flagValue(key, type);
|
||||
return value != null ? value : defaultValue;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* This package contains classes related to parsing command flags.
|
||||
*/
|
||||
package org.mvplugins.multiverse.core.command.flag;
|
||||
@@ -1,41 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.flags;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandValueFlag;
|
||||
import org.mvplugins.multiverse.core.display.filters.ContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.filters.RegexContentFilter;
|
||||
|
||||
/**
|
||||
* A command flag for regex filtering.
|
||||
* <br/>
|
||||
* Parses the value of the --filter (or -f) flag as a {@link ContentFilter}.
|
||||
*/
|
||||
public final class FilterCommandFlag extends CommandValueFlag<ContentFilter> {
|
||||
|
||||
private static final Function<String, ContentFilter> VALUE_PARSER = value -> {
|
||||
try {
|
||||
return RegexContentFilter.fromString(value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new InvalidCommandArgument("Invalid filter: " + value);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new instance of this flag.
|
||||
*
|
||||
* @return The new instance.
|
||||
*/
|
||||
@NotNull
|
||||
public static FilterCommandFlag create() {
|
||||
return new FilterCommandFlag();
|
||||
}
|
||||
|
||||
private FilterCommandFlag() {
|
||||
super("--filter", List.of("-f"), ContentFilter.class, false, null, VALUE_PARSER, null);
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.flags;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandValueFlag;
|
||||
|
||||
/**
|
||||
* A command flag for page number.
|
||||
* <br/>
|
||||
* Parses the value of the --page (or -p) flag as an integer.
|
||||
*/
|
||||
public final class PageCommandFlag extends CommandValueFlag<Integer> {
|
||||
|
||||
private static final Function<String, Integer> VALUE_PARSER = value -> {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("Invalid page number: " + value);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new instance of this flag.
|
||||
*
|
||||
* @return The new instance.
|
||||
*/
|
||||
@NotNull
|
||||
public static PageCommandFlag create() {
|
||||
return new PageCommandFlag();
|
||||
}
|
||||
|
||||
private PageCommandFlag() {
|
||||
super("--page", List.of("-p"), Integer.class, false, null, VALUE_PARSER, null);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.flags;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandValueFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.FlagBuilder;
|
||||
import org.mvplugins.multiverse.core.display.filters.ContentFilter;
|
||||
|
||||
@Service
|
||||
public class PageFilterFlags extends FlagBuilder {
|
||||
|
||||
public static final String NAME = "pagefilter";
|
||||
|
||||
protected PageFilterFlags(@NotNull String name, @NotNull CommandFlagsManager flagsManager) {
|
||||
super(name, flagsManager);
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected PageFilterFlags(@NotNull CommandFlagsManager flagsManager) {
|
||||
super(NAME, flagsManager);
|
||||
}
|
||||
|
||||
public final CommandValueFlag<Integer> page = flag(PageCommandFlag.create());
|
||||
|
||||
public final CommandValueFlag<ContentFilter> filter = flag(FilterCommandFlag.create());
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.flags;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.FlagBuilder;
|
||||
|
||||
@Service
|
||||
public class RemovePlayerFlags extends FlagBuilder {
|
||||
|
||||
public static final String NAME = "removeplayer";
|
||||
|
||||
protected RemovePlayerFlags(@NotNull String name, @NotNull CommandFlagsManager flagsManager) {
|
||||
super(name, flagsManager);
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected RemovePlayerFlags(@NotNull CommandFlagsManager flagsManager) {
|
||||
super(NAME, flagsManager);
|
||||
}
|
||||
|
||||
public final CommandFlag removePlayers = flag(CommandFlag.builder("--remove-players")
|
||||
.addAlias("-r")
|
||||
.build());
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.flags;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.FlagBuilder;
|
||||
|
||||
@Service
|
||||
public class UnsafeFlags extends FlagBuilder {
|
||||
|
||||
public static final String NAME = "unsafe";
|
||||
|
||||
protected UnsafeFlags(@NotNull String name, @NotNull CommandFlagsManager flagsManager) {
|
||||
super(name, flagsManager);
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected UnsafeFlags(@NotNull CommandFlagsManager flagsManager) {
|
||||
super(NAME, flagsManager);
|
||||
}
|
||||
|
||||
public final CommandFlag unsafe = flag(CommandFlag.builder("--unsafe")
|
||||
.addAlias("-u")
|
||||
.build());
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* This package contains predefined flags for commands.
|
||||
*/
|
||||
package org.mvplugins.multiverse.core.command.flags;
|
||||
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* This package contains the classes that manages command handling.
|
||||
*/
|
||||
package org.mvplugins.multiverse.core.command;
|
||||
@@ -1,192 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Multiverse 2 Copyright (c) the Multiverse Team 2020. *
|
||||
* Multiverse 2 is licensed under the BSD License. *
|
||||
* For more information please check the README.md file included *
|
||||
* with this project. *
|
||||
******************************************************************************/
|
||||
|
||||
package org.mvplugins.multiverse.core.command.queue;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import io.vavr.control.Option;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.block.data.type.CommandBlock;
|
||||
import org.bukkit.command.BlockCommandSender;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.MultiverseCore;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.utils.result.Attempt;
|
||||
|
||||
import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.*;
|
||||
|
||||
/**
|
||||
* <p>Manages the queuing of dangerous commands that require {@code /mv confirm} before executing.</p>
|
||||
*
|
||||
* <p>Each sender can only have one command in queue at any given time. When a queued command is added
|
||||
* for a sender that already has a command in queue, it will replace the old queued command.</p>
|
||||
*/
|
||||
@Service
|
||||
public class CommandQueueManager {
|
||||
|
||||
private static final String CONSOLE_NAME = "@console";
|
||||
private static final String COMMAND_BLOCK_NAME = "@commandblock";
|
||||
private static final long TICKS_PER_SECOND = 20;
|
||||
|
||||
private final Plugin plugin;
|
||||
private final CoreConfig config;
|
||||
private final Map<String, CommandQueuePayload> queuedCommandMap;
|
||||
|
||||
@Inject
|
||||
CommandQueueManager(@NotNull MultiverseCore plugin, @NotNull CoreConfig config) {
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
this.queuedCommandMap = new WeakHashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link CommandQueuePayload} into queue.
|
||||
*
|
||||
* @param payload The command queue payload to add.
|
||||
*/
|
||||
public void addToQueue(CommandQueuePayload payload) {
|
||||
String senderName = parseSenderName(payload.issuer());
|
||||
if (canRunImmediately(senderName)) {
|
||||
payload.action().run();
|
||||
return;
|
||||
}
|
||||
|
||||
this.removeFromQueue(senderName);
|
||||
|
||||
Logging.finer("Add new command to queue for sender %s.", senderName);
|
||||
this.queuedCommandMap.put(senderName, payload);
|
||||
payload.expireTask(runExpireLater(senderName, config.getConfirmTimeout()));
|
||||
|
||||
payload.issuer().sendInfo(payload.prompt());
|
||||
var confirmCommand = "/mv confirm";
|
||||
if (config.getUseConfirmOtp()) {
|
||||
confirmCommand += " " + payload.otp();
|
||||
}
|
||||
payload.issuer().sendMessage(String.format("Run %s%s %sto continue. This will expire in %s seconds.",
|
||||
ChatColor.GREEN, confirmCommand, ChatColor.WHITE, config.getConfirmTimeout()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if sender does not need to queue before running.
|
||||
*
|
||||
* @param senderName The name of sender.
|
||||
* @return True if sender does not need to queue before running.
|
||||
*/
|
||||
private boolean canRunImmediately(@NotNull String senderName) {
|
||||
return switch (config.getConfirmMode()) {
|
||||
case ENABLE -> false;
|
||||
case PLAYER_ONLY -> senderName.equals(CONSOLE_NAME) || senderName.equals(COMMAND_BLOCK_NAME);
|
||||
case DISABLE_COMMAND_BLOCKS -> senderName.equals(COMMAND_BLOCK_NAME);
|
||||
case DISABLE_CONSOLE -> senderName.equals(CONSOLE_NAME);
|
||||
case DISABLE -> true;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Expire task that removes a {@link CommandQueuePayload} from queue after valid duration defined.
|
||||
*
|
||||
* @param senderName The name of the sender.
|
||||
* @return The expire {@link BukkitTask}.
|
||||
*/
|
||||
@NotNull
|
||||
private BukkitTask runExpireLater(@NotNull String senderName, int validDuration) {
|
||||
return Bukkit.getScheduler().runTaskLater(
|
||||
this.plugin,
|
||||
expireRunnable(senderName),
|
||||
validDuration * TICKS_PER_SECOND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runnable responsible for expiring the queued command.
|
||||
*
|
||||
* @param senderName The name of the sender.
|
||||
* @return The expire runnable.
|
||||
*/
|
||||
@NotNull
|
||||
private Runnable expireRunnable(@NotNull String senderName) {
|
||||
return () -> {
|
||||
CommandQueuePayload payload = this.queuedCommandMap.remove(senderName);
|
||||
if (payload == null) {
|
||||
// Payload already removed
|
||||
return;
|
||||
}
|
||||
payload.issuer().sendMessage("Your queued command has expired.");
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the command in queue for the given sender, if any.
|
||||
*
|
||||
* @param issuer Sender that confirmed the command.
|
||||
* @return True if queued command ran successfully, else false.
|
||||
*/
|
||||
public Attempt<Void, RunQueuedFailedReason> runQueuedCommand(@NotNull MVCommandIssuer issuer, String otpInput) {
|
||||
String senderName = parseSenderName(issuer);
|
||||
return Option.of(this.queuedCommandMap.get(senderName)).fold(
|
||||
() -> Attempt.failure(RunQueuedFailedReason.NO_COMMAND_IN_QUEUE),
|
||||
payload -> runPayload(senderName, otpInput, payload));
|
||||
}
|
||||
|
||||
private Attempt<Void, RunQueuedFailedReason> runPayload(String senderName, String otpInput, CommandQueuePayload payload) {
|
||||
if (config.getUseConfirmOtp() && !Objects.equals(payload.otp(), otpInput)) {
|
||||
return Attempt.failure(RunQueuedFailedReason.INVALID_OTP, replace("{otp}").with(otpInput));
|
||||
}
|
||||
this.removeFromQueue(senderName);
|
||||
Logging.finer("Running queued command...");
|
||||
payload.action().run();
|
||||
return Attempt.success(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Since only one command is stored in queue per sender, we remove the old one.
|
||||
*
|
||||
* @param senderName The sender that executed the command.
|
||||
*/
|
||||
public void removeFromQueue(@NotNull String senderName) {
|
||||
CommandQueuePayload payload = this.queuedCommandMap.remove(senderName);
|
||||
if (payload == null) {
|
||||
Logging.finer("No queue command to remove for sender %s.", senderName);
|
||||
return;
|
||||
}
|
||||
Option.of(payload.expireTask()).peek(BukkitTask::cancel);
|
||||
Logging.finer("Removed queue command for sender %s.", senderName);
|
||||
}
|
||||
|
||||
private String parseSenderName(MVCommandIssuer issuer) {
|
||||
CommandSender sender = issuer.getIssuer();
|
||||
if (isCommandBlock(sender)) {
|
||||
return COMMAND_BLOCK_NAME;
|
||||
} else if (sender instanceof ConsoleCommandSender) {
|
||||
return CONSOLE_NAME;
|
||||
}
|
||||
return sender.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the sender is a command block.
|
||||
*
|
||||
* @param sender The sender to check.
|
||||
* @return True if sender is a command block, else false.
|
||||
*/
|
||||
private boolean isCommandBlock(@NotNull CommandSender sender) {
|
||||
return sender instanceof BlockCommandSender
|
||||
&& ((BlockCommandSender) sender).getBlock().getBlockData() instanceof CommandBlock;
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.queue;
|
||||
|
||||
import co.aikar.commands.ACFUtil;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
|
||||
/**
|
||||
* Represents a single command used in {@link CommandQueueManager} for confirming before running potentially
|
||||
* dangerous action.
|
||||
*/
|
||||
public class CommandQueuePayload {
|
||||
|
||||
/**
|
||||
* Creates a new {@link CommandQueuePayload}
|
||||
*
|
||||
* @param issuer The issuer of the command
|
||||
* @return The new {@link CommandQueuePayload}
|
||||
*/
|
||||
public static CommandQueuePayload issuer(@NotNull MVCommandIssuer issuer) {
|
||||
return new CommandQueuePayload(issuer);
|
||||
}
|
||||
|
||||
private static final String DEFAULT_PROMPT_MESSAGE = "The command you are trying to run is deemed dangerous."; // todo: localize
|
||||
|
||||
private final MVCommandIssuer issuer;
|
||||
private String otp;
|
||||
private Runnable action = () -> {};
|
||||
private Message prompt = Message.of(DEFAULT_PROMPT_MESSAGE);
|
||||
private BukkitTask expireTask;
|
||||
|
||||
protected CommandQueuePayload(@NotNull MVCommandIssuer issuer) {
|
||||
this.otp = String.valueOf(ACFUtil.rand(100, 999));
|
||||
this.issuer = issuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the issuer of the command.
|
||||
* @return The issuer
|
||||
*/
|
||||
@NotNull
|
||||
public MVCommandIssuer issuer() {
|
||||
return issuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the logic to execute upon confirming.
|
||||
* @param action The logic to execute
|
||||
* @return The same {@link CommandQueuePayload} for method chaining
|
||||
*/
|
||||
public CommandQueuePayload action(@NotNull Runnable action) {
|
||||
this.action = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the logic to execute upon confirming.
|
||||
*
|
||||
* @return The logic to execute
|
||||
*/
|
||||
@NotNull
|
||||
public Runnable action() {
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the OTP number for validation.
|
||||
*
|
||||
* @param otp The OTP number
|
||||
* @return The same {@link CommandQueuePayload} for method chaining
|
||||
*/
|
||||
public CommandQueuePayload otp(String otp) {
|
||||
this.otp = otp;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the OTP number for validation.
|
||||
*
|
||||
* @return The OTP number
|
||||
*/
|
||||
public String otp() {
|
||||
return otp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the question to ask sender to confirm.
|
||||
*
|
||||
* @param prompt The prompt message.
|
||||
* @return The same {@link CommandQueuePayload} for method chaining.
|
||||
*/
|
||||
public CommandQueuePayload prompt(Message prompt) {
|
||||
this.prompt = prompt;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the question to ask sender to confirm.
|
||||
*
|
||||
* @return The prompt message.
|
||||
*/
|
||||
public Message prompt() {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
void expireTask(BukkitTask expireTask) {
|
||||
this.expireTask = expireTask;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
BukkitTask expireTask() {
|
||||
return expireTask;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.queue;
|
||||
|
||||
/**
|
||||
* Sets whether the command executor needs to confirm before executing a command.
|
||||
*/
|
||||
public enum ConfirmMode {
|
||||
/**
|
||||
* Every command executor needs to confirm before executing a command.
|
||||
*/
|
||||
ENABLE,
|
||||
|
||||
/**
|
||||
* Only players need to confirm before executing a command. Command blocks and console will not need to confirm.
|
||||
*/
|
||||
PLAYER_ONLY,
|
||||
|
||||
/**
|
||||
* Everyone except command blocks will not need to confirm before executing a command.
|
||||
*/
|
||||
DISABLE_COMMAND_BLOCKS,
|
||||
|
||||
/**
|
||||
* Everyone except console will not need to confirm before executing a command.
|
||||
*/
|
||||
DISABLE_CONSOLE,
|
||||
|
||||
/**
|
||||
* Everyone will not need to confirm before executing a command.
|
||||
*/
|
||||
DISABLE,
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.command.queue;
|
||||
|
||||
import co.aikar.locales.MessageKey;
|
||||
import co.aikar.locales.MessageKeyProvider;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.utils.result.FailureReason;
|
||||
|
||||
public enum RunQueuedFailedReason implements FailureReason {
|
||||
NO_COMMAND_IN_QUEUE(MVCorei18n.QUEUECOMMAND_NOCOMMANDINQUEUE),
|
||||
INVALID_OTP(MVCorei18n.QUEUECOMMAND_INVALIDOTP),
|
||||
COMMAND_EXECUTION_ERROR(MVCorei18n.QUEUECOMMAND_COMMANDEXECUTIONERROR),
|
||||
;
|
||||
|
||||
private final MessageKeyProvider message;
|
||||
|
||||
RunQueuedFailedReason(MessageKeyProvider message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public MessageKey getMessageKey() {
|
||||
return message.getMessageKey();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* Manager queuing of dangerous commands in need of confirmation.
|
||||
*/
|
||||
package org.mvplugins.multiverse.core.command.queue;
|
||||
@@ -1,43 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.anchor.AnchorManager;
|
||||
import org.mvplugins.multiverse.core.anchor.MultiverseAnchor;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
|
||||
@Service
|
||||
final class AnchorDeleteCommand extends CoreCommand {
|
||||
|
||||
private final AnchorManager anchorManager;
|
||||
|
||||
@Inject
|
||||
AnchorDeleteCommand(@NotNull AnchorManager anchorManager) {
|
||||
this.anchorManager = anchorManager;
|
||||
}
|
||||
|
||||
@Subcommand("anchor delete")
|
||||
@CommandPermission("multiverse.core.anchor.delete")
|
||||
@CommandCompletion("@anchornames")
|
||||
@Syntax("<name>")
|
||||
@Description("")
|
||||
void onAnchorDeleteCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Syntax("<name>")
|
||||
@Description("")
|
||||
MultiverseAnchor anchor) {
|
||||
if (anchorManager.deleteAnchor(anchor).isSuccess()) {
|
||||
issuer.sendMessage("&aAnchor &f" + anchor.getName() + "&a deleted.");
|
||||
} else {
|
||||
issuer.sendMessage("&cFailed to delete anchor.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Optional;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.anchor.AnchorManager;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.flags.PageFilterFlags;
|
||||
import org.mvplugins.multiverse.core.display.ContentDisplay;
|
||||
import org.mvplugins.multiverse.core.display.filters.DefaultContentFilter;
|
||||
import org.mvplugins.multiverse.core.display.handlers.PagedSendHandler;
|
||||
import org.mvplugins.multiverse.core.display.parsers.ListContentProvider;
|
||||
import org.mvplugins.multiverse.core.teleportation.LocationManipulation;
|
||||
|
||||
@Service
|
||||
final class AnchorListCommand extends CoreCommand {
|
||||
|
||||
private final AnchorManager anchorManager;
|
||||
private final LocationManipulation locationManipulation;
|
||||
private final PageFilterFlags flags;
|
||||
|
||||
@Inject
|
||||
AnchorListCommand(
|
||||
@NotNull AnchorManager anchorManager,
|
||||
@NotNull LocationManipulation locationManipulation,
|
||||
@NotNull PageFilterFlags flags
|
||||
) {
|
||||
this.anchorManager = anchorManager;
|
||||
this.locationManipulation = locationManipulation;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Subcommand("anchor list")
|
||||
@CommandPermission("multiverse.core.anchor.list")
|
||||
@CommandCompletion("@flags:groupName=" + PageFilterFlags.NAME)
|
||||
@Syntax("[--page <page>] [--filter <filter>]")
|
||||
@Description("")
|
||||
void onAnchorListCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Optional
|
||||
@Syntax("[--page <page>] [--filter <filter>]")
|
||||
@Description("")
|
||||
String[] flagArray) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
ContentDisplay.create()
|
||||
.addContent(ListContentProvider.forContent(getAnchors(issuer.getPlayer())))
|
||||
.withSendHandler(PagedSendHandler.create()
|
||||
.withHeader("&3==== [ Multiverse Anchors ] ====")
|
||||
.doPagination(true)
|
||||
.withTargetPage(parsedFlags.flagValue(flags.page, 1))
|
||||
.withFilter(parsedFlags.flagValue(flags.filter, DefaultContentFilter.get())))
|
||||
.send(issuer);
|
||||
}
|
||||
|
||||
private List<String> getAnchors(Player player) {
|
||||
return anchorManager.getAnchors(player).stream()
|
||||
.map(anchor ->
|
||||
"&a%s&7 - &f%s".formatted(
|
||||
anchor.getName(), locationManipulation.locationToString(anchor.getLocation())))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Flags;
|
||||
import co.aikar.commands.annotation.Single;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.anchor.AnchorManager;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.teleportation.LocationManipulation;
|
||||
|
||||
@Service
|
||||
final class AnchorSetCommand extends CoreCommand {
|
||||
|
||||
private final AnchorManager anchorManager;
|
||||
private final LocationManipulation locationManipulation;
|
||||
|
||||
@Inject
|
||||
AnchorSetCommand(
|
||||
@NotNull AnchorManager anchorManager,
|
||||
@NotNull LocationManipulation locationManipulation
|
||||
) {
|
||||
this.anchorManager = anchorManager;
|
||||
this.locationManipulation = locationManipulation;
|
||||
}
|
||||
|
||||
@Subcommand("anchor set")
|
||||
@CommandPermission("multiverse.core.anchor.create")
|
||||
@CommandCompletion("@empty @locations")
|
||||
@Syntax("<name> [location]")
|
||||
@Description("")
|
||||
void onAnchorSetCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Flags("resolve=issuerOnly")
|
||||
Player player,
|
||||
|
||||
@Single
|
||||
@Syntax("<name>")
|
||||
@Description("")
|
||||
//TODO: Check if anchor name is valid or exists already.
|
||||
String anchorName) {
|
||||
Location anchorLocation = player.getLocation();
|
||||
if (anchorManager.setAnchor(anchorName, anchorLocation).isSuccess()) {
|
||||
sendAnchorSetSuccessMessage(issuer, anchorName, locationManipulation.locationToString(anchorLocation));
|
||||
} else {
|
||||
sendAnchorSetFailedMessage(issuer, anchorName);
|
||||
}
|
||||
}
|
||||
|
||||
@Subcommand("anchor set")
|
||||
@CommandPermission("multiverse.core.anchor.create")
|
||||
@CommandCompletion("@anchornames @locations")
|
||||
@Syntax("<name> [location]")
|
||||
@Description("")
|
||||
void onAnchorSetCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Syntax("<name>")
|
||||
@Description("")
|
||||
String anchorName,
|
||||
|
||||
@Single
|
||||
@Syntax("[location]")
|
||||
@Description("")
|
||||
String locationString) {
|
||||
if (anchorManager.setAnchor(anchorName, locationString).isSuccess()) {
|
||||
sendAnchorSetSuccessMessage(issuer, anchorName, locationString);
|
||||
} else {
|
||||
sendAnchorSetFailedMessage(issuer, anchorName);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendAnchorSetSuccessMessage(MVCommandIssuer issuer, String anchorName, String locationString) {
|
||||
issuer.sendMessage("&aAnchor &f" + anchorName + "&a set to &f" + locationString);
|
||||
}
|
||||
|
||||
private void sendAnchorSetFailedMessage(MVCommandIssuer issuer, String anchorName) {
|
||||
issuer.sendMessage("&cFailed to set anchor &f" + anchorName + ".");
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package org.mvplugins.multiverse.core.commands;
|
||||
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationInstance;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
|
||||
import org.mvplugins.multiverse.core.permissions.CorePermissionsChecker;
|
||||
import org.mvplugins.multiverse.core.teleportation.LocationManipulation;
|
||||
|
||||
import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
|
||||
|
||||
@Service
|
||||
class CheckCommand extends CoreCommand {
|
||||
|
||||
private final CorePermissionsChecker corePermissionsChecker;
|
||||
private final LocationManipulation locationManipulation;
|
||||
|
||||
@Inject
|
||||
CheckCommand(
|
||||
@NotNull CorePermissionsChecker corePermissionsChecker,
|
||||
@NotNull LocationManipulation locationManipulation
|
||||
) {
|
||||
this.corePermissionsChecker = corePermissionsChecker;
|
||||
this.locationManipulation = locationManipulation;
|
||||
}
|
||||
|
||||
@Subcommand("check")
|
||||
@CommandPermission("multiverse.core.check")
|
||||
@CommandCompletion("@players @destinations")
|
||||
@Syntax("<player> <destination>")
|
||||
@Description("{@@mv-core.check.description}")
|
||||
void onCheckCommand(
|
||||
MVCommandIssuer issuer,
|
||||
|
||||
@Syntax("<player>")
|
||||
@Description("{@@mv-core.check.player.description}")
|
||||
Player player,
|
||||
|
||||
@Syntax("<destination>")
|
||||
@Description("{@@mv-core.check.destination.description}")
|
||||
DestinationInstance<?, ?> destination) {
|
||||
issuer.sendInfo(this.corePermissionsChecker.checkTeleportPermission(player, player, destination)
|
||||
? MVCorei18n.CHECK_HASPERMISSION
|
||||
: MVCorei18n.CHECK_NOPERMISSION,
|
||||
Replace.PLAYER.with(player.getName()),
|
||||
Replace.DESTINATION.with(destination));
|
||||
issuer.sendInfo(MVCorei18n.CHECK_LOCATION,
|
||||
replace("{location}").with(destination.getLocation(player)
|
||||
.map(locationManipulation::locationToString)
|
||||
.map(Message::of)
|
||||
.getOrElse(() -> Message.of(MVCorei18n.GENERIC_NULL, "Null!"))));
|
||||
|
||||
// TODO: Show permission required for this particular destination
|
||||
}
|
||||
|
||||
@Service
|
||||
private final static class LegacyAlias extends CheckCommand implements LegacyAliasCommand {
|
||||
@Inject
|
||||
LegacyAlias(@NotNull CorePermissionsChecker corePermissionsChecker, @NotNull LocationManipulation locationManipulation) {
|
||||
super(corePermissionsChecker, locationManipulation);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvcheck")
|
||||
void onCheckCommand(MVCommandIssuer issuer, Player player, DestinationInstance<?, ?> destination) {
|
||||
super.onCheckCommand(issuer, player, destination);
|
||||
}
|
||||
}
|
||||
}
|
||||