├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── feature_request.yml │ └── incompatible_plugin.yml ├── renovate.json └── workflows │ ├── build.yml │ ├── hangar-publish.yml │ └── maven-publish.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle ├── gradle-daemon-jvm.properties └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── plugin ├── build.gradle.kts └── src │ └── main │ ├── java │ └── net │ │ └── thenextlvl │ │ └── service │ │ ├── ServicePlugin.java │ │ ├── command │ │ ├── ServiceCommand.java │ │ ├── ServiceConvertCommand.java │ │ ├── ServiceInfoCommand.java │ │ └── argument │ │ │ ├── BankArgumentType.java │ │ │ ├── CharacterArgumentType.java │ │ │ ├── ChatArgumentType.java │ │ │ ├── EconomyArgumentType.java │ │ │ ├── GroupArgumentType.java │ │ │ ├── HologramArgumentType.java │ │ │ └── PermissionArgumentType.java │ │ ├── controller │ │ ├── character │ │ │ ├── CitizensCharacterController.java │ │ │ └── FancyCharacterController.java │ │ ├── chat │ │ │ ├── GroupManagerChatController.java │ │ │ └── LuckPermsChatController.java │ │ ├── group │ │ │ ├── GroupManagerGroupController.java │ │ │ └── LuckPermsGroupController.java │ │ ├── hologram │ │ │ ├── DecentHologramController.java │ │ │ └── FancyHologramController.java │ │ └── permission │ │ │ ├── GroupManagerPermissionController.java │ │ │ ├── LuckPermsPermissionController.java │ │ │ └── SuperPermsPermissionController.java │ │ ├── listener │ │ ├── CitizensListener.java │ │ └── FancyNpcsListener.java │ │ ├── model │ │ ├── character │ │ │ ├── citizens │ │ │ │ └── CitizensCharacter.java │ │ │ └── fancy │ │ │ │ └── FancyCharacter.java │ │ ├── chat │ │ │ ├── GroupManagerChatProfile.java │ │ │ └── LuckPermsChatProfile.java │ │ ├── group │ │ │ ├── GroupManagerGroup.java │ │ │ └── LuckPermsGroup.java │ │ ├── hologram │ │ │ ├── decent │ │ │ │ ├── DecentBlockHologramLine.java │ │ │ │ ├── DecentEntityHologramLine.java │ │ │ │ ├── DecentHologram.java │ │ │ │ ├── DecentHologramLine.java │ │ │ │ ├── DecentItemHologramLine.java │ │ │ │ └── DecentTextHologramLine.java │ │ │ └── fancy │ │ │ │ ├── FancyBlockHologramLine.java │ │ │ │ ├── FancyHologram.java │ │ │ │ ├── FancyHologramDisplay.java │ │ │ │ ├── FancyHologramLine.java │ │ │ │ ├── FancyItemHologramLine.java │ │ │ │ └── FancyTextHologramLine.java │ │ └── permission │ │ │ ├── GroupManagerPermissionHolder.java │ │ │ ├── LuckPermsPermissionHolder.java │ │ │ └── SuperPermsPermissionHolder.java │ │ ├── version │ │ └── PluginVersionChecker.java │ │ └── wrapper │ │ ├── VaultChatServiceWrapper.java │ │ ├── VaultEconomyServiceWrapper.java │ │ ├── VaultPermissionServiceWrapper.java │ │ └── service │ │ ├── BankServiceWrapper.java │ │ ├── ChatServiceWrapper.java │ │ ├── EconomyServiceWrapper.java │ │ ├── PermissionServiceWrapper.java │ │ └── model │ │ ├── WrappedAccount.java │ │ ├── WrappedBank.java │ │ ├── WrappedChatProfile.java │ │ └── WrappedPermissionHolder.java │ └── resources │ ├── service-io.properties │ └── service-io_german.properties ├── settings.gradle.kts └── src └── main └── java └── net └── thenextlvl └── service └── api ├── Controller.java ├── capability ├── Capability.java ├── CapabilityException.java └── CapabilityProvider.java ├── character ├── Character.java ├── CharacterCapability.java ├── CharacterController.java └── event │ ├── CharacterDamageEvent.java │ ├── CharacterEvent.java │ ├── EntityDamageCharacterEvent.java │ └── PlayerInteractCharacterEvent.java ├── chat ├── ChatController.java └── ChatProfile.java ├── economy ├── Account.java ├── EconomyController.java └── bank │ ├── Bank.java │ └── BankController.java ├── group ├── Group.java ├── GroupController.java └── GroupHolder.java ├── hologram ├── Hologram.java ├── HologramCapability.java ├── HologramController.java ├── HologramDisplay.java ├── HologramLine.java └── LineType.java ├── model ├── Display.java ├── InfoNode.java ├── Persistable.java ├── Positioned.java └── Viewable.java └── permission ├── PermissionController.java └── PermissionHolder.java /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug report 2 | description: Create a report to help us improve 3 | labels: 4 | - bug 5 | assignees: 6 | - NonSwag 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thanks for taking the time to fill out this bug report for ServiceIO! Fill out the following form to your best ability to help us fix the problem. 12 | Only use this if you're absolutely sure that you found a bug and can reproduce it. For anything else, use: [our Discord server](https://thenextlvl.net/discord). 13 | 14 | - type: textarea 15 | attributes: 16 | label: Describe the bug 17 | description: A clear and concise description of what the bug is. 18 | validations: 19 | required: true 20 | 21 | - type: textarea 22 | attributes: 23 | label: To Reproduce 24 | description: Steps to reproduce this behaviour 25 | placeholder: | 26 | 1. Go to '...' 27 | 2. Click on '...' 28 | 3. Scroll down to '...' 29 | 4. See error 30 | validations: 31 | required: true 32 | 33 | - type: textarea 34 | attributes: 35 | label: Expected behaviour 36 | description: A clear and concise description of what you expected to happen. 37 | validations: 38 | required: true 39 | 40 | - type: input 41 | attributes: 42 | label: Error log (if applicable) 43 | description: If you are reporting a console error, upload any relevant log excerpts to either https://paste.gg/ or https://gist.github.com, save and the paste the link in this box. 44 | 45 | - type: textarea 46 | attributes: 47 | label: Installed plugins 48 | description: What plugins are you using? (`/plugins`) 49 | placeholder: "Example output: Essentials, PlotSquared, ServiceIO, VaultChatFormatter" 50 | validations: 51 | required: true 52 | 53 | - type: input 54 | attributes: 55 | label: ServiceIO Version 56 | description: What version of ServiceIO are you running? (`/version ServiceIO`) 57 | placeholder: "For example: version 1.1.0" 58 | validations: 59 | required: true 60 | 61 | - type: textarea 62 | attributes: 63 | label: Paper version 64 | description: | 65 | Run `/version` on your server and **paste** the full, unmodified output here. 66 | "latest" is *not* a version; we require the output of `/version` so we can adequately track down the issue. 67 | Additionally, do NOT provide a screenshot, you MUST paste the entire output. 68 |
69 | Example 70 | 71 | ``` 72 | > version 73 | [20:34:42 INFO]: Checking version, please wait... 74 | [20:34:42 INFO]: This server is running Paper version 1.21-105-master@7e91a2c (2024-07-20T21:04:31Z) (Implementing API version 1.21-R0.1-SNAPSHOT) 75 | [20:34:42 INFO]: You are running the latest version 76 | [20:34:42 INFO]: Previous version: 1.21-103-aa3b356 (MC: 1.21) 77 | ``` 78 | 79 |
80 | validations: 81 | required: true 82 | 83 | - type: checkboxes 84 | attributes: 85 | label: Checklist 86 | description: Make sure you have followed each of the steps outlined here. 87 | options: 88 | - label: I am using the newest build from https://github.com/TheNextLvl-net/service-io and the issue still persists. 89 | required: true 90 | 91 | - type: textarea 92 | attributes: 93 | label: Anything else? 94 | description: You can provide additional context below. 95 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest an idea for this project 3 | labels: 4 | - enhancement 5 | assignees: 6 | - NonSwag 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thanks for taking the time to fill out this feature request for ServiceIO! Fill out the following form to your best 12 | ability to help us understand your feature request and greatly improve the change of it getting added. 13 | For anything else than a feature request, use: [our Discord server](https://thenextlvl.net/discord). 14 | 15 | - type: textarea 16 | attributes: 17 | label: What feature do you want to see added? 18 | description: A clear and concise description of your feature request. 19 | validations: 20 | required: true 21 | 22 | - type: textarea 23 | attributes: 24 | label: Are there any alternatives? 25 | description: List any alternatives you might have tried 26 | validations: 27 | required: true 28 | 29 | - type: textarea 30 | attributes: 31 | label: Anything else? 32 | description: You can provide additional context below. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/incompatible_plugin.yml: -------------------------------------------------------------------------------- 1 | name: Incompatible plugin 2 | description: Report a plugin does not recognice ServiceIO as Vault 3 | labels: 4 | - incompatibility 5 | assignees: 6 | - NonSwag 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thanks for taking the time to submit an incompatible plugin to ServiceIO! 12 | For questions and updates feel free to join [our Discord server](https://thenextlvl.net/discord). 13 | 14 | - type: input 15 | attributes: 16 | label: The name of the incompatible plugin 17 | validations: 18 | required: true 19 | 20 | - type: input 21 | attributes: 22 | label: Link to the plugin (GitHub, GitLab, Website, Discord...) 23 | description: A link to the plugin in question 24 | validations: 25 | required: true 26 | 27 | - type: textarea 28 | attributes: 29 | label: Anything else? 30 | description: You can provide additional context below. 31 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended", 5 | ":disableDependencyDashboard" 6 | ], 7 | "dependencyDashboard": false 8 | } 9 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: [ pull_request, push ] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Checkout sources 8 | uses: actions/checkout@v4 9 | - name: Setup Java 10 | uses: actions/setup-java@v4 11 | with: 12 | distribution: 'temurin' 13 | java-version: 21 14 | - name: Setup Gradle 15 | uses: gradle/actions/setup-gradle@v4 16 | - name: Build with Gradle 17 | run: ./gradlew build 18 | - name: Test with Gradle 19 | run: ./gradlew test -------------------------------------------------------------------------------- /.github/workflows/hangar-publish.yml: -------------------------------------------------------------------------------- 1 | name: Hangar Publish 2 | on: 3 | release: 4 | types: [ prereleased, released ] 5 | jobs: 6 | build: 7 | env: 8 | HANGAR_API_TOKEN: ${{ secrets.HANGAR_API_TOKEN }} 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout sources 12 | uses: actions/checkout@v4 13 | - name: Setup Java 14 | uses: actions/setup-java@v4 15 | with: 16 | distribution: 'temurin' 17 | java-version: 21 18 | - name: Setup Gradle 19 | uses: gradle/actions/setup-gradle@v4 20 | - name: Publish with Gradle to Hangar 21 | run: ./gradlew publishAllPublicationsToHangar -------------------------------------------------------------------------------- /.github/workflows/maven-publish.yml: -------------------------------------------------------------------------------- 1 | name: Maven Publish 2 | on: 3 | release: 4 | types: [ prereleased, released ] 5 | jobs: 6 | build: 7 | env: 8 | REPOSITORY_USER: ${{ secrets.REPOSITORY_USER }} 9 | REPOSITORY_TOKEN: ${{ secrets.REPOSITORY_TOKEN }} 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout sources 13 | uses: actions/checkout@v4 14 | - name: Setup Java 15 | uses: actions/setup-java@v4 16 | with: 17 | distribution: 'temurin' 18 | java-version: 21 19 | - name: Setup Gradle 20 | uses: gradle/actions/setup-gradle@v4 21 | - name: Publish with Gradle to Repository 22 | run: ./gradlew publish -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | id("java-library") 4 | id("maven-publish") 5 | } 6 | 7 | group = "net.thenextlvl.services" 8 | version = "2.2.0" 9 | 10 | java { 11 | toolchain.languageVersion = JavaLanguageVersion.of(21) 12 | withSourcesJar() 13 | withJavadocJar() 14 | } 15 | 16 | tasks.compileJava { 17 | options.release.set(21) 18 | } 19 | 20 | repositories { 21 | mavenCentral() 22 | maven("https://repo.thenextlvl.net/releases") 23 | maven("https://repo.papermc.io/repository/maven-public/") 24 | } 25 | 26 | dependencies { 27 | compileOnly("io.papermc.paper:paper-api:1.21.5-R0.1-SNAPSHOT") 28 | } 29 | 30 | publishing { 31 | publications.create("maven") { 32 | from(components["java"]) 33 | } 34 | repositories.maven { 35 | val channel = if ((version as String).contains("-pre")) "snapshots" else "releases" 36 | url = uri("https://repo.thenextlvl.net/$channel") 37 | credentials { 38 | username = System.getenv("REPOSITORY_USER") 39 | password = System.getenv("REPOSITORY_TOKEN") 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | gameVersions=1.21,1.21.1,1.21.2,1.21.3,1.21.4,1.21.5 2 | -------------------------------------------------------------------------------- /gradle/gradle-daemon-jvm.properties: -------------------------------------------------------------------------------- 1 | #This file is generated by updateDaemonJvm 2 | toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect 3 | toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect 4 | toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect 5 | toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect 6 | toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/73bcfb608d1fde9fb62e462f834a3299/redirect 7 | toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/846ee0d876d26a26f37aa1ce8de73224/redirect 8 | toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect 9 | toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect 10 | toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/9482ddec596298c84656d31d16652665/redirect 11 | toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/39701d92e1756bb2f141eb67cd4c660e/redirect 12 | toolchainVersion=21 13 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheNextLvl-net/service-io/b90954c31f66b94de45e6f36335facb33268a5d6/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH= 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /plugin/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import io.papermc.hangarpublishplugin.model.Platforms 2 | import net.minecrell.pluginyml.bukkit.BukkitPluginDescription 3 | import net.minecrell.pluginyml.paper.PaperPluginDescription 4 | 5 | plugins { 6 | id("java") 7 | 8 | id("com.gradleup.shadow") version "9.0.0-beta15" 9 | id("com.modrinth.minotaur") version "2.+" 10 | id("de.eldoria.plugin-yml.paper") version "0.7.1" 11 | id("io.papermc.hangar-publish-plugin") version "0.1.3" 12 | } 13 | 14 | group = rootProject.group 15 | version = rootProject.version 16 | 17 | java { 18 | toolchain.languageVersion = JavaLanguageVersion.of(21) 19 | } 20 | 21 | tasks.compileJava { 22 | options.release.set(21) 23 | } 24 | 25 | repositories { 26 | mavenCentral() 27 | maven("https://jitpack.io") 28 | maven("https://maven.citizensnpcs.co/repo") 29 | maven("https://repo.papermc.io/repository/maven-public/") 30 | maven("https://repo.fancyplugins.de/releases") 31 | maven("https://repo.thenextlvl.net/releases") 32 | } 33 | 34 | dependencies { 35 | compileOnly("io.papermc.paper:paper-api:1.21.5-R0.1-SNAPSHOT") 36 | 37 | compileOnly("com.github.ElgarL:groupmanager:3.2") 38 | compileOnly("com.github.decentsoftware-eu:decentholograms:2.8.17") 39 | compileOnly("de.oliver:FancyHolograms:2.5.0") 40 | compileOnly("de.oliver:FancyNpcs:2.5.1") 41 | compileOnly("net.citizensnpcs:citizens-main:2.0.37-SNAPSHOT") 42 | compileOnly("net.luckperms:api:5.5") 43 | 44 | implementation("com.github.MilkBowl:VaultAPI:1.7.1") 45 | implementation("net.thenextlvl.core:i18n:3.2.0") 46 | implementation("net.thenextlvl.core:paper:2.1.2") 47 | implementation("org.bstats:bstats-bukkit:3.1.0") 48 | 49 | implementation(rootProject) 50 | 51 | testImplementation("org.junit.jupiter:junit-jupiter") 52 | testImplementation(platform("org.junit:junit-bom:5.13.1")) 53 | } 54 | 55 | tasks.shadowJar { 56 | relocate("org.bstats", "net.thenextlvl.services.bstats") 57 | archiveBaseName.set("service-io") 58 | } 59 | 60 | tasks.test { 61 | useJUnitPlatform() 62 | } 63 | 64 | paper { 65 | name = "ServiceIO" 66 | main = "net.thenextlvl.service.ServicePlugin" 67 | author = "NonSwag" 68 | apiVersion = "1.21" 69 | foliaSupported = true 70 | load = BukkitPluginDescription.PluginLoadOrder.STARTUP 71 | 72 | website = "https://thenextlvl.net" 73 | provides = listOf("Vault") 74 | 75 | serverDependencies { 76 | register("Citizens") { 77 | load = PaperPluginDescription.RelativeLoadOrder.BEFORE 78 | required = false 79 | } 80 | register("DecentHolograms") { 81 | load = PaperPluginDescription.RelativeLoadOrder.BEFORE 82 | required = false 83 | } 84 | register("FancyHolograms") { 85 | load = PaperPluginDescription.RelativeLoadOrder.BEFORE 86 | required = false 87 | } 88 | register("FancyNpcs") { 89 | load = PaperPluginDescription.RelativeLoadOrder.BEFORE 90 | required = false 91 | } 92 | register("GroupManager") { 93 | load = PaperPluginDescription.RelativeLoadOrder.BEFORE 94 | required = false 95 | } 96 | register("LuckPerms") { 97 | load = PaperPluginDescription.RelativeLoadOrder.BEFORE 98 | required = false 99 | } 100 | } 101 | 102 | permissions { 103 | register("vault.admin") { 104 | description = "Backwards compatibility for Vault permission" 105 | default = BukkitPluginDescription.Permission.Default.OP 106 | children = listOf("service.admin") 107 | } 108 | register("service.admin") { 109 | description = "Grants access to all /services commands" 110 | default = BukkitPluginDescription.Permission.Default.OP 111 | children = listOf("service.info", "service.convert") 112 | } 113 | register("service.info") { 114 | description = "Grants access to /service info" 115 | default = BukkitPluginDescription.Permission.Default.OP 116 | children = listOf("service.command") 117 | } 118 | register("service.convert") { 119 | description = "Grants access to /service convert" 120 | default = BukkitPluginDescription.Permission.Default.OP 121 | children = listOf("service.command") 122 | } 123 | } 124 | } 125 | 126 | val versionString: String = project.version as String 127 | val isRelease: Boolean = !versionString.contains("-pre") 128 | 129 | val versions: List = (property("gameVersions") as String) 130 | .split(",") 131 | .map { it.trim() } 132 | 133 | hangarPublish { // docs - https://docs.papermc.io/misc/hangar-publishing 134 | publications.register("plugin") { 135 | id.set("ServiceIO") 136 | version.set(versionString) 137 | channel.set(if (isRelease) "Release" else "Snapshot") 138 | apiKey.set(System.getenv("HANGAR_API_TOKEN")) 139 | platforms.register(Platforms.PAPER) { 140 | jar.set(tasks.shadowJar.flatMap { it.archiveFile }) 141 | platformVersions.set(versions) 142 | } 143 | } 144 | } 145 | 146 | modrinth { 147 | token.set(System.getenv("MODRINTH_TOKEN")) 148 | projectId.set("MNPyHOe7") 149 | versionType = if (isRelease) "release" else "beta" 150 | uploadFile.set(tasks.shadowJar) 151 | gameVersions.set(versions) 152 | loaders.add("paper") 153 | loaders.add("folia") 154 | dependencies { 155 | optional.project("luckperms", "decentholograms", "fancynpcs", "fancyholograms") 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/command/ServiceCommand.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.command; 2 | 3 | import io.papermc.paper.command.brigadier.Commands; 4 | import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; 5 | import net.thenextlvl.service.ServicePlugin; 6 | import org.jspecify.annotations.NullMarked; 7 | 8 | @NullMarked 9 | public class ServiceCommand { 10 | public void register(ServicePlugin plugin) { 11 | var command = Commands.literal("service") 12 | .requires(stack -> stack.getSender().hasPermission("service.command")) 13 | .then(new ServiceInfoCommand(plugin).create()) 14 | .then(new ServiceConvertCommand(plugin).create()) 15 | .build(); 16 | plugin.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS.newHandler(event -> 17 | event.registrar().register(command))); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/command/argument/BankArgumentType.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.command.argument; 2 | 3 | import com.mojang.brigadier.arguments.StringArgumentType; 4 | import com.mojang.brigadier.context.CommandContext; 5 | import core.paper.command.WrappedArgumentType; 6 | import net.thenextlvl.service.ServicePlugin; 7 | import net.thenextlvl.service.api.economy.bank.BankController; 8 | import org.bukkit.plugin.RegisteredServiceProvider; 9 | import org.jspecify.annotations.NullMarked; 10 | 11 | import java.util.function.BiPredicate; 12 | 13 | @NullMarked 14 | public class BankArgumentType extends WrappedArgumentType { 15 | public BankArgumentType(ServicePlugin plugin, BiPredicate, BankController> filter) { 16 | super(StringArgumentType.string(), (reader, type) -> plugin.getServer().getServicesManager() 17 | .getRegistrations(BankController.class).stream() 18 | .map(RegisteredServiceProvider::getProvider) 19 | .filter(controller -> controller.getName().equals(type)) 20 | .findAny().orElseThrow(), (context, builder) -> { 21 | plugin.getServer().getServicesManager() 22 | .getRegistrations(BankController.class).stream() 23 | .map(RegisteredServiceProvider::getProvider) 24 | .filter(controller -> filter.test(context, controller)) 25 | .map(BankController::getName) 26 | .map(StringArgumentType::escapeIfRequired) 27 | .filter(name -> name.contains(builder.getRemaining())) 28 | .forEach(builder::suggest); 29 | return builder.buildFuture(); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/command/argument/CharacterArgumentType.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.command.argument; 2 | 3 | import com.mojang.brigadier.arguments.StringArgumentType; 4 | import com.mojang.brigadier.context.CommandContext; 5 | import core.paper.command.WrappedArgumentType; 6 | import net.thenextlvl.service.ServicePlugin; 7 | import net.thenextlvl.service.api.character.CharacterController; 8 | import org.bukkit.plugin.RegisteredServiceProvider; 9 | import org.jspecify.annotations.NullMarked; 10 | 11 | import java.util.function.BiPredicate; 12 | 13 | @NullMarked 14 | public class CharacterArgumentType extends WrappedArgumentType { 15 | public CharacterArgumentType(ServicePlugin plugin, BiPredicate, CharacterController> filter) { 16 | super(StringArgumentType.string(), (reader, type) -> plugin.getServer().getServicesManager() 17 | .getRegistrations(CharacterController.class).stream() 18 | .map(RegisteredServiceProvider::getProvider) 19 | .filter(controller -> controller.getName().equals(type)) 20 | .findAny().orElseThrow(), (context, builder) -> { 21 | plugin.getServer().getServicesManager() 22 | .getRegistrations(CharacterController.class).stream() 23 | .map(RegisteredServiceProvider::getProvider) 24 | .filter(controller -> filter.test(context, controller)) 25 | .map(CharacterController::getName) 26 | .map(StringArgumentType::escapeIfRequired) 27 | .filter(name -> name.contains(builder.getRemaining())) 28 | .forEach(builder::suggest); 29 | return builder.buildFuture(); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/command/argument/ChatArgumentType.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.command.argument; 2 | 3 | import com.mojang.brigadier.arguments.StringArgumentType; 4 | import com.mojang.brigadier.context.CommandContext; 5 | import core.paper.command.WrappedArgumentType; 6 | import net.thenextlvl.service.ServicePlugin; 7 | import net.thenextlvl.service.api.chat.ChatController; 8 | import org.bukkit.plugin.RegisteredServiceProvider; 9 | import org.jspecify.annotations.NullMarked; 10 | 11 | import java.util.function.BiPredicate; 12 | 13 | @NullMarked 14 | public class ChatArgumentType extends WrappedArgumentType { 15 | public ChatArgumentType(ServicePlugin plugin, BiPredicate, ChatController> filter) { 16 | super(StringArgumentType.string(), (reader, type) -> plugin.getServer().getServicesManager() 17 | .getRegistrations(ChatController.class).stream() 18 | .map(RegisteredServiceProvider::getProvider) 19 | .filter(controller -> controller.getName().equals(type)) 20 | .findAny().orElseThrow(), (context, builder) -> { 21 | plugin.getServer().getServicesManager() 22 | .getRegistrations(ChatController.class).stream() 23 | .map(RegisteredServiceProvider::getProvider) 24 | .filter(controller -> filter.test(context, controller)) 25 | .map(ChatController::getName) 26 | .map(StringArgumentType::escapeIfRequired) 27 | .filter(name -> name.contains(builder.getRemaining())) 28 | .forEach(builder::suggest); 29 | return builder.buildFuture(); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/command/argument/EconomyArgumentType.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.command.argument; 2 | 3 | import com.mojang.brigadier.arguments.StringArgumentType; 4 | import com.mojang.brigadier.context.CommandContext; 5 | import core.paper.command.WrappedArgumentType; 6 | import net.thenextlvl.service.ServicePlugin; 7 | import net.thenextlvl.service.api.economy.EconomyController; 8 | import org.bukkit.plugin.RegisteredServiceProvider; 9 | import org.jspecify.annotations.NullMarked; 10 | 11 | import java.util.function.BiPredicate; 12 | 13 | @NullMarked 14 | public class EconomyArgumentType extends WrappedArgumentType { 15 | public EconomyArgumentType(ServicePlugin plugin, BiPredicate, EconomyController> filter) { 16 | super(StringArgumentType.string(), (reader, type) -> plugin.getServer().getServicesManager() 17 | .getRegistrations(EconomyController.class).stream() 18 | .map(RegisteredServiceProvider::getProvider) 19 | .filter(controller -> controller.getName().equals(type)) 20 | .findAny().orElseThrow(), (context, builder) -> { 21 | plugin.getServer().getServicesManager() 22 | .getRegistrations(EconomyController.class).stream() 23 | .map(RegisteredServiceProvider::getProvider) 24 | .filter(controller -> filter.test(context, controller)) 25 | .map(EconomyController::getName) 26 | .map(StringArgumentType::escapeIfRequired) 27 | .filter(name -> name.contains(builder.getRemaining())) 28 | .forEach(builder::suggest); 29 | return builder.buildFuture(); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/command/argument/GroupArgumentType.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.command.argument; 2 | 3 | import com.mojang.brigadier.arguments.StringArgumentType; 4 | import com.mojang.brigadier.context.CommandContext; 5 | import core.paper.command.WrappedArgumentType; 6 | import net.thenextlvl.service.ServicePlugin; 7 | import net.thenextlvl.service.api.group.GroupController; 8 | import org.bukkit.plugin.RegisteredServiceProvider; 9 | import org.jspecify.annotations.NullMarked; 10 | 11 | import java.util.function.BiPredicate; 12 | 13 | @NullMarked 14 | public class GroupArgumentType extends WrappedArgumentType { 15 | public GroupArgumentType(ServicePlugin plugin, BiPredicate, GroupController> filter) { 16 | super(StringArgumentType.string(), (reader, type) -> plugin.getServer().getServicesManager() 17 | .getRegistrations(GroupController.class).stream() 18 | .map(RegisteredServiceProvider::getProvider) 19 | .filter(controller -> controller.getName().equals(type)) 20 | .findAny().orElseThrow(), (context, builder) -> { 21 | plugin.getServer().getServicesManager() 22 | .getRegistrations(GroupController.class).stream() 23 | .map(RegisteredServiceProvider::getProvider) 24 | .filter(controller -> filter.test(context, controller)) 25 | .map(GroupController::getName) 26 | .map(StringArgumentType::escapeIfRequired) 27 | .filter(name -> name.contains(builder.getRemaining())) 28 | .forEach(builder::suggest); 29 | return builder.buildFuture(); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/command/argument/HologramArgumentType.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.command.argument; 2 | 3 | import com.mojang.brigadier.arguments.StringArgumentType; 4 | import com.mojang.brigadier.context.CommandContext; 5 | import core.paper.command.WrappedArgumentType; 6 | import net.thenextlvl.service.ServicePlugin; 7 | import net.thenextlvl.service.api.hologram.HologramController; 8 | import org.bukkit.plugin.RegisteredServiceProvider; 9 | import org.jspecify.annotations.NullMarked; 10 | 11 | import java.util.function.BiPredicate; 12 | 13 | @NullMarked 14 | public class HologramArgumentType extends WrappedArgumentType { 15 | public HologramArgumentType(ServicePlugin plugin, BiPredicate, HologramController> filter) { 16 | super(StringArgumentType.string(), (reader, type) -> plugin.getServer().getServicesManager() 17 | .getRegistrations(HologramController.class).stream() 18 | .map(RegisteredServiceProvider::getProvider) 19 | .filter(controller -> controller.getName().equals(type)) 20 | .findAny().orElseThrow(), (context, builder) -> { 21 | plugin.getServer().getServicesManager() 22 | .getRegistrations(HologramController.class).stream() 23 | .map(RegisteredServiceProvider::getProvider) 24 | .filter(controller -> filter.test(context, controller)) 25 | .map(HologramController::getName) 26 | .map(StringArgumentType::escapeIfRequired) 27 | .filter(name -> name.contains(builder.getRemaining())) 28 | .forEach(builder::suggest); 29 | return builder.buildFuture(); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/command/argument/PermissionArgumentType.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.command.argument; 2 | 3 | import com.mojang.brigadier.arguments.StringArgumentType; 4 | import com.mojang.brigadier.context.CommandContext; 5 | import core.paper.command.WrappedArgumentType; 6 | import net.thenextlvl.service.ServicePlugin; 7 | import net.thenextlvl.service.api.permission.PermissionController; 8 | import org.bukkit.plugin.RegisteredServiceProvider; 9 | import org.jspecify.annotations.NullMarked; 10 | 11 | import java.util.function.BiPredicate; 12 | 13 | @NullMarked 14 | public class PermissionArgumentType extends WrappedArgumentType { 15 | public PermissionArgumentType(ServicePlugin plugin, BiPredicate, PermissionController> filter) { 16 | super(StringArgumentType.string(), (reader, type) -> plugin.getServer().getServicesManager() 17 | .getRegistrations(PermissionController.class).stream() 18 | .map(RegisteredServiceProvider::getProvider) 19 | .filter(controller -> controller.getName().equals(type)) 20 | .findAny().orElseThrow(), (context, builder) -> { 21 | plugin.getServer().getServicesManager() 22 | .getRegistrations(PermissionController.class).stream() 23 | .map(RegisteredServiceProvider::getProvider) 24 | .filter(controller -> filter.test(context, controller)) 25 | .map(PermissionController::getName) 26 | .map(StringArgumentType::escapeIfRequired) 27 | .filter(name -> name.contains(builder.getRemaining())) 28 | .forEach(builder::suggest); 29 | return builder.buildFuture(); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/controller/character/CitizensCharacterController.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.controller.character; 2 | 3 | import net.citizensnpcs.api.CitizensAPI; 4 | import net.citizensnpcs.api.npc.NPC; 5 | import net.thenextlvl.service.ServicePlugin; 6 | import net.thenextlvl.service.api.character.Character; 7 | import net.thenextlvl.service.api.character.CharacterCapability; 8 | import net.thenextlvl.service.api.character.CharacterController; 9 | import net.thenextlvl.service.model.character.citizens.CitizensCharacter; 10 | import org.bukkit.Location; 11 | import org.bukkit.World; 12 | import org.bukkit.entity.Entity; 13 | import org.bukkit.entity.EntityType; 14 | import org.bukkit.entity.Player; 15 | import org.bukkit.plugin.Plugin; 16 | import org.jetbrains.annotations.Unmodifiable; 17 | import org.jspecify.annotations.NullMarked; 18 | 19 | import java.util.Collection; 20 | import java.util.EnumSet; 21 | import java.util.List; 22 | import java.util.Optional; 23 | import java.util.UUID; 24 | import java.util.stream.Collectors; 25 | import java.util.stream.Stream; 26 | import java.util.stream.StreamSupport; 27 | 28 | @NullMarked 29 | public class CitizensCharacterController implements CharacterController { 30 | private final EnumSet capabilities = EnumSet.of( 31 | CharacterCapability.HEALTH, 32 | CharacterCapability.INTERACTIONS, 33 | CharacterCapability.NON_PLAYER_ENTITIES, 34 | CharacterCapability.ACTUAL_ENTITIES 35 | ); 36 | private final ServicePlugin plugin; 37 | 38 | public CitizensCharacterController(ServicePlugin plugin) { 39 | this.plugin = plugin; 40 | } 41 | 42 | @Override 43 | public Character createNPC(String name, Class type) { 44 | return createNPC(name, plugin.getEntityTypeByClass(type)); 45 | } 46 | 47 | @Override 48 | public Character createNPC(String name, EntityType type) { 49 | var npc = CitizensAPI.getNPCRegistry().createNPC(type, name); 50 | return new CitizensCharacter<>(npc); 51 | } 52 | 53 | @Override 54 | public Character spawnNPC(String name, Location location, Class type) { 55 | return spawnNPC(name, location, plugin.getEntityTypeByClass(type)); 56 | } 57 | 58 | @Override 59 | public Character spawnNPC(String name, Location location, EntityType type) { 60 | var npc = CitizensAPI.getNPCRegistry().createNPC(type, name, location); 61 | return new CitizensCharacter<>(npc); 62 | } 63 | 64 | @Override 65 | public Optional> getNPC(T entity) { 66 | return Optional.ofNullable(CitizensAPI.getNPCRegistry().getNPC(entity)) 67 | .map(CitizensCharacter::new); 68 | } 69 | 70 | @Override 71 | public @Unmodifiable List> getNPCs() { 72 | return streamNPCs().map(CitizensCharacter::new) 73 | .collect(Collectors.toUnmodifiableList()); 74 | } 75 | 76 | @Override 77 | public @Unmodifiable List> getNPCs(Player player) { 78 | return streamNPCs() 79 | .filter(character -> !character.isHiddenFrom(player)) 80 | .map(CitizensCharacter::new) 81 | .collect(Collectors.toUnmodifiableList()); 82 | } 83 | 84 | @Override 85 | public @Unmodifiable List> getNPCs(World world) { 86 | return streamNPCs() 87 | .filter(character -> world.equals(character.getEntity().getWorld())) 88 | .map(CitizensCharacter::new) 89 | .collect(Collectors.toUnmodifiableList()); 90 | } 91 | 92 | @Override 93 | public Optional> getNPC(String name) { 94 | return streamNPCs().filter(npc -> name.equals(npc.getRawName())) 95 | .>map(CitizensCharacter::new) 96 | .findAny(); 97 | } 98 | 99 | @Override 100 | public Character createNPC(String name) { 101 | return createNPC(name, Player.class); 102 | } 103 | 104 | @Override 105 | public Character spawnNPC(String name, Location location) { 106 | return spawnNPC(name, location, Player.class); 107 | } 108 | 109 | @Override 110 | public Optional> getNPC(UUID uuid) { 111 | return Optional.ofNullable(plugin.getServer().getEntity(uuid)) 112 | .map(CitizensAPI.getNPCRegistry()::getNPC) 113 | .map(CitizensCharacter::new); 114 | } 115 | 116 | @Override 117 | public Optional> getNPC(Player player) { 118 | return Optional.ofNullable(CitizensAPI.getNPCRegistry().getNPC(player)) 119 | .filter(npc -> npc.getEntity().getType().equals(EntityType.PLAYER)) 120 | .map(CitizensCharacter::new); 121 | } 122 | 123 | @Override 124 | public Plugin getPlugin() { 125 | return CitizensAPI.getPlugin(); 126 | } 127 | 128 | @Override 129 | public String getName() { 130 | return "Citizens"; 131 | } 132 | 133 | @Override 134 | public boolean isNPC(Entity entity) { 135 | return CitizensAPI.getNPCRegistry().isNPC(entity); 136 | } 137 | 138 | private static Stream streamNPCs() { 139 | return StreamSupport.stream(CitizensAPI.getNPCRegistries().spliterator(), false) 140 | .flatMap(iterable -> StreamSupport.stream(iterable.spliterator(), false)); 141 | } 142 | 143 | @Override 144 | public @Unmodifiable EnumSet getCapabilities() { 145 | return EnumSet.copyOf(this.capabilities); 146 | } 147 | 148 | @Override 149 | public boolean hasCapabilities(Collection capabilities) { 150 | return this.capabilities.containsAll(capabilities); 151 | } 152 | 153 | @Override 154 | public boolean hasCapability(CharacterCapability capability) { 155 | return this.capabilities.contains(capability); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/controller/character/FancyCharacterController.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.controller.character; 2 | 3 | import de.oliver.fancynpcs.api.FancyNpcsPlugin; 4 | import de.oliver.fancynpcs.api.NpcData; 5 | import net.thenextlvl.service.ServicePlugin; 6 | import net.thenextlvl.service.api.character.Character; 7 | import net.thenextlvl.service.api.character.CharacterCapability; 8 | import net.thenextlvl.service.api.character.CharacterController; 9 | import net.thenextlvl.service.model.character.fancy.FancyCharacter; 10 | import org.bukkit.Location; 11 | import org.bukkit.World; 12 | import org.bukkit.entity.Entity; 13 | import org.bukkit.entity.EntityType; 14 | import org.bukkit.entity.Player; 15 | import org.bukkit.plugin.Plugin; 16 | import org.jetbrains.annotations.Unmodifiable; 17 | import org.jspecify.annotations.NullMarked; 18 | 19 | import java.util.Collection; 20 | import java.util.EnumSet; 21 | import java.util.List; 22 | import java.util.Optional; 23 | import java.util.UUID; 24 | import java.util.stream.Collectors; 25 | 26 | @NullMarked 27 | public class FancyCharacterController implements CharacterController { 28 | private final EnumSet capabilities = EnumSet.of( 29 | CharacterCapability.INTERACTIONS, 30 | CharacterCapability.NON_PLAYER_ENTITIES 31 | ); 32 | private final ServicePlugin plugin; 33 | 34 | public FancyCharacterController(ServicePlugin plugin) { 35 | this.plugin = plugin; 36 | } 37 | 38 | @Override 39 | public Character createNPC(String name, Class type) { 40 | return createNPC(name, plugin.getEntityTypeByClass(type)); 41 | } 42 | 43 | @Override 44 | public Character createNPC(String name, EntityType type) { 45 | var plugin = FancyNpcsPlugin.get(); 46 | 47 | var location = new Location(this.plugin.getServer().getWorlds().getFirst(), 0, 0, 0); 48 | var data = new NpcData(name, new UUID(0, 0), location); 49 | data.setType(type); 50 | var npc = plugin.getNpcAdapter().apply(data); 51 | 52 | plugin.getNpcManager().registerNpc(npc); 53 | npc.create(); 54 | return new FancyCharacter<>(npc); 55 | } 56 | 57 | @Override 58 | public Character spawnNPC(String name, Location location, Class type) { 59 | return spawnNPC(name, location, plugin.getEntityTypeByClass(type)); 60 | } 61 | 62 | @Override 63 | public Character spawnNPC(String name, Location location, EntityType type) { 64 | var npc = this.createNPC(name, type); 65 | npc.spawn(location); 66 | return npc; 67 | } 68 | 69 | @Override 70 | public Optional> getNPC(T entity) { 71 | return Optional.empty(); 72 | } 73 | 74 | @Override 75 | public Character createNPC(String name) { 76 | return createNPC(name, Player.class); 77 | } 78 | 79 | @Override 80 | public Character spawnNPC(String name, Location location) { 81 | return spawnNPC(name, location, Player.class); 82 | } 83 | 84 | @Override 85 | public @Unmodifiable List> getNPCs() { 86 | return FancyNpcsPlugin.get().getNpcManager().getAllNpcs().stream() 87 | .map(FancyCharacter::new) 88 | .collect(Collectors.toUnmodifiableList()); 89 | } 90 | 91 | @Override 92 | public @Unmodifiable List> getNPCs(Player player) { 93 | return FancyNpcsPlugin.get().getNpcManager().getAllNpcs().stream() 94 | .filter(npc -> npc.getIsVisibleForPlayer().containsKey(player.getUniqueId())) 95 | .map(FancyCharacter::new) 96 | .collect(Collectors.toUnmodifiableList()); 97 | } 98 | 99 | @Override 100 | public @Unmodifiable List> getNPCs(World world) { 101 | return FancyNpcsPlugin.get().getNpcManager().getAllNpcs().stream() 102 | .filter(npc -> npc.getData().getLocation() != null) 103 | .filter(npc -> world.equals(npc.getData().getLocation().getWorld())) 104 | .map(FancyCharacter::new) 105 | .collect(Collectors.toUnmodifiableList()); 106 | } 107 | 108 | @Override 109 | public Optional> getNPC(String name) { 110 | return Optional.ofNullable(FancyNpcsPlugin.get().getNpcManager().getNpc(name)) 111 | .map(FancyCharacter::new); 112 | } 113 | 114 | @Override 115 | public Optional> getNPC(UUID uuid) { 116 | return Optional.empty(); 117 | } 118 | 119 | @Override 120 | public Optional> getNPC(Player player) { 121 | return Optional.empty(); 122 | } 123 | 124 | @Override 125 | public @Unmodifiable EnumSet getCapabilities() { 126 | return EnumSet.copyOf(this.capabilities); 127 | } 128 | 129 | @Override 130 | public boolean hasCapabilities(Collection capabilities) { 131 | return this.capabilities.containsAll(capabilities); 132 | } 133 | 134 | @Override 135 | public boolean hasCapability(CharacterCapability capability) { 136 | return this.capabilities.contains(capability); 137 | } 138 | 139 | @Override 140 | public Plugin getPlugin() { 141 | return FancyNpcsPlugin.get().getPlugin(); 142 | } 143 | 144 | @Override 145 | public String getName() { 146 | return "FancyNpcs"; 147 | } 148 | 149 | @Override 150 | public boolean isNPC(Entity entity) { 151 | return false; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/controller/chat/GroupManagerChatController.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.controller.chat; 2 | 3 | import net.thenextlvl.service.api.chat.ChatController; 4 | import net.thenextlvl.service.api.chat.ChatProfile; 5 | import net.thenextlvl.service.model.chat.GroupManagerChatProfile; 6 | import org.anjocaido.groupmanager.GroupManager; 7 | import org.anjocaido.groupmanager.dataholder.WorldDataHolder; 8 | import org.bukkit.OfflinePlayer; 9 | import org.bukkit.World; 10 | import org.bukkit.plugin.Plugin; 11 | import org.bukkit.plugin.java.JavaPlugin; 12 | import org.jspecify.annotations.NullMarked; 13 | import org.jspecify.annotations.Nullable; 14 | 15 | import java.util.Optional; 16 | import java.util.UUID; 17 | import java.util.concurrent.CompletableFuture; 18 | 19 | @NullMarked 20 | public class GroupManagerChatController implements ChatController { 21 | private final GroupManager groupManager = JavaPlugin.getPlugin(GroupManager.class); 22 | 23 | @Override 24 | public CompletableFuture loadProfile(OfflinePlayer player) { 25 | return getProfile(player) 26 | .map(CompletableFuture::completedFuture) 27 | .orElseGet(() -> CompletableFuture.completedFuture(null)); 28 | } 29 | 30 | @Override 31 | public CompletableFuture loadProfile(OfflinePlayer player, World world) { 32 | return getProfile(player, world) 33 | .map(CompletableFuture::completedFuture) 34 | .orElseGet(() -> CompletableFuture.completedFuture(null)); 35 | } 36 | 37 | @Override 38 | public CompletableFuture loadProfile(UUID uuid) { 39 | return getProfile(uuid) 40 | .map(CompletableFuture::completedFuture) 41 | .orElseGet(() -> CompletableFuture.completedFuture(null)); 42 | } 43 | 44 | @Override 45 | public CompletableFuture loadProfile(UUID uuid, World world) { 46 | return getProfile(uuid, world) 47 | .map(CompletableFuture::completedFuture) 48 | .orElseGet(() -> CompletableFuture.completedFuture(null)); 49 | } 50 | 51 | @Override 52 | public Optional getProfile(OfflinePlayer player) { 53 | var holder = groupManager.getWorldsHolder().getDefaultWorld(); 54 | return getProfile(holder, player.getUniqueId(), player.getName()); 55 | } 56 | 57 | @Override 58 | public Optional getProfile(OfflinePlayer player, World world) { 59 | var holder = groupManager.getWorldsHolder().getWorldData(world.getName()); 60 | return getProfile(holder, player.getUniqueId(), player.getName()); 61 | } 62 | 63 | @Override 64 | public Optional getProfile(UUID uuid) { 65 | var holder = groupManager.getWorldsHolder().getDefaultWorld(); 66 | return getProfile(holder, uuid, null); 67 | } 68 | 69 | @Override 70 | public Optional getProfile(UUID uuid, World world) { 71 | var holder = groupManager.getWorldsHolder().getWorldData(world.getName()); 72 | return getProfile(holder, uuid, null); 73 | } 74 | 75 | private Optional getProfile(@Nullable WorldDataHolder holder, UUID uuid, @Nullable String name) { 76 | if (holder == null) return Optional.empty(); 77 | var user = name != null ? holder.getUser(uuid.toString(), name) : holder.getUser(uuid.toString()); 78 | return user != null ? Optional.of(new GroupManagerChatProfile(user, holder)) : Optional.empty(); 79 | } 80 | 81 | @Override 82 | public Plugin getPlugin() { 83 | return groupManager; 84 | } 85 | 86 | @Override 87 | public String getName() { 88 | return "GroupManager Chat"; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/controller/chat/LuckPermsChatController.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.controller.chat; 2 | 3 | import net.luckperms.api.LuckPerms; 4 | import net.luckperms.api.LuckPermsProvider; 5 | import net.luckperms.api.context.ImmutableContextSet; 6 | import net.luckperms.api.query.QueryOptions; 7 | import net.thenextlvl.service.api.chat.ChatController; 8 | import net.thenextlvl.service.api.chat.ChatProfile; 9 | import net.thenextlvl.service.model.chat.LuckPermsChatProfile; 10 | import org.bukkit.World; 11 | import org.bukkit.plugin.Plugin; 12 | import org.jspecify.annotations.NullMarked; 13 | 14 | import java.util.Optional; 15 | import java.util.UUID; 16 | import java.util.concurrent.CompletableFuture; 17 | 18 | @NullMarked 19 | public class LuckPermsChatController implements ChatController { 20 | private final LuckPerms luckPerms = LuckPermsProvider.get(); 21 | private final Plugin plugin; 22 | 23 | public LuckPermsChatController(Plugin plugin) { 24 | this.plugin = plugin; 25 | } 26 | 27 | @Override 28 | public CompletableFuture loadProfile(UUID uuid) { 29 | return luckPerms.getUserManager().loadUser(uuid).thenApply(user -> 30 | new LuckPermsChatProfile(user, QueryOptions.defaultContextualOptions())); 31 | } 32 | 33 | @Override 34 | public CompletableFuture loadProfile(UUID uuid, World world) { 35 | return luckPerms.getUserManager().loadUser(uuid).thenApply(user -> { 36 | var options = QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); 37 | return new LuckPermsChatProfile(user, options); 38 | }); 39 | } 40 | 41 | @Override 42 | public Optional getProfile(UUID uuid) { 43 | return Optional.ofNullable(luckPerms.getUserManager().getUser(uuid)).map(user -> 44 | new LuckPermsChatProfile(user, QueryOptions.defaultContextualOptions())); 45 | } 46 | 47 | @Override 48 | public Optional getProfile(UUID uuid, World world) { 49 | return Optional.ofNullable(luckPerms.getUserManager().getUser(uuid)).map(user -> { 50 | var options = QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); 51 | return new LuckPermsChatProfile(user, options); 52 | }); 53 | } 54 | 55 | @Override 56 | public Plugin getPlugin() { 57 | return plugin; 58 | } 59 | 60 | @Override 61 | public String getName() { 62 | return "LuckPerms Chat"; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/controller/hologram/DecentHologramController.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.controller.hologram; 2 | 3 | import eu.decentsoftware.holograms.api.DHAPI; 4 | import eu.decentsoftware.holograms.api.DecentHologramsAPI; 5 | import eu.decentsoftware.holograms.api.utils.items.HologramItem; 6 | import net.kyori.adventure.text.Component; 7 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; 8 | import net.thenextlvl.service.api.capability.CapabilityException; 9 | import net.thenextlvl.service.api.hologram.Hologram; 10 | import net.thenextlvl.service.api.hologram.HologramCapability; 11 | import net.thenextlvl.service.api.hologram.HologramController; 12 | import net.thenextlvl.service.api.hologram.HologramLine; 13 | import net.thenextlvl.service.model.hologram.decent.DecentBlockHologramLine; 14 | import net.thenextlvl.service.model.hologram.decent.DecentEntityHologramLine; 15 | import net.thenextlvl.service.model.hologram.decent.DecentHologram; 16 | import net.thenextlvl.service.model.hologram.decent.DecentItemHologramLine; 17 | import net.thenextlvl.service.model.hologram.decent.DecentTextHologramLine; 18 | import org.bukkit.Location; 19 | import org.bukkit.World; 20 | import org.bukkit.block.data.BlockData; 21 | import org.bukkit.entity.EntityType; 22 | import org.bukkit.entity.Player; 23 | import org.bukkit.inventory.ItemStack; 24 | import org.bukkit.plugin.Plugin; 25 | import org.jetbrains.annotations.Unmodifiable; 26 | import org.jspecify.annotations.NullMarked; 27 | 28 | import java.util.Collection; 29 | import java.util.EnumSet; 30 | import java.util.List; 31 | import java.util.Optional; 32 | import java.util.stream.Collectors; 33 | 34 | @NullMarked 35 | public class DecentHologramController implements HologramController { 36 | private final EnumSet capabilities = EnumSet.of( 37 | HologramCapability.BLOCK_LINES, 38 | HologramCapability.ENTITY_LINES, 39 | HologramCapability.ITEM_LINES, 40 | HologramCapability.TEXT_LINES, 41 | HologramCapability.MULTILINE 42 | ); 43 | 44 | @Override 45 | public Hologram createHologram(String name, Location location, Collection> lines) throws CapabilityException { 46 | var hologram = new DecentHologram(DHAPI.createHologram(name, location, false)); 47 | hologram.addLines(lines); 48 | return hologram; 49 | } 50 | 51 | @Override 52 | public HologramLine createLine(BlockData block) throws CapabilityException { 53 | var item = ItemStack.of(block.getMaterial()); 54 | var line = new eu.decentsoftware.holograms.api.holograms.HologramLine( 55 | null, new Location(null, 0, 0, 0), 56 | "#HEAD:" + HologramItem.fromItemStack(item).getContent() 57 | ); 58 | return new DecentBlockHologramLine(line, false); 59 | } 60 | 61 | @Override 62 | public HologramLine createLine(Component text) throws CapabilityException { 63 | var line = new eu.decentsoftware.holograms.api.holograms.HologramLine( 64 | null, new Location(null, 0, 0, 0), 65 | LegacyComponentSerializer.legacyAmpersand().serialize(text) 66 | ); 67 | return new DecentTextHologramLine(line); 68 | } 69 | 70 | @Override 71 | public HologramLine createLine(EntityType entity) throws CapabilityException { 72 | var line = new eu.decentsoftware.holograms.api.holograms.HologramLine( 73 | null, new Location(null, 0, 0, 0), 74 | "#ENTITY:" + entity.name() 75 | ); 76 | return new DecentEntityHologramLine(line); 77 | } 78 | 79 | @Override 80 | public HologramLine createLine(ItemStack itemStack) throws CapabilityException { 81 | var line = new eu.decentsoftware.holograms.api.holograms.HologramLine( 82 | null, new Location(null, 0, 0, 0), 83 | "#ICON:" + HologramItem.fromItemStack(itemStack).getContent() 84 | ); 85 | return new DecentItemHologramLine(line); 86 | } 87 | 88 | @Override 89 | public @Unmodifiable List getHolograms() { 90 | return eu.decentsoftware.holograms.api.holograms.Hologram.getCachedHolograms().stream() 91 | .map(DecentHologram::new) 92 | .collect(Collectors.toUnmodifiableList()); 93 | } 94 | 95 | @Override 96 | public @Unmodifiable List getHolograms(Player player) { 97 | return eu.decentsoftware.holograms.api.holograms.Hologram.getCachedHolograms().stream() 98 | .filter(hologram -> hologram.isVisible(player)) 99 | .map(DecentHologram::new) 100 | .collect(Collectors.toUnmodifiableList()); 101 | } 102 | 103 | @Override 104 | public @Unmodifiable List getHolograms(World world) { 105 | return eu.decentsoftware.holograms.api.holograms.Hologram.getCachedHolograms().stream() 106 | .filter(hologram -> world.equals(hologram.getLocation().getWorld())) 107 | .map(DecentHologram::new) 108 | .collect(Collectors.toUnmodifiableList()); 109 | } 110 | 111 | @Override 112 | public Optional getHologram(String name) { 113 | return Optional.ofNullable(DHAPI.getHologram(name)) 114 | .map(DecentHologram::new); 115 | } 116 | 117 | @Override 118 | public Plugin getPlugin() { 119 | return DecentHologramsAPI.get().getPlugin(); 120 | } 121 | 122 | @Override 123 | public String getName() { 124 | return "DecentHolograms"; 125 | } 126 | 127 | @Override 128 | public @Unmodifiable EnumSet getCapabilities() { 129 | return EnumSet.copyOf(this.capabilities); 130 | } 131 | 132 | @Override 133 | public boolean hasCapabilities(Collection capabilities) { 134 | return this.capabilities.containsAll(capabilities); 135 | } 136 | 137 | @Override 138 | public boolean hasCapability(HologramCapability capability) { 139 | return capabilities.contains(capability); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/controller/permission/GroupManagerPermissionController.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.controller.permission; 2 | 3 | import net.thenextlvl.service.api.permission.PermissionController; 4 | import net.thenextlvl.service.api.permission.PermissionHolder; 5 | import net.thenextlvl.service.model.permission.GroupManagerPermissionHolder; 6 | import org.anjocaido.groupmanager.GroupManager; 7 | import org.anjocaido.groupmanager.dataholder.WorldDataHolder; 8 | import org.bukkit.World; 9 | import org.bukkit.plugin.Plugin; 10 | import org.bukkit.plugin.java.JavaPlugin; 11 | import org.jspecify.annotations.NullMarked; 12 | import org.jspecify.annotations.Nullable; 13 | 14 | import java.util.Optional; 15 | import java.util.UUID; 16 | import java.util.concurrent.CompletableFuture; 17 | 18 | @NullMarked 19 | public class GroupManagerPermissionController implements PermissionController { 20 | private final GroupManager groupManager = JavaPlugin.getPlugin(GroupManager.class); 21 | 22 | @Override 23 | public CompletableFuture loadPermissionHolder(UUID uuid) { 24 | var holder = groupManager.getWorldsHolder().getDefaultWorld(); 25 | return CompletableFuture.completedFuture(getHolder(holder, uuid).orElse(null)); 26 | } 27 | 28 | @Override 29 | public CompletableFuture loadPermissionHolder(UUID uuid, World world) { 30 | var holder = groupManager.getWorldsHolder().getWorldData(world.getName()); 31 | return CompletableFuture.completedFuture(getHolder(holder, uuid).orElse(null)); 32 | } 33 | 34 | @Override 35 | public Optional getPermissionHolder(UUID uuid) { 36 | return Optional.empty(); 37 | } 38 | 39 | @Override 40 | public Optional getPermissionHolder(UUID uuid, World world) { 41 | return Optional.empty(); 42 | } 43 | 44 | private Optional getHolder(@Nullable WorldDataHolder holder, UUID uuid) { 45 | return holder != null ? Optional.ofNullable(holder.getUser(uuid.toString())) 46 | .map(user -> new GroupManagerPermissionHolder(user, holder)) : Optional.empty(); 47 | } 48 | 49 | @Override 50 | public Plugin getPlugin() { 51 | return groupManager; 52 | } 53 | 54 | @Override 55 | public String getName() { 56 | return "GroupManager"; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/controller/permission/LuckPermsPermissionController.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.controller.permission; 2 | 3 | import net.luckperms.api.LuckPerms; 4 | import net.luckperms.api.LuckPermsProvider; 5 | import net.luckperms.api.context.ImmutableContextSet; 6 | import net.luckperms.api.query.QueryOptions; 7 | import net.thenextlvl.service.api.permission.PermissionController; 8 | import net.thenextlvl.service.api.permission.PermissionHolder; 9 | import net.thenextlvl.service.model.permission.LuckPermsPermissionHolder; 10 | import org.bukkit.World; 11 | import org.bukkit.plugin.Plugin; 12 | import org.jspecify.annotations.NullMarked; 13 | 14 | import java.util.Optional; 15 | import java.util.UUID; 16 | import java.util.concurrent.CompletableFuture; 17 | 18 | @NullMarked 19 | public class LuckPermsPermissionController implements PermissionController { 20 | private final LuckPerms luckPerms = LuckPermsProvider.get(); 21 | private final Plugin plugin; 22 | 23 | public LuckPermsPermissionController(Plugin plugin) { 24 | this.plugin = plugin; 25 | } 26 | 27 | @Override 28 | public CompletableFuture loadPermissionHolder(UUID uuid) { 29 | return luckPerms.getUserManager().loadUser(uuid).thenApply(user -> 30 | new LuckPermsPermissionHolder(user, QueryOptions.defaultContextualOptions())); 31 | } 32 | 33 | @Override 34 | public CompletableFuture loadPermissionHolder(UUID uuid, World world) { 35 | return luckPerms.getUserManager().loadUser(uuid).thenApply(user -> { 36 | var context = QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); 37 | return new LuckPermsPermissionHolder(user, context); 38 | }); 39 | } 40 | 41 | @Override 42 | public Optional getPermissionHolder(UUID uuid) { 43 | return Optional.ofNullable(luckPerms.getUserManager().getUser(uuid)) 44 | .map(user -> new LuckPermsPermissionHolder(user, QueryOptions.defaultContextualOptions())); 45 | } 46 | 47 | @Override 48 | public Optional getPermissionHolder(UUID uuid, World world) { 49 | return Optional.ofNullable(luckPerms.getUserManager().getUser(uuid)).map(user -> { 50 | var context = QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); 51 | return new LuckPermsPermissionHolder(user, context); 52 | }); 53 | } 54 | 55 | @Override 56 | public Plugin getPlugin() { 57 | return plugin; 58 | } 59 | 60 | @Override 61 | public String getName() { 62 | return "LuckPerms"; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/controller/permission/SuperPermsPermissionController.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.controller.permission; 2 | 3 | import net.thenextlvl.service.ServicePlugin; 4 | import net.thenextlvl.service.api.permission.PermissionController; 5 | import net.thenextlvl.service.api.permission.PermissionHolder; 6 | import net.thenextlvl.service.model.permission.SuperPermsPermissionHolder; 7 | import org.bukkit.OfflinePlayer; 8 | import org.bukkit.World; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.plugin.Plugin; 11 | import org.jspecify.annotations.NullMarked; 12 | import org.jspecify.annotations.Nullable; 13 | 14 | import java.util.Optional; 15 | import java.util.UUID; 16 | import java.util.concurrent.CompletableFuture; 17 | 18 | @NullMarked 19 | public class SuperPermsPermissionController implements PermissionController { 20 | private final ServicePlugin plugin; 21 | 22 | public SuperPermsPermissionController(ServicePlugin plugin) { 23 | this.plugin = plugin; 24 | } 25 | 26 | @Override 27 | public CompletableFuture loadPermissionHolder(OfflinePlayer player) { 28 | return CompletableFuture.completedFuture(getPermissionHolder(player.getPlayer()).orElse(null)); 29 | } 30 | 31 | @Override 32 | public CompletableFuture loadPermissionHolder(OfflinePlayer player, World world) { 33 | return loadPermissionHolder(player); 34 | } 35 | 36 | @Override 37 | public CompletableFuture loadPermissionHolder(UUID uuid) { 38 | return CompletableFuture.completedFuture(getPermissionHolder(uuid).orElse(null)); 39 | } 40 | 41 | @Override 42 | public CompletableFuture loadPermissionHolder(UUID uuid, World world) { 43 | return loadPermissionHolder(uuid); 44 | } 45 | 46 | @Override 47 | public Optional getPermissionHolder(UUID uuid) { 48 | return getPermissionHolder(plugin.getServer().getPlayer(uuid)); 49 | } 50 | 51 | @Override 52 | public Optional getPermissionHolder(UUID uuid, World world) { 53 | return getPermissionHolder(uuid); 54 | } 55 | 56 | private Optional getPermissionHolder(@Nullable Player player) { 57 | return Optional.ofNullable(player).map(SuperPermsPermissionHolder::new); 58 | } 59 | 60 | @Override 61 | public Plugin getPlugin() { 62 | return plugin; 63 | } 64 | 65 | @Override 66 | public String getName() { 67 | return "SuperPerms"; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/listener/CitizensListener.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.listener; 2 | 3 | import net.citizensnpcs.api.event.NPCClickEvent; 4 | import net.citizensnpcs.api.event.NPCDamageByEntityEvent; 5 | import net.citizensnpcs.api.event.NPCDamageEvent; 6 | import net.citizensnpcs.api.event.NPCLeftClickEvent; 7 | import net.citizensnpcs.api.event.NPCRightClickEvent; 8 | import net.thenextlvl.service.api.character.CharacterController; 9 | import net.thenextlvl.service.api.character.event.CharacterDamageEvent; 10 | import net.thenextlvl.service.api.character.event.EntityDamageCharacterEvent; 11 | import net.thenextlvl.service.api.character.event.PlayerInteractCharacterEvent; 12 | import net.thenextlvl.service.api.character.event.PlayerInteractCharacterEvent.InteractionType; 13 | import net.thenextlvl.service.model.character.citizens.CitizensCharacter; 14 | import org.bukkit.entity.Player; 15 | import org.bukkit.event.EventHandler; 16 | import org.bukkit.event.EventPriority; 17 | import org.bukkit.event.Listener; 18 | import org.bukkit.event.entity.EntityDamageByEntityEvent; 19 | import org.jspecify.annotations.NullMarked; 20 | 21 | @NullMarked 22 | public class CitizensListener implements Listener { 23 | private final CharacterController controller; 24 | 25 | public CitizensListener(CharacterController controller) { 26 | this.controller = controller; 27 | } 28 | 29 | @EventHandler(priority = EventPriority.LOWEST) 30 | public void onNPCRightClick(NPCRightClickEvent event) { 31 | onNPCClick(event, event.getClicker().isSneaking() 32 | ? InteractionType.SHIFT_RIGHT_CLICK 33 | : InteractionType.RIGHT_CLICK); 34 | } 35 | 36 | @EventHandler(priority = EventPriority.LOWEST) 37 | public void onNPCDamageByEntity(NPCDamageByEntityEvent event) { 38 | var cause = (EntityDamageByEntityEvent) event.getEvent(); 39 | var character = new CitizensCharacter<>(event.getNPC()); 40 | var damageEvent = new EntityDamageCharacterEvent( 41 | controller, character, event.getDamager(), event.getCause(), 42 | event.getDamage(), cause.isCritical() 43 | ); 44 | damageEvent.setCancelled(event.isCancelled()); 45 | event.setCancelled(!damageEvent.callEvent()); 46 | event.setDamage(damageEvent.getDamage()); 47 | 48 | if (!(event.getDamager() instanceof Player player)) return; 49 | var clickEvent = new NPCLeftClickEvent(event.getNPC(), player); 50 | clickEvent.setCancelled(event.isCancelled()); 51 | onNPCClick(clickEvent, event.getDamager().isSneaking() 52 | ? InteractionType.SHIFT_LEFT_CLICK 53 | : InteractionType.LEFT_CLICK); 54 | if (clickEvent.isCancelled()) event.setCancelled(true); 55 | } 56 | 57 | @EventHandler(priority = EventPriority.LOWEST) 58 | public void onNPCDamage(NPCDamageEvent event) { 59 | var character = new CitizensCharacter<>(event.getNPC()); 60 | var damageEvent = new CharacterDamageEvent( 61 | controller, character, event.getCause(), event.getDamage() 62 | ); 63 | damageEvent.setCancelled(event.isCancelled()); 64 | event.setCancelled(!damageEvent.callEvent()); 65 | } 66 | 67 | private void onNPCClick(NPCClickEvent event, InteractionType type) { 68 | var character = new CitizensCharacter<>(event.getNPC()); 69 | var characterEvent = new PlayerInteractCharacterEvent( 70 | controller, character, event.getClicker(), type 71 | ); 72 | characterEvent.setCancelled(event.isCancelled()); 73 | event.setCancelled(!characterEvent.callEvent()); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/listener/FancyNpcsListener.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.listener; 2 | 3 | import de.oliver.fancynpcs.api.actions.ActionTrigger; 4 | import de.oliver.fancynpcs.api.events.NpcInteractEvent; 5 | import net.thenextlvl.service.api.character.CharacterController; 6 | import net.thenextlvl.service.api.character.event.PlayerInteractCharacterEvent; 7 | import net.thenextlvl.service.api.character.event.PlayerInteractCharacterEvent.InteractionType; 8 | import net.thenextlvl.service.model.character.fancy.FancyCharacter; 9 | import org.bukkit.event.EventHandler; 10 | import org.bukkit.event.EventPriority; 11 | import org.bukkit.event.Listener; 12 | import org.jspecify.annotations.NullMarked; 13 | 14 | @NullMarked 15 | public class FancyNpcsListener implements Listener { 16 | private final CharacterController controller; 17 | 18 | public FancyNpcsListener(CharacterController controller) { 19 | this.controller = controller; 20 | } 21 | 22 | @EventHandler(priority = EventPriority.LOWEST) 23 | public void onNPCInteract(NpcInteractEvent event) { 24 | var interactionType = event.getInteractionType().equals(ActionTrigger.RIGHT_CLICK) 25 | ? event.getPlayer().isSneaking() ? InteractionType.SHIFT_RIGHT_CLICK : InteractionType.RIGHT_CLICK 26 | : event.getPlayer().isSneaking() ? InteractionType.SHIFT_LEFT_CLICK : InteractionType.LEFT_CLICK; 27 | var interactEvent = new PlayerInteractCharacterEvent( 28 | controller, new FancyCharacter<>(event.getNpc()), 29 | event.getPlayer(), interactionType 30 | ); 31 | interactEvent.setCancelled(event.isCancelled()); 32 | event.setCancelled(!interactEvent.callEvent()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/model/chat/GroupManagerChatProfile.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.model.chat; 2 | 3 | import net.thenextlvl.service.api.chat.ChatProfile; 4 | import org.anjocaido.groupmanager.data.Group; 5 | import org.anjocaido.groupmanager.data.User; 6 | import org.anjocaido.groupmanager.dataholder.WorldDataHolder; 7 | import org.jetbrains.annotations.Unmodifiable; 8 | import org.jspecify.annotations.NullMarked; 9 | import org.jspecify.annotations.Nullable; 10 | 11 | import java.util.Map; 12 | import java.util.Objects; 13 | import java.util.Optional; 14 | import java.util.Set; 15 | import java.util.function.Function; 16 | import java.util.stream.Collectors; 17 | 18 | @NullMarked 19 | public record GroupManagerChatProfile(User user, WorldDataHolder holder) implements ChatProfile { 20 | @Override 21 | public Optional getDisplayName() { 22 | return Optional.empty(); 23 | } 24 | 25 | @Override 26 | public Optional getName() { 27 | return Optional.of(user().getLastName()); 28 | } 29 | 30 | @Override 31 | public Optional getPrefix(int priority) { 32 | return Optional.ofNullable(holder().getPermissionsHandler().getUserPrefix(user().getLastName())); 33 | } 34 | 35 | @Override 36 | public @Unmodifiable Map getPrefixes() { 37 | return getPrefix().map(prefix -> Map.of(0, prefix)).orElseGet(Map::of); 38 | } 39 | 40 | @Override 41 | public Optional getPrimaryGroup() { 42 | return Optional.of(user().getGroup().getName()); 43 | } 44 | 45 | @Override 46 | public Optional getSuffix(int priority) { 47 | return Optional.ofNullable(holder().getPermissionsHandler().getUserSuffix(user().getLastName())); 48 | } 49 | 50 | @Override 51 | public @Unmodifiable Map getSuffixes() { 52 | return getSuffix().map(suffix -> Map.of(0, suffix)).orElseGet(Map::of); 53 | } 54 | 55 | @Override 56 | public @Unmodifiable Set getGroups() { 57 | return user().getSaveSubGroupsList().stream() 58 | .map(holder()::getGroup) 59 | .filter(Objects::nonNull) 60 | .map(Group::getName) 61 | .collect(Collectors.toUnmodifiableSet()); 62 | } 63 | 64 | @Override 65 | public boolean setDisplayName(@Nullable String displayName) { 66 | return false; 67 | } 68 | 69 | @Override 70 | public boolean setPrefix(@Nullable String prefix, int priority) { 71 | if (prefix == null) return removeInfoNode("prefix"); 72 | return setInfoNode("prefix", prefix); 73 | } 74 | 75 | @Override 76 | public boolean setSuffix(@Nullable String suffix, int priority) { 77 | if (suffix == null) return removeInfoNode("suffix"); 78 | return setInfoNode("suffix", suffix); 79 | } 80 | 81 | @Override 82 | public Optional getInfoNode(String key, Function<@Nullable String, @Nullable T> mapper) { 83 | return Optional.ofNullable(mapper.apply(user().getVariables().getVarString(key))); 84 | } 85 | 86 | @Override 87 | public boolean removeInfoNode(String key) { 88 | if (!hasInfoNode(key)) return false; 89 | user().getVariables().removeVar(key); 90 | return true; 91 | } 92 | 93 | @Override 94 | public boolean setInfoNode(String key, String value) { 95 | user().getVariables().addVar(key, value); 96 | return true; 97 | } 98 | 99 | @Override 100 | public boolean hasInfoNode(String key) { 101 | return user().getVariables().hasVar(key); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/model/chat/LuckPermsChatProfile.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.model.chat; 2 | 3 | import net.luckperms.api.LuckPermsProvider; 4 | import net.luckperms.api.model.group.Group; 5 | import net.luckperms.api.model.user.User; 6 | import net.luckperms.api.node.types.DisplayNameNode; 7 | import net.luckperms.api.node.types.MetaNode; 8 | import net.luckperms.api.node.types.PrefixNode; 9 | import net.luckperms.api.node.types.SuffixNode; 10 | import net.luckperms.api.query.QueryOptions; 11 | import net.thenextlvl.service.api.chat.ChatProfile; 12 | import org.jetbrains.annotations.Unmodifiable; 13 | import org.jspecify.annotations.NullMarked; 14 | import org.jspecify.annotations.Nullable; 15 | 16 | import java.util.Map; 17 | import java.util.Optional; 18 | import java.util.Set; 19 | import java.util.function.Function; 20 | import java.util.stream.Collectors; 21 | 22 | @NullMarked 23 | public record LuckPermsChatProfile(User user, QueryOptions options) implements ChatProfile { 24 | @Override 25 | public Optional getDisplayName() { 26 | return getInfoNode("DISPLAY_NAME"); 27 | } 28 | 29 | @Override 30 | public Optional getName() { 31 | return Optional.ofNullable(user().getUsername()); 32 | } 33 | 34 | @Override 35 | public Optional getPrefix() { 36 | return Optional.ofNullable(user().getCachedData().getMetaData(options()).getPrefix()); 37 | } 38 | 39 | @Override 40 | public Optional getPrefix(int priority) { 41 | return Optional.ofNullable(getPrefixes().get(priority)); 42 | } 43 | 44 | @Override 45 | public @Unmodifiable Map getPrefixes() { 46 | return user().getCachedData().getMetaData(options()).getPrefixes(); 47 | } 48 | 49 | @Override 50 | public Optional getPrimaryGroup() { 51 | return Optional.of(user().getPrimaryGroup()); 52 | } 53 | 54 | @Override 55 | public Optional getSuffix() { 56 | return Optional.ofNullable(user().getCachedData().getMetaData(options()).getSuffix()); 57 | } 58 | 59 | @Override 60 | public Optional getSuffix(int priority) { 61 | return Optional.ofNullable(getSuffixes().get(priority)); 62 | } 63 | 64 | @Override 65 | public @Unmodifiable Map getSuffixes() { 66 | return user().getCachedData().getMetaData(options()).getSuffixes(); 67 | } 68 | 69 | @Override 70 | public Set getGroups() { 71 | return user().getInheritedGroups(options()).stream() 72 | .map(Group::getName) 73 | .collect(Collectors.toUnmodifiableSet()); 74 | } 75 | 76 | @Override 77 | public boolean setDisplayName(@Nullable String displayName) { 78 | if (displayName == null) return unsetDisplayName(); 79 | var result = user().data().add(DisplayNameNode.builder(displayName).build()); 80 | LuckPermsProvider.get().getUserManager().saveUser(user()); 81 | return result.wasSuccessful(); 82 | } 83 | 84 | private boolean unsetDisplayName() { 85 | user().data().clear(options().context(), node -> node instanceof DisplayNameNode); 86 | LuckPermsProvider.get().getUserManager().saveUser(user()); 87 | return true; 88 | } 89 | 90 | @Override 91 | public boolean setPrefix(@Nullable String prefix, int priority) { 92 | if (prefix == null) return unsetPrefix(priority); 93 | var result = user().data().add(PrefixNode.builder(prefix, priority).context(options().context()).build()); 94 | LuckPermsProvider.get().getUserManager().saveUser(user()); 95 | return result.wasSuccessful(); 96 | } 97 | 98 | private boolean unsetPrefix(int priority) { 99 | user().data().clear(options().context(), node -> node instanceof PrefixNode prefix && prefix.getPriority() == priority); 100 | LuckPermsProvider.get().getUserManager().saveUser(user()); 101 | return true; 102 | } 103 | 104 | @Override 105 | public boolean setSuffix(@Nullable String suffix, int priority) { 106 | if (suffix == null) return unsetSuffix(priority); 107 | var result = user().data().add(SuffixNode.builder(suffix, priority).context(options().context()).build()); 108 | LuckPermsProvider.get().getUserManager().saveUser(user()); 109 | return result.wasSuccessful(); 110 | } 111 | 112 | private boolean unsetSuffix(int priority) { 113 | user().data().clear(options().context(), node -> node instanceof SuffixNode suffix && suffix.getPriority() == priority); 114 | LuckPermsProvider.get().getUserManager().saveUser(user()); 115 | return true; 116 | } 117 | 118 | @Override 119 | public Optional getInfoNode(String key, Function mapper) { 120 | return user().getCachedData().getMetaData(options()).getMetaValue(key, mapper); 121 | } 122 | 123 | @Override 124 | public boolean setInfoNode(String key, String value) { 125 | var result = user().data().add(MetaNode.builder(key, value).context(options().context()).build()); 126 | LuckPermsProvider.get().getUserManager().saveUser(user()); 127 | return result.wasSuccessful(); 128 | } 129 | 130 | @Override 131 | public boolean removeInfoNode(String key) { 132 | user().data().clear(options().context(), node -> node.getKey().equals(key)); 133 | LuckPermsProvider.get().getUserManager().saveUser(user()); 134 | return true; 135 | } 136 | 137 | @Override 138 | public boolean removeInfoNode(String key, String value) { 139 | var result = user().data().remove(MetaNode.builder(key, value).context(options().context()).build()); 140 | LuckPermsProvider.get().getUserManager().saveUser(user()); 141 | return result.wasSuccessful(); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/model/group/GroupManagerGroup.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.model.group; 2 | 3 | import net.kyori.adventure.util.TriState; 4 | import net.thenextlvl.service.api.group.Group; 5 | import org.anjocaido.groupmanager.GroupManager; 6 | import org.bukkit.World; 7 | import org.bukkit.plugin.java.JavaPlugin; 8 | import org.jetbrains.annotations.Unmodifiable; 9 | import org.jspecify.annotations.NullMarked; 10 | import org.jspecify.annotations.Nullable; 11 | 12 | import java.util.Map; 13 | import java.util.Optional; 14 | import java.util.OptionalInt; 15 | import java.util.function.Function; 16 | import java.util.stream.Collectors; 17 | 18 | @NullMarked 19 | public record GroupManagerGroup(org.anjocaido.groupmanager.data.Group group) implements Group { 20 | @Override 21 | public Optional getDisplayName() { 22 | return Optional.empty(); 23 | } 24 | 25 | @Override 26 | public Optional getPrefix(int priority) { 27 | return getInfoNode("prefix"); 28 | } 29 | 30 | @Override 31 | public @Unmodifiable Map getPrefixes() { 32 | return getPrefix().map(prefix -> Map.of(0, prefix)).orElseGet(Map::of); 33 | } 34 | 35 | @Override 36 | public Optional getSuffix(int priority) { 37 | return getInfoNode("suffix"); 38 | } 39 | 40 | @Override 41 | public @Unmodifiable Map getSuffixes() { 42 | return getSuffix().map(suffix -> Map.of(0, suffix)).orElseGet(Map::of); 43 | } 44 | 45 | @Override 46 | public OptionalInt getWeight() { 47 | return OptionalInt.empty(); 48 | } 49 | 50 | @Override 51 | public String getName() { 52 | return group().getName(); 53 | } 54 | 55 | @Override 56 | public Optional getWorld() { 57 | var plugin = JavaPlugin.getPlugin(GroupManager.class); 58 | return Optional.ofNullable(group().getDataSource().getName()) 59 | .map(plugin.getServer()::getWorld); 60 | } 61 | 62 | @Override 63 | public boolean setDisplayName(@Nullable String displayName) { 64 | return false; 65 | } 66 | 67 | @Override 68 | public boolean setWeight(int weight) { 69 | return false; 70 | } 71 | 72 | @Override 73 | public boolean setPrefix(@Nullable String prefix, int priority) { 74 | return setInfoNode("prefix", prefix); 75 | } 76 | 77 | @Override 78 | public boolean setSuffix(@Nullable String suffix, int priority) { 79 | return setInfoNode("suffix", suffix); 80 | } 81 | 82 | @Override 83 | public @Unmodifiable Map getPermissions() { 84 | return group.getPermissionList().stream().collect(Collectors.toUnmodifiableMap( 85 | permission -> permission, permission -> checkPermission(permission).toBooleanOrElse(false)) 86 | ); 87 | } 88 | 89 | @Override 90 | public TriState checkPermission(String permission) { 91 | var handler = group().getDataSource().getPermissionsHandler(); 92 | return switch (handler.checkGroupOnlyPermission(group(), permission).resultType) { 93 | case FOUND -> TriState.TRUE; 94 | case NEGATION, EXCEPTION -> TriState.FALSE; 95 | default -> TriState.NOT_SET; 96 | }; 97 | } 98 | 99 | @Override 100 | public boolean addPermission(String permission) { 101 | return setPermission(permission, true); 102 | } 103 | 104 | @Override 105 | public boolean removePermission(String permission) { 106 | return group().removePermission(permission); 107 | } 108 | 109 | @Override 110 | public boolean setPermission(String permission, boolean value) { 111 | var state = checkPermission(permission).toBoolean(); 112 | if (state != null && state.equals(value)) return false; 113 | removePermission(value ? "-" + permission : permission); 114 | group().addPermission(!value ? "-" + permission : permission); 115 | return true; 116 | } 117 | 118 | @Override 119 | public Optional getInfoNode(String key, Function<@Nullable String, @Nullable T> mapper) { 120 | return Optional.ofNullable(mapper.apply(group().getVariables().getVarString(key))); 121 | } 122 | 123 | @Override 124 | public boolean removeInfoNode(String key) { 125 | if (!hasInfoNode(key)) return false; 126 | group().getVariables().removeVar(key); 127 | return true; 128 | } 129 | 130 | @Override 131 | public boolean setInfoNode(String key, @Nullable String value) { 132 | group().getVariables().addVar(key, value); 133 | return true; 134 | } 135 | 136 | @Override 137 | public boolean hasInfoNode(String key) { 138 | return group().getVariables().hasVar(key); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/model/hologram/decent/DecentBlockHologramLine.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.model.hologram.decent; 2 | 3 | import eu.decentsoftware.holograms.api.holograms.HologramLine; 4 | import eu.decentsoftware.holograms.api.utils.items.HologramItem; 5 | import io.papermc.paper.datacomponent.DataComponentTypes; 6 | import net.thenextlvl.service.api.hologram.LineType; 7 | import org.bukkit.block.Skull; 8 | import org.bukkit.block.data.BlockData; 9 | import org.bukkit.inventory.ItemStack; 10 | import org.jspecify.annotations.NullMarked; 11 | import org.jspecify.annotations.Nullable; 12 | 13 | import java.util.Objects; 14 | 15 | @NullMarked 16 | public class DecentBlockHologramLine extends DecentHologramLine { 17 | private final boolean small; 18 | 19 | public DecentBlockHologramLine(HologramLine line, boolean small) { 20 | super(line); 21 | this.small = small; 22 | } 23 | 24 | @Override 25 | public LineType getType() { 26 | return LineType.BLOCK; 27 | } 28 | 29 | @Override 30 | public BlockData getContent() { 31 | var item = line.getItem().parse(null); 32 | return item.getType().createBlockData(blockData -> { 33 | if (!(blockData instanceof Skull skull)) return; 34 | var data = item.getData(DataComponentTypes.PROFILE); 35 | if (data == null) return; 36 | var profile = getServer().createProfile(data.uuid(), data.name()); 37 | skull.setPlayerProfile(profile); 38 | }); 39 | } 40 | 41 | @Override 42 | public void setContent(BlockData content) { 43 | var type = small ? "#SMALLHEAD:" : "#HEAD:"; 44 | var item = ItemStack.of(content.getMaterial()); 45 | line.setContent(type + HologramItem.fromItemStack(item)); 46 | } 47 | 48 | @Override 49 | public boolean equals(@Nullable Object o) { 50 | if (o == null || getClass() != o.getClass()) return false; 51 | if (!super.equals(o)) return false; 52 | DecentBlockHologramLine that = (DecentBlockHologramLine) o; 53 | return small == that.small; 54 | } 55 | 56 | @Override 57 | public int hashCode() { 58 | return Objects.hash(super.hashCode(), small); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/model/hologram/decent/DecentEntityHologramLine.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.model.hologram.decent; 2 | 3 | import eu.decentsoftware.holograms.api.holograms.HologramLine; 4 | import net.thenextlvl.service.api.hologram.LineType; 5 | import org.bukkit.entity.EntityType; 6 | import org.jspecify.annotations.NullMarked; 7 | 8 | @NullMarked 9 | public class DecentEntityHologramLine extends DecentHologramLine { 10 | public DecentEntityHologramLine(HologramLine line) { 11 | super(line); 12 | } 13 | 14 | @Override 15 | public LineType getType() { 16 | return LineType.ENTITY; 17 | } 18 | 19 | @Override 20 | public EntityType getContent() { 21 | return line.getEntity().getType(); 22 | } 23 | 24 | @Override 25 | public void setContent(EntityType content) { 26 | line.setContent("#ENTITY:" + content.name()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/model/hologram/decent/DecentHologramLine.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.model.hologram.decent; 2 | 3 | import net.thenextlvl.service.api.hologram.HologramDisplay; 4 | import net.thenextlvl.service.api.hologram.HologramLine; 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.Location; 7 | import org.bukkit.Server; 8 | import org.bukkit.World; 9 | import org.jspecify.annotations.NullMarked; 10 | import org.jspecify.annotations.Nullable; 11 | 12 | import java.util.Objects; 13 | import java.util.Optional; 14 | 15 | @NullMarked 16 | abstract class DecentHologramLine implements HologramLine { 17 | protected final eu.decentsoftware.holograms.api.holograms.HologramLine line; 18 | 19 | protected DecentHologramLine(eu.decentsoftware.holograms.api.holograms.HologramLine line) { 20 | this.line = line; 21 | } 22 | 23 | @Override 24 | public Optional getDisplay() { 25 | return Optional.empty(); 26 | } 27 | 28 | @Override 29 | public double getHeight() { 30 | return line.getHeight(); 31 | } 32 | 33 | @Override 34 | public double getOffsetX() { 35 | return line.getOffsetX(); 36 | } 37 | 38 | @Override 39 | public double getOffsetY() { 40 | return line.getOffsetY(); 41 | } 42 | 43 | @Override 44 | public double getOffsetZ() { 45 | return line.getOffsetZ(); 46 | } 47 | 48 | @Override 49 | public void setHeight(double height) { 50 | line.setHeight(height); 51 | } 52 | 53 | @Override 54 | public void setOffsetX(double offsetX) { 55 | line.setOffsetX(offsetX); 56 | } 57 | 58 | @Override 59 | public void setOffsetY(double offsetY) { 60 | line.setOffsetY(offsetY); 61 | } 62 | 63 | @Override 64 | public void setOffsetZ(double offsetZ) { 65 | line.setOffsetZ(offsetZ); 66 | } 67 | 68 | @Override 69 | public Location getLocation() { 70 | return line.getLocation(); 71 | } 72 | 73 | @Override 74 | public Server getServer() { 75 | return Bukkit.getServer(); 76 | } 77 | 78 | @Override 79 | public World getWorld() { 80 | return getLocation().getWorld(); 81 | } 82 | 83 | @Override 84 | public double getX() { 85 | return getLocation().getX(); 86 | } 87 | 88 | @Override 89 | public double getY() { 90 | return getLocation().getY(); 91 | } 92 | 93 | @Override 94 | public double getZ() { 95 | return getLocation().getZ(); 96 | } 97 | 98 | @Override 99 | public float getPitch() { 100 | return getLocation().getPitch(); 101 | } 102 | 103 | @Override 104 | public float getYaw() { 105 | return getLocation().getYaw(); 106 | } 107 | 108 | @Override 109 | public boolean equals(@Nullable Object o) { 110 | if (o == null || getClass() != o.getClass()) return false; 111 | DecentHologramLine that = (DecentHologramLine) o; 112 | return Objects.equals(line, that.line); 113 | } 114 | 115 | @Override 116 | public int hashCode() { 117 | return Objects.hashCode(line); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/model/hologram/decent/DecentItemHologramLine.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.model.hologram.decent; 2 | 3 | import eu.decentsoftware.holograms.api.holograms.HologramLine; 4 | import eu.decentsoftware.holograms.api.utils.items.HologramItem; 5 | import net.thenextlvl.service.api.hologram.LineType; 6 | import org.bukkit.inventory.ItemStack; 7 | import org.jspecify.annotations.NullMarked; 8 | 9 | @NullMarked 10 | public class DecentItemHologramLine extends DecentHologramLine { 11 | public DecentItemHologramLine(HologramLine line) { 12 | super(line); 13 | } 14 | 15 | @Override 16 | public LineType getType() { 17 | return LineType.ITEM; 18 | } 19 | 20 | @Override 21 | public ItemStack getContent() { 22 | return line.getItem().parse(null); 23 | } 24 | 25 | @Override 26 | public void setContent(ItemStack itemStack) { 27 | line.setContent("#ICON:" + HologramItem.fromItemStack(itemStack).getContent()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/model/hologram/decent/DecentTextHologramLine.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.model.hologram.decent; 2 | 3 | import eu.decentsoftware.holograms.api.holograms.HologramLine; 4 | import net.kyori.adventure.text.Component; 5 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; 6 | import net.thenextlvl.service.api.hologram.LineType; 7 | import org.jspecify.annotations.NullMarked; 8 | 9 | @NullMarked 10 | public class DecentTextHologramLine extends DecentHologramLine { 11 | public DecentTextHologramLine(HologramLine line) { 12 | super(line); 13 | } 14 | 15 | @Override 16 | public LineType getType() { 17 | return LineType.TEXT; 18 | } 19 | 20 | @Override 21 | public Component getContent() { 22 | return LegacyComponentSerializer.legacyAmpersand().deserialize(line.getText()); 23 | } 24 | 25 | @Override 26 | public void setContent(Component component) { 27 | line.setContent(LegacyComponentSerializer.legacyAmpersand().serialize(component)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/model/hologram/fancy/FancyBlockHologramLine.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.model.hologram.fancy; 2 | 3 | import de.oliver.fancyholograms.api.data.BlockHologramData; 4 | import org.bukkit.block.data.BlockData; 5 | import org.jspecify.annotations.NullMarked; 6 | 7 | @NullMarked 8 | public class FancyBlockHologramLine extends FancyHologramLine { 9 | public FancyBlockHologramLine(BlockHologramData data) { 10 | super(data); 11 | } 12 | 13 | @Override 14 | public BlockData getContent() { 15 | return data.getBlock().createBlockData(); 16 | } 17 | 18 | @Override 19 | public void setContent(BlockData content) { 20 | data.setBlock(content.getMaterial()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/model/hologram/fancy/FancyHologramDisplay.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.model.hologram.fancy; 2 | 3 | import de.oliver.fancyholograms.api.data.DisplayHologramData; 4 | import de.oliver.fancyholograms.api.data.TextHologramData; 5 | import net.thenextlvl.service.api.hologram.HologramDisplay; 6 | import org.bukkit.Color; 7 | import org.bukkit.entity.Display; 8 | import org.bukkit.entity.TextDisplay; 9 | import org.bukkit.util.Transformation; 10 | import org.joml.AxisAngle4f; 11 | import org.joml.Matrix4f; 12 | import org.joml.Vector3f; 13 | import org.jspecify.annotations.NullMarked; 14 | import org.jspecify.annotations.Nullable; 15 | 16 | @NullMarked 17 | public record FancyHologramDisplay(DisplayHologramData data) implements HologramDisplay { 18 | @Override 19 | public Transformation getTransformation() { 20 | return new Transformation( 21 | new Vector3f(0), new AxisAngle4f(0, 0, 0, 0), 22 | data().getScale(), new AxisAngle4f(0, 0, 0, 0) 23 | ); 24 | } 25 | 26 | @Override 27 | public void setTransformation(Transformation transformation) { 28 | data().setScale(transformation.getScale()); 29 | } 30 | 31 | @Override 32 | public void setTransformationMatrix(Matrix4f transformationMatrix) { 33 | } 34 | 35 | @Override 36 | public int getInterpolationDuration() { 37 | return data().getInterpolationDuration(); 38 | } 39 | 40 | @Override 41 | public void setInterpolationDuration(int duration) { 42 | data().setInterpolationDuration(duration); 43 | } 44 | 45 | @Override 46 | public int getTeleportDuration() { 47 | return 0; 48 | } 49 | 50 | @Override 51 | public void setTeleportDuration(int duration) { 52 | } 53 | 54 | @Override 55 | public float getViewRange() { 56 | return 0; 57 | } 58 | 59 | @Override 60 | public void setViewRange(float range) { 61 | } 62 | 63 | @Override 64 | public float getShadowRadius() { 65 | return data().getShadowRadius(); 66 | } 67 | 68 | @Override 69 | public void setShadowRadius(float radius) { 70 | data().setShadowRadius(radius); 71 | } 72 | 73 | @Override 74 | public float getShadowStrength() { 75 | return data().getShadowStrength(); 76 | } 77 | 78 | @Override 79 | public void setShadowStrength(float strength) { 80 | data().setShadowStrength(strength); 81 | } 82 | 83 | @Override 84 | public float getDisplayWidth() { 85 | return 0; 86 | } 87 | 88 | @Override 89 | public void setDisplayWidth(float width) { 90 | } 91 | 92 | @Override 93 | public float getDisplayHeight() { 94 | return 0; 95 | } 96 | 97 | @Override 98 | public void setDisplayHeight(float height) { 99 | } 100 | 101 | @Override 102 | public int getInterpolationDelay() { 103 | return 0; 104 | } 105 | 106 | @Override 107 | public void setInterpolationDelay(int ticks) { 108 | } 109 | 110 | @Override 111 | public Display.Billboard getBillboard() { 112 | return data().getBillboard(); 113 | } 114 | 115 | @Override 116 | public void setBillboard(Display.Billboard billboard) { 117 | data().setBillboard(billboard); 118 | } 119 | 120 | @Override 121 | public @Nullable Color getGlowColorOverride() { 122 | return null; 123 | } 124 | 125 | @Override 126 | public void setGlowColorOverride(@Nullable Color color) { 127 | } 128 | 129 | @Override 130 | public Display.@Nullable Brightness getBrightness() { 131 | return data().getBrightness(); 132 | } 133 | 134 | @Override 135 | public void setBrightness(Display.@Nullable Brightness brightness) { 136 | data().setBrightness(brightness); 137 | } 138 | 139 | @Override 140 | public int getLineWidth() { 141 | return 0; 142 | } 143 | 144 | @Override 145 | public void setLineWidth(int width) { 146 | } 147 | 148 | @Override 149 | public @Nullable Color getBackgroundColor() { 150 | return data() instanceof TextHologramData text ? text.getBackground() : null; 151 | } 152 | 153 | @Override 154 | public void setBackgroundColor(@Nullable Color color) { 155 | if (data() instanceof TextHologramData text) text.setBackground(color); 156 | } 157 | 158 | @Override 159 | public byte getTextOpacity() { 160 | return 0; 161 | } 162 | 163 | @Override 164 | public void setTextOpacity(byte opacity) { 165 | } 166 | 167 | @Override 168 | public boolean isShadowed() { 169 | return data() instanceof TextHologramData text && text.hasTextShadow(); 170 | } 171 | 172 | @Override 173 | public void setShadowed(boolean shadow) { 174 | if (data() instanceof TextHologramData text) text.setTextShadow(shadow); 175 | } 176 | 177 | @Override 178 | public boolean isSeeThrough() { 179 | return data() instanceof TextHologramData text && text.isSeeThrough(); 180 | } 181 | 182 | @Override 183 | public void setSeeThrough(boolean seeThrough) { 184 | if (data() instanceof TextHologramData text) text.setSeeThrough(seeThrough); 185 | } 186 | 187 | @Override 188 | public boolean isDefaultBackground() { 189 | return false; 190 | } 191 | 192 | @Override 193 | public void setDefaultBackground(boolean defaultBackground) { 194 | } 195 | 196 | @Override 197 | public TextDisplay.TextAlignment getAlignment() { 198 | return data() instanceof TextHologramData text ? text.getTextAlignment() : TextDisplay.TextAlignment.CENTER; 199 | } 200 | 201 | @Override 202 | public void setAlignment(TextDisplay.TextAlignment alignment) { 203 | if (data() instanceof TextHologramData text) text.setTextAlignment(alignment); 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/model/hologram/fancy/FancyHologramLine.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.model.hologram.fancy; 2 | 3 | import de.oliver.fancyholograms.api.data.DisplayHologramData; 4 | import net.thenextlvl.service.api.hologram.HologramDisplay; 5 | import net.thenextlvl.service.api.hologram.HologramLine; 6 | import net.thenextlvl.service.api.hologram.LineType; 7 | import org.bukkit.Bukkit; 8 | import org.bukkit.Location; 9 | import org.bukkit.Server; 10 | import org.bukkit.World; 11 | import org.joml.Vector3f; 12 | import org.jspecify.annotations.NullMarked; 13 | 14 | import java.util.Objects; 15 | import java.util.Optional; 16 | 17 | @NullMarked 18 | abstract class FancyHologramLine implements HologramLine { 19 | public final D data; 20 | 21 | protected FancyHologramLine(D data) { 22 | this.data = data; 23 | } 24 | 25 | @Override 26 | public LineType getType() { 27 | return switch (data.getType()) { 28 | case TEXT -> LineType.TEXT; 29 | case ITEM -> LineType.ITEM; 30 | case BLOCK -> LineType.BLOCK; 31 | }; 32 | } 33 | 34 | @Override 35 | public Optional getDisplay() { 36 | return Optional.of(new FancyHologramDisplay(data)); 37 | } 38 | 39 | @Override 40 | public double getHeight() { 41 | return 0; 42 | } 43 | 44 | @Override 45 | public double getOffsetX() { 46 | return data.getTranslation().x(); 47 | } 48 | 49 | @Override 50 | public double getOffsetY() { 51 | return data.getTranslation().y(); 52 | } 53 | 54 | @Override 55 | public double getOffsetZ() { 56 | return data.getTranslation().z(); 57 | } 58 | 59 | @Override 60 | public void setHeight(double height) { 61 | } 62 | 63 | @Override 64 | public void setOffsetX(double offsetX) { 65 | data.setTranslation(new Vector3f( 66 | (float) offsetX, 67 | (float) getOffsetY(), 68 | (float) getOffsetZ()) 69 | ); 70 | } 71 | 72 | @Override 73 | public void setOffsetY(double offsetY) { 74 | data.setTranslation(new Vector3f( 75 | (float) getOffsetX(), 76 | (float) offsetY, 77 | (float) getOffsetZ()) 78 | ); 79 | } 80 | 81 | @Override 82 | public void setOffsetZ(double offsetZ) { 83 | data.setTranslation(new Vector3f( 84 | (float) getOffsetX(), 85 | (float) getOffsetY(), 86 | (float) offsetZ) 87 | ); 88 | } 89 | 90 | @Override 91 | public Location getLocation() { 92 | return data.getLocation(); 93 | } 94 | 95 | @Override 96 | public Server getServer() { 97 | return Bukkit.getServer(); 98 | } 99 | 100 | @Override 101 | public World getWorld() { 102 | return data.getLocation().getWorld(); 103 | } 104 | 105 | @Override 106 | public double getX() { 107 | return getLocation().getX(); 108 | } 109 | 110 | @Override 111 | public double getY() { 112 | return getLocation().getY(); 113 | } 114 | 115 | @Override 116 | public double getZ() { 117 | return getLocation().getZ(); 118 | } 119 | 120 | @Override 121 | public float getPitch() { 122 | return getLocation().getPitch(); 123 | } 124 | 125 | @Override 126 | public float getYaw() { 127 | return getLocation().getYaw(); 128 | } 129 | 130 | @Override 131 | public boolean equals(Object o) { 132 | if (o == null || getClass() != o.getClass()) return false; 133 | FancyHologramLine that = (FancyHologramLine) o; 134 | return Objects.equals(data, that.data); 135 | } 136 | 137 | @Override 138 | public int hashCode() { 139 | return Objects.hashCode(data); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/model/hologram/fancy/FancyItemHologramLine.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.model.hologram.fancy; 2 | 3 | import de.oliver.fancyholograms.api.data.ItemHologramData; 4 | import org.bukkit.inventory.ItemStack; 5 | import org.jspecify.annotations.NullMarked; 6 | 7 | @NullMarked 8 | public class FancyItemHologramLine extends FancyHologramLine { 9 | public FancyItemHologramLine(ItemHologramData data) { 10 | super(data); 11 | } 12 | 13 | @Override 14 | public ItemStack getContent() { 15 | return data.getItemStack(); 16 | } 17 | 18 | @Override 19 | public void setContent(ItemStack content) { 20 | data.setItemStack(content); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/model/hologram/fancy/FancyTextHologramLine.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.model.hologram.fancy; 2 | 3 | import de.oliver.fancyholograms.api.data.TextHologramData; 4 | import net.kyori.adventure.text.Component; 5 | import net.kyori.adventure.text.JoinConfiguration; 6 | import net.kyori.adventure.text.minimessage.MiniMessage; 7 | import org.jspecify.annotations.NullMarked; 8 | 9 | import java.util.Arrays; 10 | 11 | @NullMarked 12 | public class FancyTextHologramLine extends FancyHologramLine { 13 | public FancyTextHologramLine(TextHologramData data) { 14 | super(data); 15 | } 16 | 17 | @Override 18 | public Component getContent() { 19 | return Component.join(JoinConfiguration.newlines(), data.getText().stream() 20 | .map(MiniMessage.miniMessage()::deserialize) 21 | .toList()); 22 | } 23 | 24 | @Override 25 | public void setContent(Component content) { 26 | var lines = MiniMessage.miniMessage().serialize(content).split("\\\\n||
"); 27 | data.setText(Arrays.asList(lines)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/model/permission/GroupManagerPermissionHolder.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.model.permission; 2 | 3 | import net.kyori.adventure.util.TriState; 4 | import net.thenextlvl.service.api.group.Group; 5 | import net.thenextlvl.service.api.group.GroupHolder; 6 | import net.thenextlvl.service.model.group.GroupManagerGroup; 7 | import org.anjocaido.groupmanager.data.User; 8 | import org.anjocaido.groupmanager.dataholder.WorldDataHolder; 9 | import org.jetbrains.annotations.Unmodifiable; 10 | import org.jspecify.annotations.NullMarked; 11 | import org.jspecify.annotations.Nullable; 12 | 13 | import java.util.Map; 14 | import java.util.Optional; 15 | import java.util.Set; 16 | import java.util.function.Function; 17 | import java.util.stream.Collectors; 18 | 19 | @NullMarked 20 | public record GroupManagerPermissionHolder(User user, WorldDataHolder holder) implements GroupHolder { 21 | @Override 22 | public @Unmodifiable Map getPermissions() { 23 | return user().getPermissionList().stream().collect(Collectors.toUnmodifiableMap( 24 | permission -> permission, permission -> checkPermission(permission).toBooleanOrElse(false)) 25 | ); 26 | } 27 | 28 | @Override 29 | public TriState checkPermission(String permission) { 30 | return switch (holder().getPermissionsHandler().checkFullUserPermission(user(), permission).resultType) { 31 | case FOUND -> TriState.TRUE; 32 | case NEGATION, EXCEPTION -> TriState.FALSE; 33 | default -> TriState.NOT_SET; 34 | }; 35 | } 36 | 37 | @Override 38 | public boolean addPermission(String permission) { 39 | return setPermission(permission, true); 40 | } 41 | 42 | @Override 43 | public boolean removePermission(String permission) { 44 | return user().removePermission(permission); 45 | } 46 | 47 | @Override 48 | public boolean setPermission(String permission, boolean value) { 49 | var state = checkPermission(permission).toBoolean(); 50 | if (state != null && state.equals(value)) return false; 51 | removePermission(value ? "-" + permission : permission); 52 | user().addPermission(!value ? "-" + permission : permission); 53 | return true; 54 | } 55 | 56 | @Override 57 | public Optional getInfoNode(String key, Function<@Nullable String, @Nullable T> mapper) { 58 | return Optional.ofNullable(mapper.apply(user().getVariables().getVarString(key))); 59 | } 60 | 61 | @Override 62 | public boolean removeInfoNode(String key) { 63 | if (!hasInfoNode(key)) return false; 64 | user().getVariables().removeVar(key); 65 | return true; 66 | } 67 | 68 | @Override 69 | public boolean setInfoNode(String key, String value) { 70 | user().getVariables().addVar(key, value); 71 | return true; 72 | } 73 | 74 | @Override 75 | public boolean hasInfoNode(String key) { 76 | return user().getVariables().hasVar(key); 77 | } 78 | 79 | @Override 80 | public @Unmodifiable Set getGroups() { 81 | return holder.getGroups().values().stream() 82 | .filter(group -> inGroup(group.getName())) 83 | .map(GroupManagerGroup::new) 84 | .collect(Collectors.toUnmodifiableSet()); 85 | } 86 | 87 | @Override 88 | public String getPrimaryGroup() { 89 | return user().getGroupName(); 90 | } 91 | 92 | @Override 93 | public boolean addGroup(Group group) { 94 | if (!(group instanceof GroupManagerGroup(var managerGroup))) 95 | return addGroup(group.getName()); 96 | return user().addSubGroup(managerGroup); 97 | } 98 | 99 | @Override 100 | public boolean addGroup(String name) { 101 | var group = holder().getGroup(name); 102 | return group != null && user().addSubGroup(group); 103 | } 104 | 105 | @Override 106 | public boolean inGroup(Group group) { 107 | return inGroup(group.getName()); 108 | } 109 | 110 | @Override 111 | public boolean inGroup(String name) { 112 | var handler = holder().getPermissionsHandler(); 113 | return handler.hasGroupInInheritance(user().getGroup(), name); 114 | } 115 | 116 | @Override 117 | public boolean removeGroup(Group group) { 118 | if (!(group instanceof GroupManagerGroup(var managerGroup))) 119 | return removeGroup(group.getName()); 120 | return user().removeSubGroup(managerGroup); 121 | } 122 | 123 | @Override 124 | public boolean removeGroup(String name) { 125 | var group = holder().getGroup(name); 126 | return group != null && user().removeSubGroup(group); 127 | } 128 | 129 | @Override 130 | public boolean setPrimaryGroup(Group group) { 131 | if (!(group instanceof GroupManagerGroup(var managerGroup))) 132 | return setPrimaryGroup(group.getName()); 133 | user().setGroup(managerGroup, true); 134 | return true; 135 | } 136 | 137 | @Override 138 | public boolean setPrimaryGroup(String name) { 139 | var group = holder().getGroup(name); 140 | if (group != null) user().setGroup(group, true); 141 | return group != null; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/model/permission/LuckPermsPermissionHolder.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.model.permission; 2 | 3 | import net.kyori.adventure.util.TriState; 4 | import net.luckperms.api.LuckPermsProvider; 5 | import net.luckperms.api.model.user.User; 6 | import net.luckperms.api.node.Node; 7 | import net.luckperms.api.node.types.MetaNode; 8 | import net.luckperms.api.query.QueryOptions; 9 | import net.thenextlvl.service.api.group.Group; 10 | import net.thenextlvl.service.api.group.GroupHolder; 11 | import net.thenextlvl.service.model.group.LuckPermsGroup; 12 | import org.jetbrains.annotations.Unmodifiable; 13 | import org.jspecify.annotations.NullMarked; 14 | 15 | import java.util.Map; 16 | import java.util.Optional; 17 | import java.util.Set; 18 | import java.util.function.Function; 19 | import java.util.stream.Collectors; 20 | 21 | @NullMarked 22 | public record LuckPermsPermissionHolder(User user, QueryOptions options) implements GroupHolder { 23 | @Override 24 | public @Unmodifiable Map getPermissions() { 25 | return user().getCachedData().getPermissionData(options()).getPermissionMap(); 26 | } 27 | 28 | @Override 29 | public TriState checkPermission(String permission) { 30 | return switch (user().getCachedData().getPermissionData(options()).checkPermission(permission)) { 31 | case FALSE -> TriState.FALSE; 32 | case TRUE -> TriState.TRUE; 33 | case UNDEFINED -> TriState.NOT_SET; 34 | }; 35 | } 36 | 37 | @Override 38 | public boolean addPermission(String permission) { 39 | return setPermission(permission, true); 40 | } 41 | 42 | @Override 43 | public boolean removePermission(String permission) { 44 | var result = user().data().remove(Node.builder(permission).context(options().context()).build()); 45 | LuckPermsProvider.get().getUserManager().saveUser(user()); 46 | return result.wasSuccessful(); 47 | } 48 | 49 | @Override 50 | public boolean setPermission(String permission, boolean value) { 51 | var result = user().data().add(Node.builder(permission).value(value).context(options().context()).build()); 52 | LuckPermsProvider.get().getUserManager().saveUser(user()); 53 | return result.wasSuccessful(); 54 | } 55 | 56 | @Override 57 | public Optional getInfoNode(String key, Function mapper) { 58 | return user().getCachedData().getMetaData(options()).getMetaValue(key, mapper); 59 | } 60 | 61 | @Override 62 | public boolean setInfoNode(String key, String value) { 63 | var result = user().data().add(MetaNode.builder(key, value).context(options().context()).build()); 64 | LuckPermsProvider.get().getUserManager().saveUser(user()); 65 | return result.wasSuccessful(); 66 | } 67 | 68 | @Override 69 | public boolean removeInfoNode(String key) { 70 | user().data().clear(options().context(), node -> node.getKey().equals(key)); 71 | LuckPermsProvider.get().getUserManager().saveUser(user()); 72 | return true; 73 | } 74 | 75 | @Override 76 | public boolean removeInfoNode(String key, String value) { 77 | var result = user().data().remove(MetaNode.builder(key, value).context(options().context()).build()); 78 | LuckPermsProvider.get().getUserManager().saveUser(user()); 79 | return result.wasSuccessful(); 80 | } 81 | 82 | @Override 83 | public Set getGroups() { 84 | return user().getInheritedGroups(options()).stream() 85 | .map(group -> new LuckPermsGroup(group, options(), null)) 86 | .collect(Collectors.toUnmodifiableSet()); 87 | } 88 | 89 | @Override 90 | public String getPrimaryGroup() { 91 | return user().getPrimaryGroup(); 92 | } 93 | 94 | @Override 95 | public boolean addGroup(Group group) { 96 | return addGroup(group.getName()); 97 | } 98 | 99 | @Override 100 | public boolean addGroup(String name) { 101 | return addPermission("group." + name); 102 | } 103 | 104 | @Override 105 | public boolean inGroup(Group group) { 106 | return inGroup(group.getName()); 107 | } 108 | 109 | @Override 110 | public boolean inGroup(String name) { 111 | return checkPermission("group." + name).equals(TriState.TRUE); 112 | } 113 | 114 | @Override 115 | public boolean removeGroup(Group group) { 116 | return removeGroup(group.getName()); 117 | } 118 | 119 | @Override 120 | public boolean removeGroup(String name) { 121 | return removePermission("group." + name); 122 | } 123 | 124 | @Override 125 | public boolean setPrimaryGroup(Group group) { 126 | return setPrimaryGroup(group.getName()); 127 | } 128 | 129 | @Override 130 | public boolean setPrimaryGroup(String name) { 131 | return user.setPrimaryGroup(name).wasSuccessful(); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/model/permission/SuperPermsPermissionHolder.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.model.permission; 2 | 3 | import net.kyori.adventure.util.TriState; 4 | import net.thenextlvl.service.api.permission.PermissionHolder; 5 | import org.bukkit.command.CommandSender; 6 | import org.bukkit.permissions.PermissionAttachmentInfo; 7 | import org.jetbrains.annotations.Unmodifiable; 8 | import org.jspecify.annotations.NullMarked; 9 | 10 | import java.util.Map; 11 | import java.util.Optional; 12 | import java.util.function.Function; 13 | import java.util.stream.Collectors; 14 | 15 | @NullMarked 16 | public record SuperPermsPermissionHolder(CommandSender sender) implements PermissionHolder { 17 | @Override 18 | public @Unmodifiable Map getPermissions() { 19 | return sender.getEffectivePermissions().stream() 20 | .collect(Collectors.toUnmodifiableMap( 21 | PermissionAttachmentInfo::getPermission, 22 | PermissionAttachmentInfo::getValue 23 | )); 24 | } 25 | 26 | @Override 27 | public TriState checkPermission(String permission) { 28 | return sender.permissionValue(permission); 29 | } 30 | 31 | @Override 32 | public boolean addPermission(String permission) { 33 | return false; 34 | } 35 | 36 | @Override 37 | public boolean removePermission(String permission) { 38 | return false; 39 | } 40 | 41 | @Override 42 | public boolean setPermission(String permission, boolean value) { 43 | return false; 44 | } 45 | 46 | @Override 47 | public Optional getInfoNode(String key, Function mapper) { 48 | return Optional.empty(); 49 | } 50 | 51 | @Override 52 | public boolean removeInfoNode(String key) { 53 | return false; 54 | } 55 | 56 | @Override 57 | public boolean removeInfoNode(String key, String value) { 58 | return false; 59 | } 60 | 61 | @Override 62 | public boolean setInfoNode(String key, String value) { 63 | return false; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/version/PluginVersionChecker.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.version; 2 | 3 | import core.paper.version.PaperHangarVersionChecker; 4 | import core.version.SemanticVersion; 5 | import org.bukkit.plugin.Plugin; 6 | import org.jspecify.annotations.NullMarked; 7 | 8 | @NullMarked 9 | public class PluginVersionChecker extends PaperHangarVersionChecker { 10 | public PluginVersionChecker(Plugin plugin) { 11 | super(plugin, "TheNextLvl", "ServiceIO"); 12 | } 13 | 14 | @Override 15 | public SemanticVersion parseVersion(String version) { 16 | return SemanticVersion.parse(version); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.wrapper.service; 2 | 3 | import net.milkbowl.vault.economy.Economy; 4 | import net.milkbowl.vault.economy.EconomyResponse; 5 | import net.thenextlvl.service.ServicePlugin; 6 | import net.thenextlvl.service.api.economy.bank.Bank; 7 | import net.thenextlvl.service.api.economy.bank.BankController; 8 | import net.thenextlvl.service.wrapper.service.model.WrappedBank; 9 | import org.bukkit.OfflinePlayer; 10 | import org.bukkit.World; 11 | import org.bukkit.plugin.Plugin; 12 | import org.jetbrains.annotations.Unmodifiable; 13 | import org.jspecify.annotations.NullMarked; 14 | 15 | import java.util.Optional; 16 | import java.util.Set; 17 | import java.util.UUID; 18 | import java.util.concurrent.CompletableFuture; 19 | import java.util.stream.Collectors; 20 | 21 | @NullMarked 22 | public class BankServiceWrapper implements BankController { 23 | private final Economy economy; 24 | private final Plugin provider; 25 | private final ServicePlugin plugin; 26 | 27 | public BankServiceWrapper(Economy economy, Plugin provider, ServicePlugin plugin) { 28 | this.economy = economy; 29 | this.plugin = plugin; 30 | this.provider = provider; 31 | } 32 | 33 | @Override 34 | public CompletableFuture createBank(OfflinePlayer player, String name) throws IllegalStateException { 35 | return CompletableFuture.supplyAsync(() -> economy.createBank(name, player)) 36 | .thenApply(bank -> getBank(name).orElseThrow()); 37 | } 38 | 39 | @Override 40 | public CompletableFuture createBank(OfflinePlayer player, String name, World world) throws IllegalStateException { 41 | return createBank(player, name); 42 | } 43 | 44 | @Override 45 | public CompletableFuture createBank(UUID uuid, String name) throws IllegalStateException { 46 | return createBank(plugin.getServer().getOfflinePlayer(uuid), name); 47 | } 48 | 49 | @Override 50 | public CompletableFuture createBank(UUID uuid, String name, World world) throws IllegalStateException { 51 | return createBank(plugin.getServer().getOfflinePlayer(uuid), name, world); 52 | } 53 | 54 | @Override 55 | public CompletableFuture loadBank(String name) { 56 | return CompletableFuture.completedFuture(getBank(name).orElse(null)); 57 | } 58 | 59 | @Override 60 | public CompletableFuture loadBank(UUID uuid) { 61 | return CompletableFuture.completedFuture(getBank(uuid).orElse(null)); 62 | } 63 | 64 | @Override 65 | public CompletableFuture loadBank(UUID uuid, World world) { 66 | return CompletableFuture.completedFuture(getBank(uuid, world).orElse(null)); 67 | } 68 | 69 | @Override 70 | public CompletableFuture<@Unmodifiable Set> loadBanks() { 71 | return CompletableFuture.supplyAsync(this::getBanks); 72 | } 73 | 74 | @Override 75 | public CompletableFuture<@Unmodifiable Set> loadBanks(World world) { 76 | return CompletableFuture.supplyAsync(() -> getBanks(world)); 77 | } 78 | 79 | @Override 80 | public CompletableFuture deleteBank(String name) { 81 | return CompletableFuture.completedFuture(economy.deleteBank(name)) 82 | .thenApply(EconomyResponse::transactionSuccess); 83 | } 84 | 85 | @Override 86 | public CompletableFuture deleteBank(UUID uuid) { 87 | return deleteBank(getBank(uuid).orElseThrow().getName()); 88 | } 89 | 90 | @Override 91 | public CompletableFuture deleteBank(UUID uuid, World world) { 92 | return deleteBank(getBank(uuid, world).orElseThrow().getName()); 93 | } 94 | 95 | @Override 96 | public @Unmodifiable Set getBanks() { 97 | return economy.getBanks().stream() 98 | .map(bank -> new WrappedBank(bank, null, economy, plugin)) 99 | .collect(Collectors.toUnmodifiableSet()); 100 | } 101 | 102 | @Override 103 | public @Unmodifiable Set getBanks(World world) { 104 | return getBanks(); 105 | } 106 | 107 | @Override 108 | public Optional getBank(String name) { 109 | return Optional.of(new WrappedBank(name, null, economy, plugin)); 110 | } 111 | 112 | @Override 113 | public Optional getBank(UUID uuid) { 114 | return Optional.empty(); 115 | } 116 | 117 | @Override 118 | public Optional getBank(UUID uuid, World world) { 119 | return Optional.empty(); 120 | } 121 | 122 | @Override 123 | public Plugin getPlugin() { 124 | return provider; 125 | } 126 | 127 | @Override 128 | public String getName() { 129 | return economy.getName(); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/wrapper/service/ChatServiceWrapper.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.wrapper.service; 2 | 3 | import net.milkbowl.vault.chat.Chat; 4 | import net.thenextlvl.service.ServicePlugin; 5 | import net.thenextlvl.service.api.chat.ChatController; 6 | import net.thenextlvl.service.api.chat.ChatProfile; 7 | import net.thenextlvl.service.wrapper.service.model.WrappedChatProfile; 8 | import org.bukkit.OfflinePlayer; 9 | import org.bukkit.World; 10 | import org.bukkit.plugin.Plugin; 11 | import org.jspecify.annotations.NullMarked; 12 | 13 | import java.util.Optional; 14 | import java.util.UUID; 15 | import java.util.concurrent.CompletableFuture; 16 | 17 | @NullMarked 18 | public class ChatServiceWrapper implements ChatController { 19 | private final Plugin provider; 20 | private final ServicePlugin plugin; 21 | private final Chat chat; 22 | 23 | public ChatServiceWrapper(Chat chat, Plugin provider, ServicePlugin plugin) { 24 | this.chat = chat; 25 | this.plugin = plugin; 26 | this.provider = provider; 27 | } 28 | 29 | @Override 30 | public CompletableFuture loadProfile(OfflinePlayer player) { 31 | return CompletableFuture.supplyAsync(() -> new WrappedChatProfile(null, chat, player)); 32 | } 33 | 34 | @Override 35 | public CompletableFuture loadProfile(OfflinePlayer player, World world) { 36 | return CompletableFuture.supplyAsync(() -> new WrappedChatProfile(world, chat, player)); 37 | } 38 | 39 | @Override 40 | public CompletableFuture loadProfile(UUID uuid) { 41 | return loadProfile(plugin.getServer().getOfflinePlayer(uuid)); 42 | } 43 | 44 | @Override 45 | public CompletableFuture loadProfile(UUID uuid, World world) { 46 | return loadProfile(plugin.getServer().getOfflinePlayer(uuid), world); 47 | } 48 | 49 | @Override 50 | public Optional getProfile(OfflinePlayer player) { 51 | return Optional.of(new WrappedChatProfile(null, chat, player)); 52 | } 53 | 54 | @Override 55 | public Optional getProfile(OfflinePlayer player, World world) { 56 | return Optional.of(new WrappedChatProfile(world, chat, player)); 57 | } 58 | 59 | @Override 60 | public Optional getProfile(UUID uuid) { 61 | return getProfile(plugin.getServer().getOfflinePlayer(uuid)); 62 | } 63 | 64 | @Override 65 | public Optional getProfile(UUID uuid, World world) { 66 | return getProfile(plugin.getServer().getOfflinePlayer(uuid), world); 67 | } 68 | 69 | @Override 70 | public Plugin getPlugin() { 71 | return provider; 72 | } 73 | 74 | @Override 75 | public String getName() { 76 | return chat.getName(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.wrapper.service; 2 | 3 | import net.milkbowl.vault.economy.Economy; 4 | import net.thenextlvl.service.ServicePlugin; 5 | import net.thenextlvl.service.api.economy.Account; 6 | import net.thenextlvl.service.api.economy.EconomyController; 7 | import net.thenextlvl.service.wrapper.service.model.WrappedAccount; 8 | import org.bukkit.OfflinePlayer; 9 | import org.bukkit.World; 10 | import org.bukkit.plugin.Plugin; 11 | import org.jetbrains.annotations.Unmodifiable; 12 | import org.jspecify.annotations.NullMarked; 13 | 14 | import java.util.Arrays; 15 | import java.util.Locale; 16 | import java.util.Optional; 17 | import java.util.Set; 18 | import java.util.UUID; 19 | import java.util.concurrent.CompletableFuture; 20 | import java.util.stream.Collectors; 21 | 22 | @NullMarked 23 | public class EconomyServiceWrapper implements EconomyController { 24 | private final Economy economy; 25 | private final Plugin provider; 26 | private final ServicePlugin plugin; 27 | 28 | public EconomyServiceWrapper(Economy economy, Plugin provider, ServicePlugin plugin) { 29 | this.economy = economy; 30 | this.plugin = plugin; 31 | this.provider = provider; 32 | } 33 | 34 | @Override 35 | public String format(Number amount) { 36 | return economy.format(amount.doubleValue()); 37 | } 38 | 39 | @Override 40 | public String getCurrencyNamePlural(Locale locale) { 41 | return economy.currencyNamePlural(); 42 | } 43 | 44 | @Override 45 | public String getCurrencyNameSingular(Locale locale) { 46 | return economy.currencyNameSingular(); 47 | } 48 | 49 | @Override 50 | public String getCurrencySymbol() { 51 | return ""; 52 | } 53 | 54 | @Override 55 | public CompletableFuture<@Unmodifiable Set> loadAccounts() { 56 | return CompletableFuture.supplyAsync(this::getAccounts); 57 | } 58 | 59 | @Override 60 | public @Unmodifiable Set getAccounts() { 61 | return Arrays.stream(plugin.getServer().getOfflinePlayers()) 62 | .filter(economy::hasAccount) 63 | .map(player -> new WrappedAccount(null, economy, player)) 64 | .collect(Collectors.toUnmodifiableSet()); 65 | } 66 | 67 | @Override 68 | public Optional getAccount(OfflinePlayer player) { 69 | if (!economy.hasAccount(player)) return Optional.empty(); 70 | return Optional.of(new WrappedAccount(null, economy, player)); 71 | } 72 | 73 | @Override 74 | public Optional getAccount(OfflinePlayer player, World world) { 75 | if (!economy.hasAccount(player, world.getName())) return Optional.empty(); 76 | return Optional.of(new WrappedAccount(world, economy, player)); 77 | } 78 | 79 | @Override 80 | public Optional getAccount(UUID uuid) { 81 | return getAccount(plugin.getServer().getOfflinePlayer(uuid)); 82 | } 83 | 84 | @Override 85 | public Optional getAccount(UUID uuid, World world) { 86 | return getAccount(plugin.getServer().getOfflinePlayer(uuid), world); 87 | } 88 | 89 | @Override 90 | public CompletableFuture createAccount(OfflinePlayer player) { 91 | return CompletableFuture.supplyAsync(() -> economy.createPlayerAccount(player)) 92 | .thenApply(account -> getAccount(player).orElseThrow()); 93 | } 94 | 95 | @Override 96 | public CompletableFuture createAccount(OfflinePlayer player, World world) { 97 | return CompletableFuture.supplyAsync(() -> economy.createPlayerAccount(player, world.getName())) 98 | .thenApply(account -> getAccount(player, world).orElseThrow()); 99 | } 100 | 101 | @Override 102 | public CompletableFuture createAccount(UUID uuid) { 103 | return createAccount(plugin.getServer().getOfflinePlayer(uuid)); 104 | } 105 | 106 | @Override 107 | public CompletableFuture createAccount(UUID uuid, World world) { 108 | return createAccount(plugin.getServer().getOfflinePlayer(uuid), world); 109 | } 110 | 111 | @Override 112 | public CompletableFuture> loadAccount(OfflinePlayer player) { 113 | return CompletableFuture.completedFuture(getAccount(player)); 114 | } 115 | 116 | @Override 117 | public CompletableFuture> loadAccount(OfflinePlayer player, World world) { 118 | return CompletableFuture.completedFuture(getAccount(player, world)); 119 | } 120 | 121 | @Override 122 | public CompletableFuture> loadAccount(UUID uuid) { 123 | return loadAccount(plugin.getServer().getOfflinePlayer(uuid)); 124 | } 125 | 126 | @Override 127 | public CompletableFuture> loadAccount(UUID uuid, World world) { 128 | return loadAccount(plugin.getServer().getOfflinePlayer(uuid), world); 129 | } 130 | 131 | @Override 132 | public CompletableFuture deleteAccount(UUID uuid) { 133 | return CompletableFuture.completedFuture(false); 134 | } 135 | 136 | @Override 137 | public CompletableFuture deleteAccount(UUID uuid, World world) { 138 | return CompletableFuture.completedFuture(false); 139 | } 140 | 141 | @Override 142 | public int fractionalDigits() { 143 | return economy.fractionalDigits(); 144 | } 145 | 146 | @Override 147 | public Plugin getPlugin() { 148 | return provider; 149 | } 150 | 151 | @Override 152 | public String getName() { 153 | return economy.getName(); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/wrapper/service/PermissionServiceWrapper.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.wrapper.service; 2 | 3 | import net.milkbowl.vault.permission.Permission; 4 | import net.thenextlvl.service.ServicePlugin; 5 | import net.thenextlvl.service.api.permission.PermissionController; 6 | import net.thenextlvl.service.api.permission.PermissionHolder; 7 | import net.thenextlvl.service.wrapper.service.model.WrappedPermissionHolder; 8 | import org.bukkit.OfflinePlayer; 9 | import org.bukkit.World; 10 | import org.bukkit.plugin.Plugin; 11 | import org.jspecify.annotations.NullMarked; 12 | 13 | import java.util.Optional; 14 | import java.util.UUID; 15 | import java.util.concurrent.CompletableFuture; 16 | 17 | @NullMarked 18 | public class PermissionServiceWrapper implements PermissionController { 19 | private final Permission permission; 20 | private final Plugin provider; 21 | private final ServicePlugin plugin; 22 | 23 | public PermissionServiceWrapper(Permission permission, Plugin provider, ServicePlugin plugin) { 24 | this.permission = permission; 25 | this.plugin = plugin; 26 | this.provider = provider; 27 | } 28 | 29 | @Override 30 | public CompletableFuture loadPermissionHolder(OfflinePlayer player) { 31 | return CompletableFuture.completedFuture(new WrappedPermissionHolder(null, player, permission)); 32 | } 33 | 34 | @Override 35 | public CompletableFuture loadPermissionHolder(OfflinePlayer player, World world) { 36 | return CompletableFuture.completedFuture(new WrappedPermissionHolder(world, player, permission)); 37 | } 38 | 39 | @Override 40 | public CompletableFuture loadPermissionHolder(UUID uuid) { 41 | return loadPermissionHolder(plugin.getServer().getOfflinePlayer(uuid)); 42 | } 43 | 44 | @Override 45 | public CompletableFuture loadPermissionHolder(UUID uuid, World world) { 46 | return loadPermissionHolder(plugin.getServer().getOfflinePlayer(uuid), world); 47 | } 48 | 49 | @Override 50 | public Optional getPermissionHolder(OfflinePlayer player) { 51 | return Optional.of(new WrappedPermissionHolder(null, player, permission)); 52 | } 53 | 54 | @Override 55 | public Optional getPermissionHolder(OfflinePlayer player, World world) { 56 | return Optional.of(new WrappedPermissionHolder(world, player, permission)); 57 | } 58 | 59 | @Override 60 | public Optional getPermissionHolder(UUID uuid) { 61 | return getPermissionHolder(plugin.getServer().getOfflinePlayer(uuid)); 62 | } 63 | 64 | @Override 65 | public Optional getPermissionHolder(UUID uuid, World world) { 66 | return getPermissionHolder(plugin.getServer().getOfflinePlayer(uuid), world); 67 | } 68 | 69 | @Override 70 | public Plugin getPlugin() { 71 | return provider; 72 | } 73 | 74 | @Override 75 | public String getName() { 76 | return permission.getName(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.wrapper.service.model; 2 | 3 | import net.milkbowl.vault.economy.Economy; 4 | import net.thenextlvl.service.api.economy.Account; 5 | import org.bukkit.OfflinePlayer; 6 | import org.bukkit.World; 7 | import org.jspecify.annotations.NullMarked; 8 | import org.jspecify.annotations.Nullable; 9 | 10 | import java.math.BigDecimal; 11 | import java.util.Optional; 12 | import java.util.UUID; 13 | 14 | @NullMarked 15 | public class WrappedAccount implements Account { 16 | private final @Nullable World world; 17 | private final Economy economy; 18 | private final OfflinePlayer holder; 19 | 20 | public WrappedAccount(@Nullable World world, Economy economy, OfflinePlayer holder) { 21 | this.world = world; 22 | this.economy = economy; 23 | this.holder = holder; 24 | } 25 | 26 | @Override 27 | public BigDecimal deposit(Number amount) { 28 | var response = economy.depositPlayer(holder, world != null ? world.getName() : null, amount.doubleValue()); 29 | return new BigDecimal(response.balance); 30 | } 31 | 32 | @Override 33 | public BigDecimal getBalance() { 34 | var balance = economy.getBalance(holder, world != null ? world.getName() : null); 35 | return new BigDecimal(balance); 36 | } 37 | 38 | @Override 39 | public BigDecimal withdraw(Number amount) { 40 | var response = economy.withdrawPlayer(holder, world != null ? world.getName() : null, amount.doubleValue()); 41 | return new BigDecimal(response.balance); 42 | } 43 | 44 | @Override 45 | public Optional getWorld() { 46 | return Optional.ofNullable(world); 47 | } 48 | 49 | @Override 50 | public UUID getOwner() { 51 | return holder.getUniqueId(); 52 | } 53 | 54 | @Override 55 | public void setBalance(Number balance) { 56 | var difference = balance.doubleValue() - getBalance().doubleValue(); 57 | if (difference > 0) deposit(difference); 58 | else if (difference < 0) withdraw(-difference); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.wrapper.service.model; 2 | 3 | import net.milkbowl.vault.economy.Economy; 4 | import net.thenextlvl.service.ServicePlugin; 5 | import net.thenextlvl.service.api.economy.bank.Bank; 6 | import org.bukkit.OfflinePlayer; 7 | import org.bukkit.World; 8 | import org.jetbrains.annotations.Unmodifiable; 9 | import org.jspecify.annotations.NullMarked; 10 | import org.jspecify.annotations.Nullable; 11 | 12 | import java.math.BigDecimal; 13 | import java.util.Arrays; 14 | import java.util.Optional; 15 | import java.util.Set; 16 | import java.util.UUID; 17 | import java.util.stream.Collectors; 18 | 19 | @NullMarked 20 | public class WrappedBank implements Bank { 21 | private final @Nullable World world; 22 | private final Economy economy; 23 | private final ServicePlugin plugin; 24 | private final String name; 25 | 26 | public WrappedBank(String name, @Nullable World world, Economy economy, ServicePlugin plugin) { 27 | this.name = name; 28 | this.world = world; 29 | this.economy = economy; 30 | this.plugin = plugin; 31 | } 32 | 33 | @Override 34 | public BigDecimal deposit(Number amount) { 35 | return new BigDecimal(economy.bankDeposit(name, amount.doubleValue()).balance); 36 | } 37 | 38 | @Override 39 | public BigDecimal getBalance() { 40 | return new BigDecimal(economy.bankBalance(name).balance); 41 | } 42 | 43 | @Override 44 | public BigDecimal withdraw(Number amount) { 45 | return new BigDecimal(economy.bankWithdraw(name, amount.doubleValue()).balance); 46 | } 47 | 48 | @Override 49 | public Optional getWorld() { 50 | return Optional.ofNullable(world); 51 | } 52 | 53 | @Override 54 | public UUID getOwner() { 55 | return Arrays.stream(plugin.getServer().getOfflinePlayers()) 56 | .filter(player -> economy.isBankOwner(name, player).transactionSuccess()) 57 | .map(OfflinePlayer::getUniqueId) 58 | .findAny() 59 | .orElse(new UUID(0, 0)); 60 | } 61 | 62 | @Override 63 | public void setBalance(Number balance) { 64 | var difference = balance.doubleValue() - getBalance().doubleValue(); 65 | if (difference > 0) deposit(difference); 66 | else if (difference < 0) withdraw(-difference); 67 | } 68 | 69 | @Override 70 | public @Unmodifiable Set getMembers() { 71 | return Arrays.stream(plugin.getServer().getOfflinePlayers()) 72 | .filter(player -> economy.isBankMember(name, player).transactionSuccess()) 73 | .map(OfflinePlayer::getUniqueId) 74 | .collect(Collectors.toUnmodifiableSet()); 75 | } 76 | 77 | @Override 78 | public String getName() { 79 | return name; 80 | } 81 | 82 | @Override 83 | public boolean addMember(UUID uuid) { 84 | return false; 85 | } 86 | 87 | @Override 88 | public boolean isMember(UUID uuid) { 89 | return false; 90 | } 91 | 92 | @Override 93 | public boolean removeMember(UUID uuid) { 94 | return false; 95 | } 96 | 97 | @Override 98 | public boolean setOwner(UUID uuid) { 99 | return false; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedChatProfile.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.wrapper.service.model; 2 | 3 | import net.milkbowl.vault.chat.Chat; 4 | import net.thenextlvl.service.api.chat.ChatProfile; 5 | import org.bukkit.OfflinePlayer; 6 | import org.bukkit.World; 7 | import org.jetbrains.annotations.Unmodifiable; 8 | import org.jspecify.annotations.NullMarked; 9 | import org.jspecify.annotations.Nullable; 10 | 11 | import java.util.Map; 12 | import java.util.Optional; 13 | import java.util.Set; 14 | import java.util.function.Function; 15 | 16 | @NullMarked 17 | public class WrappedChatProfile implements ChatProfile { 18 | private final @Nullable World world; 19 | private final Chat chat; 20 | private final OfflinePlayer holder; 21 | 22 | public WrappedChatProfile(@Nullable World world, Chat chat, OfflinePlayer holder) { 23 | this.world = world; 24 | this.chat = chat; 25 | this.holder = holder; 26 | } 27 | 28 | @Override 29 | public Optional getDisplayName() { 30 | return Optional.empty(); 31 | } 32 | 33 | @Override 34 | public Optional getName() { 35 | return Optional.ofNullable(holder.getName()); 36 | } 37 | 38 | @Override 39 | public Optional getPrefix(int priority) { 40 | return Optional.ofNullable(chat.getPlayerPrefix(world != null ? world.getName() : null, holder)); 41 | } 42 | 43 | @Override 44 | public @Unmodifiable Map getPrefixes() { 45 | return getPrefix().map(prefix -> Map.of(0, prefix)).orElseGet(Map::of); 46 | } 47 | 48 | @Override 49 | public Optional getPrimaryGroup() { 50 | return Optional.ofNullable(chat.getPrimaryGroup(world != null ? world.getName() : null, holder)); 51 | } 52 | 53 | @Override 54 | public Optional getSuffix(int priority) { 55 | return Optional.ofNullable(chat.getPlayerSuffix(world != null ? world.getName() : null, holder)); 56 | } 57 | 58 | @Override 59 | public @Unmodifiable Map getSuffixes() { 60 | return getSuffix().map(suffix -> Map.of(0, suffix)).orElseGet(Map::of); 61 | } 62 | 63 | @Override 64 | public @Unmodifiable Set getGroups() { 65 | return Set.of(chat.getPlayerGroups(world != null ? world.getName() : null, holder)); 66 | } 67 | 68 | @Override 69 | public boolean setDisplayName(@Nullable String displayName) { 70 | return false; 71 | } 72 | 73 | @Override 74 | public boolean setPrefix(@Nullable String prefix, int priority) { 75 | chat.setPlayerPrefix(world != null ? world.getName() : null, holder, prefix); 76 | return true; 77 | } 78 | 79 | @Override 80 | public boolean setSuffix(@Nullable String suffix, int priority) { 81 | chat.setPlayerSuffix(world != null ? world.getName() : null, holder, suffix); 82 | return true; 83 | } 84 | 85 | @Override 86 | public Optional getInfoNode(String key, Function<@Nullable String, @Nullable T> mapper) { 87 | return Optional.ofNullable(chat.getPlayerInfoString( 88 | world != null ? world.getName() : null, holder, key, null 89 | )).map(mapper); 90 | } 91 | 92 | @Override 93 | public Optional booleanInfoNode(String key) { 94 | return Optional.of(chat.getPlayerInfoBoolean( 95 | world != null ? world.getName() : null, holder, key, false 96 | )); 97 | } 98 | 99 | @Override 100 | public Optional doubleInfoNode(String key) throws NumberFormatException { 101 | return Optional.of(chat.getPlayerInfoDouble( 102 | world != null ? world.getName() : null, holder, key, 0 103 | )); 104 | } 105 | 106 | @Override 107 | public Optional intInfoNode(String key) throws NumberFormatException { 108 | return Optional.of(chat.getPlayerInfoInteger( 109 | world != null ? world.getName() : null, holder, key, 0 110 | )); 111 | } 112 | 113 | @Override 114 | public boolean removeInfoNode(String key) { 115 | chat.setPlayerInfoString(world != null ? world.getName() : null, holder, key, null); 116 | return true; 117 | } 118 | 119 | @Override 120 | public boolean setInfoNode(String key, String value) { 121 | chat.setPlayerInfoString(world != null ? world.getName() : null, holder, key, value); 122 | return true; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedPermissionHolder.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.wrapper.service.model; 2 | 3 | import net.kyori.adventure.util.TriState; 4 | import net.milkbowl.vault.permission.Permission; 5 | import net.thenextlvl.service.api.permission.PermissionHolder; 6 | import org.bukkit.OfflinePlayer; 7 | import org.bukkit.World; 8 | import org.bukkit.permissions.PermissionAttachmentInfo; 9 | import org.jetbrains.annotations.Unmodifiable; 10 | import org.jspecify.annotations.NullMarked; 11 | import org.jspecify.annotations.Nullable; 12 | 13 | import java.util.Map; 14 | import java.util.Optional; 15 | import java.util.function.Function; 16 | import java.util.stream.Collectors; 17 | 18 | @NullMarked 19 | public class WrappedPermissionHolder implements PermissionHolder { 20 | private final @Nullable World world; 21 | private final OfflinePlayer holder; 22 | private final Permission permission; 23 | 24 | public WrappedPermissionHolder(@Nullable World world, OfflinePlayer holder, Permission permission) { 25 | this.world = world; 26 | this.holder = holder; 27 | this.permission = permission; 28 | } 29 | 30 | @Override 31 | public @Unmodifiable Map getPermissions() { 32 | var player = holder.getPlayer(); 33 | return player != null ? player.getEffectivePermissions().stream() 34 | .collect(Collectors.toUnmodifiableMap( 35 | PermissionAttachmentInfo::getPermission, 36 | PermissionAttachmentInfo::getValue 37 | )) : Map.of(); 38 | } 39 | 40 | @Override 41 | public TriState checkPermission(String permission) { 42 | return TriState.byBoolean(this.permission.playerHas(world != null ? world.getName() : null, holder, permission)); 43 | } 44 | 45 | @Override 46 | public boolean addPermission(String permission) { 47 | return this.permission.playerAdd(world != null ? world.getName() : null, holder, permission); 48 | } 49 | 50 | @Override 51 | public boolean removePermission(String permission) { 52 | return this.permission.playerRemove(world != null ? world.getName() : null, holder, permission); 53 | } 54 | 55 | @Override 56 | public boolean setPermission(String permission, boolean value) { 57 | return false; 58 | } 59 | 60 | @Override 61 | public Optional getInfoNode(String key, Function<@Nullable String, @Nullable T> mapper) { 62 | return Optional.empty(); 63 | } 64 | 65 | @Override 66 | public boolean removeInfoNode(String key) { 67 | return false; 68 | } 69 | 70 | @Override 71 | public boolean setInfoNode(String key, String value) { 72 | return false; 73 | } 74 | } -------------------------------------------------------------------------------- /plugin/src/main/resources/service-io.properties: -------------------------------------------------------------------------------- 1 | prefix=ServiceIO » 2 | service.bank.none=No bank service found 3 | service.character.none=No character service found 4 | service.chat.none=No chat service found 5 | service.convert.done= Completed conversion in seconds, please verify the data before using it 6 | service.convert.failed= Conversion failed after seconds, see the console for more information 7 | service.convert.running= A conversion is already running 8 | service.convert.source-target= Source and target service cannot be the same 9 | service.convert.start= Start converting data from to . This may take a while 10 | service.economy.none=No economy service found 11 | service.group.none=No group service found 12 | service.hologram.none=No hologram service found 13 | service.permission.none=No permission service found 14 | service.provider.name=<#0288D1>: 15 | service.provider.registrations= 16 | service.version=ServiceIO Information (v) -------------------------------------------------------------------------------- /plugin/src/main/resources/service-io_german.properties: -------------------------------------------------------------------------------- 1 | service.bank.none=Kein Bankdienst gefunden 2 | service.character.none=Kein Charakter-Dienst gefunden 3 | service.chat.none=Kein Chatdienst gefunden 4 | service.convert.done= Konvertierung wurde in Sekunden beendet, bitte überprüfe die Daten, bevor du sie verwendest 5 | service.convert.failed= Konvertierung ist nach Sekunden fehlgeschlagen, schaue in die Konsole für mehr Informationen 6 | service.convert.running= Eine Konvertierung läuft bereits 7 | service.convert.source-target= Quell- und Zieldienst können nicht identisch sein 8 | service.convert.start= Datenkonvertierung von zu wurde gestartet. Dies könnte einige Zeit in Anspruch nehmen 9 | service.economy.none=Kein Economy-Dienst gefunden 10 | service.group.none=Kein Gruppendienst gefunden 11 | service.hologram.none=Kein Hologramm-Dienst gefunden 12 | service.permission.none=Kein Berechtigungsdienst gefunden 13 | service.version=Informationen zu ServiceIO (v) -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("org.gradle.toolchains.foojay-resolver-convention").version("1.0.0") 3 | } 4 | 5 | rootProject.name = "service-io" 6 | include("plugin") 7 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/Controller.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api; 2 | 3 | import org.bukkit.plugin.Plugin; 4 | import org.jetbrains.annotations.Contract; 5 | import org.jspecify.annotations.NullMarked; 6 | 7 | @NullMarked 8 | public interface Controller { 9 | /** 10 | * Retrieves the plugin associated with the controller. 11 | * 12 | * @return the plugin instance linked to the controller. 13 | */ 14 | @Contract(pure = true) 15 | Plugin getPlugin(); 16 | 17 | /** 18 | * Retrieves the name associated with the controller. 19 | * 20 | * @return the name of the controller. 21 | */ 22 | @Contract(pure = true) 23 | String getName(); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/capability/Capability.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.capability; 2 | 3 | import net.kyori.adventure.key.Keyed; 4 | 5 | /** 6 | * Represents a specific functionality or feature that can be supported or provided 7 | * by a system, service, or component. 8 | * A {@code Capability} serves as a key to identify and interact with a particular 9 | * feature or capability, allowing for modular and extensible design. 10 | *

11 | * This interface extends {@link Keyed}, which provides a mechanism for providing 12 | * unique identifiers for each capability. 13 | *

14 | * Implementations of this interface can be used in conjunction with capability 15 | * providers or related systems to organize and query available functionalities. 16 | */ 17 | public interface Capability extends Keyed { 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/capability/CapabilityException.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.capability; 2 | 3 | import org.jspecify.annotations.NullMarked; 4 | import org.jspecify.annotations.Nullable; 5 | 6 | /** 7 | * An exception that indicates a problem related to a specific {@link Capability}. 8 | * This exception is typically thrown when there is an issue or unsupported operation 9 | * associated with a particular capability in the system. 10 | */ 11 | @NullMarked 12 | public class CapabilityException extends RuntimeException { 13 | private final Capability capability; 14 | 15 | /** 16 | * Creates a new {@code CapabilityException} with the specified detail message and 17 | * the related capability that caused this exception. 18 | * 19 | * @param message the detail message, providing additional information about the exception. 20 | * @param capability the {@link Capability} instance associated with this exception, 21 | * indicating the capability that caused the issue. 22 | */ 23 | public CapabilityException(String message, Capability capability) { 24 | super(message); 25 | this.capability = capability; 26 | } 27 | 28 | /** 29 | * Constructs a new {@code CapabilityException} with a specified detail message, cause, 30 | * and the associated capability that led to the exception. 31 | * 32 | * @param message the detail message, providing additional information about the exception. 33 | * @param cause the cause of the exception, which may be {@code null} to indicate no specific cause. 34 | * @param capability the {@link Capability} instance associated with this exception, 35 | * indicating the capability that caused the issue. 36 | */ 37 | public CapabilityException(String message, @Nullable Throwable cause, Capability capability) { 38 | super(message, cause); 39 | this.capability = capability; 40 | } 41 | 42 | /** 43 | * Retrieves the capability associated with this exception. 44 | * 45 | * @return the {@link Capability} instance that caused this exception, 46 | * representing a specific feature or limitation. 47 | */ 48 | public Capability getCapability() { 49 | return this.capability; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/capability/CapabilityProvider.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.capability; 2 | 3 | import org.jetbrains.annotations.Unmodifiable; 4 | import org.jspecify.annotations.NullMarked; 5 | 6 | import java.util.Collection; 7 | import java.util.Set; 8 | 9 | /** 10 | * A generic interface providing methods to query and check support for specific capabilities. 11 | *

12 | * The {@code CapabilityProvider} interface allows implementing classes to define a set of supported 13 | * capabilities and provides mechanisms to check whether the provider supports individual or multiple capabilities. 14 | * 15 | * @param the type of {@link Capability} supported by this provider 16 | */ 17 | @NullMarked 18 | public interface CapabilityProvider { 19 | /** 20 | * Retrieves an unmodifiable set of all available capabilities supported by the capability provider. 21 | * 22 | * @return an unmodifiable {@link Set} containing the supported {@link T capability} values 23 | */ 24 | @Unmodifiable 25 | Set getCapabilities(); 26 | 27 | /** 28 | * Checks whether all the specified capabilities are supported by the capability provider. 29 | * 30 | * @param capabilities the collection of {@link T capability} instances to verify for support 31 | * @return {@code true} if all the specified capabilities are supported; {@code false} otherwise 32 | */ 33 | boolean hasCapabilities(Collection capabilities); 34 | 35 | /** 36 | * Checks whether the specified capability is supported. 37 | * 38 | * @param capability the {@link T capability} to verify for support 39 | * @return {@code true} if the given capability is supported; {@code false} otherwise 40 | */ 41 | boolean hasCapability(T capability); 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/character/Character.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.character; 2 | 3 | import net.kyori.adventure.text.Component; 4 | import net.thenextlvl.service.api.model.Persistable; 5 | import net.thenextlvl.service.api.model.Viewable; 6 | import org.bukkit.Location; 7 | import org.bukkit.World; 8 | import org.bukkit.entity.Entity; 9 | import org.bukkit.entity.EntityType; 10 | import org.jspecify.annotations.NullMarked; 11 | import org.jspecify.annotations.Nullable; 12 | 13 | import java.util.Optional; 14 | import java.util.concurrent.CompletableFuture; 15 | 16 | /** 17 | * Represents a character in a world that is associated with an entity and provides various 18 | * functionalities such as spawning, despawning, teleportation, and state management. 19 | * 20 | * @param the type of the entity associated with this character 21 | */ 22 | @NullMarked 23 | public interface Character extends Persistable, Viewable { 24 | /** 25 | * Asynchronously teleports the character to the specified location. 26 | * 27 | * @param location the {@code Location} to which the character will be teleported 28 | * @return a {@code CompletableFuture} that resolves to {@code true} if the teleportation was 29 | * successful, or {@code false} otherwise 30 | */ 31 | CompletableFuture teleportAsync(Location location); 32 | 33 | /** 34 | * Retrieves the display name of the character. 35 | * 36 | * @return the {@code Component} representing the display name of the character 37 | */ 38 | Component getDisplayName(); 39 | 40 | /** 41 | * Retrieves the type of entity associated with the character. 42 | * 43 | * @return the entity type of the character 44 | */ 45 | EntityType getType(); 46 | 47 | @Override 48 | @Nullable 49 | Location getLocation(); 50 | 51 | /** 52 | * Retrieves the entity associated with the character. 53 | *

54 | * This method requires the provider to support the {@link CharacterCapability#ACTUAL_ENTITIES} capability. 55 | * 56 | * @return an {@code Optional} containing the associated entity, or an empty {@code Optional} 57 | * if no entity is associated with the character. 58 | */ 59 | Optional getEntity(); 60 | 61 | @Override 62 | @Nullable 63 | World getWorld(); 64 | 65 | /** 66 | * Despawns the character, effectively removing it from the world or rendering it inactive. 67 | * 68 | * @return {@code true} if the character was successfully despawned, otherwise {@code false} 69 | */ 70 | boolean despawn(); 71 | 72 | /** 73 | * Checks if the character is collidable, meaning it can interact physically with other entities. 74 | * 75 | * @return {@code true} if the character is collidable, otherwise {@code false} 76 | */ 77 | boolean isCollidable(); 78 | 79 | /** 80 | * Checks if the character is invulnerable. 81 | *

82 | * This method requires the provider to support the {@link CharacterCapability#HEALTH} capability. 83 | * 84 | * @return {@code true} if the character is invulnerable, otherwise {@code false} 85 | */ 86 | boolean isInvulnerable(); 87 | 88 | /** 89 | * Checks if the character is currently spawned in the world. 90 | * 91 | * @return {@code true} if the character is spawned, otherwise {@code false} 92 | */ 93 | boolean isSpawned(); 94 | 95 | /** 96 | * Checks whether the tablist entry for the character is currently hidden. 97 | * 98 | * @return {@code true} if the tablist entry is hidden, otherwise {@code false} 99 | */ 100 | boolean isTablistEntryHidden(); 101 | 102 | /** 103 | * Respawns the character, bringing it back to the world if it was previously despawned. 104 | * 105 | * @return {@code true} if the character was successfully respawned, otherwise {@code false} 106 | */ 107 | boolean respawn(); 108 | 109 | /** 110 | * Spawns the character at the specified location. 111 | * 112 | * @param location the {@code Location} where the character will be spawned 113 | * @return {@code true} if the character was successfully spawned, otherwise {@code false} 114 | */ 115 | boolean spawn(Location location); 116 | 117 | /** 118 | * Adjusts the character's orientation to face the given entity. 119 | * 120 | * @param entity the {@code Entity} that the character should face 121 | */ 122 | void lookAt(Entity entity); 123 | 124 | /** 125 | * Adjusts the character's orientation to face the specified location. 126 | * 127 | * @param location the {@code Location} that the character should face 128 | */ 129 | void lookAt(Location location); 130 | 131 | /** 132 | * Permanently removes the character, rendering it inaccessible and removing all associated data. 133 | * After invoking this method, the character can't be respawned or interacted with. 134 | */ 135 | void remove(); 136 | 137 | /** 138 | * Sets whether the character is collidable, controlling its ability to physically interact 139 | * with other entities in the world. 140 | * 141 | * @param collidable {@code true} to make the character collidable, allowing physical interactions 142 | */ 143 | void setCollidable(boolean collidable); 144 | 145 | /** 146 | * Sets the display name for the character. 147 | * 148 | * @param displayName the {@code Component} representing the new display name to be set 149 | */ 150 | void setDisplayName(Component displayName); 151 | 152 | /** 153 | * Sets whether the character can take damage. 154 | *

155 | * This method requires the provider to support the {@link CharacterCapability#HEALTH} capability. 156 | * 157 | * @param invulnerable {@code true} if the character should be invulnerable, {@code false} otherwise 158 | */ 159 | void setInvulnerable(boolean invulnerable); 160 | 161 | /** 162 | * Sets the visibility state of the character's tablist entry. 163 | * 164 | * @param hidden {@code true} to hide the tablist entry, {@code false} to make it visible 165 | */ 166 | void setTablistEntryHidden(boolean hidden); 167 | } 168 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/character/CharacterCapability.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.character; 2 | 3 | import net.kyori.adventure.key.Key; 4 | import net.thenextlvl.service.api.capability.Capability; 5 | import org.jspecify.annotations.NullMarked; 6 | 7 | import java.lang.Character; 8 | 9 | /** 10 | * An enum representing various capabilities a {@link Character} might possess. 11 | *

12 | * Each capability indicates a specific feature or limitation 13 | * in how characters can be represented or interacted with. 14 | *

15 | * The enum constant values represent specific capabilities that can be 16 | * queried or utilized to determine the functionality of particular 17 | * implementations. 18 | *

19 | * Each capability is associated with a unique {@link Key} that acts as an 20 | * identifier for the capability. 21 | */ 22 | @NullMarked 23 | public enum CharacterCapability implements Capability { 24 | /** 25 | * Represents the capability for a character to have a health attribute. 26 | *

27 | * This capability indicates that the character can make use of features related 28 | * to health, such as taking damage or recovering health. 29 | */ 30 | HEALTH(Key.key("capability", "health")), 31 | 32 | /** 33 | * Represents the capability for a character to handle 34 | * interactions such as left, and right-click actions. 35 | */ 36 | INTERACTIONS(Key.key("capability", "interactions")), 37 | 38 | /** 39 | * Represents the capability for supporting non-player entities such as pigs or zombies. 40 | * This indicates whether the provider can handle entity types beyond player characters. 41 | */ 42 | NON_PLAYER_ENTITIES(Key.key("capability", "non_player_entities")), 43 | 44 | /** 45 | * Represents the capability to utilize actual entity objects. 46 | *

47 | * This capability indicates that the character provider supports using real, tangible entities 48 | * within the game world. 49 | * Such entities are recognized by the server and may be subject to various 50 | * physical interactions, such as collisions, gravity, or other in-game mechanics. 51 | */ 52 | ACTUAL_ENTITIES(Key.key("capability", "actual_entities")); 53 | 54 | private final Key key; 55 | 56 | CharacterCapability(Key key) { 57 | this.key = key; 58 | } 59 | 60 | @Override 61 | public Key key() { 62 | return this.key; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/character/event/CharacterDamageEvent.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.character.event; 2 | 3 | import net.thenextlvl.service.api.character.Character; 4 | import net.thenextlvl.service.api.character.CharacterCapability; 5 | import net.thenextlvl.service.api.character.CharacterController; 6 | import org.bukkit.event.Cancellable; 7 | import org.bukkit.event.entity.EntityDamageEvent; 8 | import org.jspecify.annotations.NullMarked; 9 | 10 | /** 11 | * The CharacterDamageEvent represents an event triggered when a character takes damage. 12 | *

13 | * The event allows for inspecting and modifying the damage dealt, determining the cause of 14 | * the damage, and controlling whether the event should be cancelled. 15 | *

16 | * This event will only be fired for providers that support the {@link CharacterCapability#HEALTH} capability. 17 | */ 18 | @NullMarked 19 | public class CharacterDamageEvent extends CharacterEvent implements Cancellable { 20 | private final EntityDamageEvent.DamageCause cause; 21 | private boolean cancelled; 22 | private double damage; 23 | 24 | /** 25 | * Constructs a new CharacterDamageEvent representing damage dealt to a character. 26 | * 27 | * @param controller the character controller managing the character 28 | * @param character the character that is taking damage 29 | * @param cause the cause of the damage 30 | * @param damage the amount of damage dealt to the character 31 | */ 32 | public CharacterDamageEvent(CharacterController controller, Character character, EntityDamageEvent.DamageCause cause, double damage) { 33 | super(controller, character); 34 | this.cause = cause; 35 | this.damage = damage; 36 | } 37 | 38 | /** 39 | * Retrieves the cause of the damage associated with this event. 40 | * 41 | * @return the {@link EntityDamageEvent.DamageCause} that represents the underlying cause of the damage 42 | */ 43 | public EntityDamageEvent.DamageCause getCause() { 44 | return cause; 45 | } 46 | 47 | /** 48 | * Retrieves the amount of damage associated with this event. 49 | * 50 | * @return the damage value as a double 51 | */ 52 | public double getDamage() { 53 | return damage; 54 | } 55 | 56 | /** 57 | * Sets the amount of damage for this event. 58 | * 59 | * @param damage the new damage value to be set 60 | */ 61 | public void setDamage(double damage) { 62 | this.damage = damage; 63 | } 64 | 65 | @Override 66 | public boolean isCancelled() { 67 | return cancelled; 68 | } 69 | 70 | @Override 71 | public void setCancelled(boolean cancelled) { 72 | this.cancelled = cancelled; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/character/event/CharacterEvent.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.character.event; 2 | 3 | import net.thenextlvl.service.api.character.Character; 4 | import net.thenextlvl.service.api.character.CharacterController; 5 | import org.bukkit.event.Event; 6 | import org.bukkit.event.HandlerList; 7 | import org.jspecify.annotations.NullMarked; 8 | 9 | /** 10 | * Represents a base class for events related to a character in the game. 11 | *

12 | * This class serves as a foundation for character-based events, providing 13 | * common functionality through the controller and character references. 14 | * It allows for tracking the controller, managing the character, and the target character 15 | * involved in the event. 16 | *

17 | * Subclasses can make use of these common properties while implementing specific 18 | * character-related event functionalities. 19 | */ 20 | @NullMarked 21 | public abstract class CharacterEvent extends Event { 22 | private static final HandlerList handlers = new HandlerList(); 23 | private final CharacterController controller; 24 | private final Character character; 25 | 26 | /** 27 | * Constructs a new CharacterEvent. 28 | * 29 | * @param controller the character controller responsible for managing the character 30 | * @param character the character instance involved in the event 31 | */ 32 | public CharacterEvent(CharacterController controller, Character character) { 33 | super(!character.getServer().isPrimaryThread()); 34 | this.controller = controller; 35 | this.character = character; 36 | } 37 | 38 | /** 39 | * Retrieves the character controller associated with this event. 40 | * 41 | * @return the {@code CharacterController} responsible for managing the character in this event. 42 | */ 43 | public CharacterController getController() { 44 | return controller; 45 | } 46 | 47 | /** 48 | * Retrieves the character associated with this event. 49 | * 50 | * @return the {@code Character} instance involved in this event 51 | */ 52 | public Character getCharacter() { 53 | return character; 54 | } 55 | 56 | @Override 57 | public HandlerList getHandlers() { 58 | return handlers; 59 | } 60 | 61 | public static HandlerList getHandlerList() { 62 | return handlers; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/character/event/EntityDamageCharacterEvent.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.character.event; 2 | 3 | import net.thenextlvl.service.api.character.Character; 4 | import net.thenextlvl.service.api.character.CharacterCapability; 5 | import net.thenextlvl.service.api.character.CharacterController; 6 | import org.bukkit.entity.Entity; 7 | import org.bukkit.event.entity.EntityDamageEvent; 8 | import org.jspecify.annotations.NullMarked; 9 | 10 | /** 11 | * Represents an event triggered when an entity damages a character. 12 | *

13 | * This event extends {@link CharacterDamageEvent} and provides additional details 14 | * about the attacker and whether the damage dealt is critical. 15 | * It can be used to inspect and modify the damage attributed to an entity's attack and to check the critical status. 16 | *

17 | * This event will only be fired for providers that support the {@link CharacterCapability#HEALTH} capability. 18 | */ 19 | @NullMarked 20 | public class EntityDamageCharacterEvent extends CharacterDamageEvent { 21 | private final Entity attacker; 22 | private final boolean critical; 23 | 24 | /** 25 | * Constructs an EntityDamageCharacterEvent. 26 | * 27 | * @param controller the CharacterController managing the character involved in the event 28 | * @param character the character that is being damaged 29 | * @param attacker the entity causing the damage to the character 30 | * @param cause the cause of the damage 31 | * @param damage the amount of damage dealt to the character 32 | * @param critical whether the damage dealt is a critical hit 33 | */ 34 | public EntityDamageCharacterEvent(CharacterController controller, Character character, Entity attacker, 35 | EntityDamageEvent.DamageCause cause, double damage, boolean critical) { 36 | super(controller, character, cause, damage); 37 | this.attacker = attacker; 38 | this.critical = critical; 39 | } 40 | 41 | /** 42 | * Determines whether the damage associated with this event is critical. 43 | * 44 | * @return {@code true} if the damage is a critical hit; {@code false} otherwise 45 | */ 46 | public boolean isCritical() { 47 | return critical; 48 | } 49 | 50 | /** 51 | * Retrieves the entity responsible for causing the damage in this event. 52 | * 53 | * @return the {@code Entity} that attacked the character, causing the damage 54 | */ 55 | public Entity getAttacker() { 56 | return attacker; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/character/event/PlayerInteractCharacterEvent.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.character.event; 2 | 3 | import net.thenextlvl.service.api.character.Character; 4 | import net.thenextlvl.service.api.character.CharacterCapability; 5 | import net.thenextlvl.service.api.character.CharacterController; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.event.Cancellable; 8 | import org.jspecify.annotations.NullMarked; 9 | 10 | /** 11 | * Represents an event triggered when a player interacts with a character. 12 | *

13 | * This event occurs when a player performs an interaction with a specific character, 14 | * such as a left-click or a right-click. 15 | * It encapsulates information about the player performing the interaction, 16 | * the type of interaction, and the character involved. 17 | *

18 | * This event is cancellable, meaning that handling methods may prevent 19 | * the interaction from proceeding by setting the event's cancelled state. 20 | *

21 | * This event will only be fired for providers that support the {@link CharacterCapability#INTERACTIONS} capability. 22 | */ 23 | @NullMarked 24 | public class PlayerInteractCharacterEvent extends CharacterEvent implements Cancellable { 25 | private final Player player; 26 | private final InteractionType type; 27 | private boolean cancelled; 28 | 29 | /** 30 | * Constructs an event representing a player's interaction with a character. 31 | * 32 | * @param controller the character controller managing the character involved in the event 33 | * @param character the character being interacted with 34 | * @param player the player performing the interaction 35 | * @param type the type of interaction performed by the player 36 | */ 37 | public PlayerInteractCharacterEvent(CharacterController controller, Character character, 38 | Player player, InteractionType type) { 39 | super(controller, character); 40 | this.player = player; 41 | this.type = type; 42 | } 43 | 44 | /** 45 | * Retrieves the player involved in the event. 46 | * 47 | * @return the {@code Player} instance that is performing the interaction in this event 48 | */ 49 | public Player getPlayer() { 50 | return player; 51 | } 52 | 53 | /** 54 | * Retrieves the type of interaction performed during the event. 55 | * 56 | * @return the {@code InteractionType} representing the type of interaction 57 | */ 58 | public InteractionType getType() { 59 | return type; 60 | } 61 | 62 | @Override 63 | public boolean isCancelled() { 64 | return cancelled; 65 | } 66 | 67 | @Override 68 | public void setCancelled(boolean cancelled) { 69 | this.cancelled = cancelled; 70 | } 71 | 72 | /** 73 | * Represents the type of interaction performed by a player. 74 | */ 75 | public enum InteractionType { 76 | /** 77 | * Represents a left-click interaction performed by a player. 78 | *

79 | * This type of interaction occurs when a player attacks. 80 | */ 81 | LEFT_CLICK, 82 | 83 | /** 84 | * Represents a right-click interaction performed by a player. 85 | *

86 | * This type of interaction occurs when a player interacts. 87 | */ 88 | RIGHT_CLICK, 89 | 90 | /** 91 | * Represents a shift-left-click interaction performed by a player. 92 | *

93 | * This type of interaction occurs when a player attacks while sneaking. 94 | */ 95 | SHIFT_LEFT_CLICK, 96 | 97 | /** 98 | * Represents a shift-right-click interaction performed by a player. 99 | *

100 | * This type of interaction occurs when a player interacts while sneaking. 101 | */ 102 | SHIFT_RIGHT_CLICK; 103 | 104 | /** 105 | * Checks if the interaction type is a left-click. 106 | * 107 | * @return whether this interaction represents a left-click 108 | */ 109 | public boolean isLeftClick() { 110 | return equals(LEFT_CLICK) || equals(SHIFT_LEFT_CLICK); 111 | } 112 | 113 | /** 114 | * Checks if the interaction type is a right-click. 115 | * 116 | * @return whether this interaction represents a right-click 117 | */ 118 | public boolean isRightClick() { 119 | return equals(RIGHT_CLICK) || equals(SHIFT_RIGHT_CLICK); 120 | } 121 | 122 | /** 123 | * Checks if the interaction type is a shift-click. 124 | * 125 | * @return whether this interaction represents either a shift-left-click or a shift-right-click 126 | */ 127 | public boolean isShiftClick() { 128 | return equals(SHIFT_LEFT_CLICK) || equals(SHIFT_RIGHT_CLICK); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/chat/ChatController.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.chat; 2 | 3 | import net.thenextlvl.service.api.Controller; 4 | import org.bukkit.OfflinePlayer; 5 | import org.bukkit.World; 6 | import org.jspecify.annotations.NullMarked; 7 | 8 | import java.util.Optional; 9 | import java.util.UUID; 10 | import java.util.concurrent.CompletableFuture; 11 | 12 | /** 13 | * The ChatController interface provides methods to retrieve a chat profile of a player. 14 | */ 15 | @NullMarked 16 | public interface ChatController extends Controller { 17 | /** 18 | * Loads the chat profile for the given OfflinePlayer. 19 | * 20 | * @param player The OfflinePlayer whose ChatProfile is to be retrieved. 21 | * @return a CompletableFuture that will complete with the chat profile 22 | */ 23 | default CompletableFuture loadProfile(OfflinePlayer player) { 24 | return loadProfile(player.getUniqueId()); 25 | } 26 | 27 | /** 28 | * Loads the chat profile for the given OfflinePlayer in the specified world. 29 | * 30 | * @param player The OfflinePlayer whose chat profile is to be retrieved. 31 | * @param world The world for which the chat profile is requested. 32 | * @return A CompletableFuture that will complete with the chat profile. 33 | */ 34 | default CompletableFuture loadProfile(OfflinePlayer player, World world) { 35 | return loadProfile(player.getUniqueId(), world); 36 | } 37 | 38 | /** 39 | * Loads the chat profile for the given UUID. 40 | * 41 | * @param uuid The UUID of the player whose ChatProfile is to be retrieved. 42 | * @return A CompletableFuture that will complete with the chat profile. 43 | */ 44 | CompletableFuture loadProfile(UUID uuid); 45 | 46 | /** 47 | * Loads the chat profile for the given UUID in the specified world. 48 | * 49 | * @param uuid The UUID of the player whose ChatProfile is to be retrieved. 50 | * @param world The world for which the ChatProfile is requested. 51 | * @return A CompletableFuture that will complete with the chat profile. 52 | */ 53 | CompletableFuture loadProfile(UUID uuid, World world); 54 | 55 | /** 56 | * Retrieves the chat profile for the given OfflinePlayer or try to load it. 57 | * 58 | * @param player The OfflinePlayer whose ChatProfile is to be retrieved. 59 | * @return a CompletableFuture that will complete with the chat profile 60 | */ 61 | default CompletableFuture tryGetProfile(OfflinePlayer player) { 62 | return getProfile(player) 63 | .map(CompletableFuture::completedFuture) 64 | .orElseGet(() -> loadProfile(player)); 65 | } 66 | 67 | /** 68 | * Retrieve the chat profile for the given OfflinePlayer in the specified world or try to load it. 69 | * 70 | * @param player The OfflinePlayer whose chat profile is to be retrieved. 71 | * @param world The world for which the chat profile is requested. 72 | * @return A CompletableFuture that will complete with the chat profile. 73 | */ 74 | default CompletableFuture tryGetProfile(OfflinePlayer player, World world) { 75 | return getProfile(player, world) 76 | .map(CompletableFuture::completedFuture) 77 | .orElseGet(() -> loadProfile(player, world)); 78 | } 79 | 80 | /** 81 | * Retrieve the chat profile for the given UUID or try to load it. 82 | * 83 | * @param uuid The UUID of the player whose ChatProfile is to be retrieved. 84 | * @return A CompletableFuture that will complete with the chat profile. 85 | */ 86 | default CompletableFuture tryGetProfile(UUID uuid) { 87 | return getProfile(uuid) 88 | .map(CompletableFuture::completedFuture) 89 | .orElseGet(() -> loadProfile(uuid)); 90 | } 91 | 92 | /** 93 | * Retrieve the chat profile for the given UUID in the specified world or try to load it. 94 | * 95 | * @param uuid The UUID of the player whose ChatProfile is to be retrieved. 96 | * @param world The world for which the ChatProfile is requested. 97 | * @return A CompletableFuture that will complete with the chat profile. 98 | */ 99 | default CompletableFuture tryGetProfile(UUID uuid, World world) { 100 | return getProfile(uuid, world) 101 | .map(CompletableFuture::completedFuture) 102 | .orElseGet(() -> loadProfile(uuid, world)); 103 | } 104 | 105 | /** 106 | * Retrieves the chat profile for the given OfflinePlayer. 107 | * 108 | * @param player The OfflinePlayer whose ChatProfile is to be retrieved. 109 | * @return an optional containing the chat profile, or empty. 110 | */ 111 | default Optional getProfile(OfflinePlayer player) { 112 | return getProfile(player.getUniqueId()); 113 | } 114 | 115 | /** 116 | * Retrieves the chat profile for the given OfflinePlayer in the specified world. 117 | * 118 | * @param player The OfflinePlayer whose chat profile is to be retrieved. 119 | * @param world The world for which the chat profile is requested. 120 | * @return an optional containing the chat profile, or empty. 121 | */ 122 | default Optional getProfile(OfflinePlayer player, World world) { 123 | return getProfile(player.getUniqueId(), world); 124 | } 125 | 126 | /** 127 | * Retrieves the chat profile for the given UUID. 128 | * 129 | * @param uuid The UUID of the player whose ChatProfile is to be retrieved. 130 | * @return an optional containing the chat profile, or empty. 131 | */ 132 | Optional getProfile(UUID uuid); 133 | 134 | /** 135 | * Retrieves the chat profile for the given UUID in the specified world. 136 | * 137 | * @param uuid The UUID of the player whose ChatProfile is to be retrieved. 138 | * @param world The world for which the ChatProfile is requested. 139 | * @return an optional containing the chat profile, or empty. 140 | */ 141 | Optional getProfile(UUID uuid, World world); 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/chat/ChatProfile.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.chat; 2 | 3 | import net.thenextlvl.service.api.model.Display; 4 | import net.thenextlvl.service.api.model.InfoNode; 5 | import org.jetbrains.annotations.Unmodifiable; 6 | import org.jspecify.annotations.NullMarked; 7 | 8 | import java.util.Optional; 9 | import java.util.Set; 10 | 11 | @NullMarked 12 | public interface ChatProfile extends InfoNode, Display { 13 | /** 14 | * Retrieves the name associated with the chat profile. 15 | * 16 | * @return An Optional containing the name of the chat profile. 17 | * Returns an empty Optional if no name is set. 18 | */ 19 | Optional getName(); 20 | 21 | /** 22 | * Retrieves the primary group associated with the chat profile. 23 | * 24 | * @return An Optional containing the primary group of the chat profile. 25 | * Returns an empty Optional if no primary group is set. 26 | */ 27 | Optional getPrimaryGroup(); 28 | 29 | /** 30 | * Retrieves the name of the groups associated with the chat profile. 31 | * 32 | * @return The name of the groups associated with the chat profile. 33 | */ 34 | @Unmodifiable 35 | Set getGroups(); 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/economy/Account.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.economy; 2 | 3 | import org.bukkit.World; 4 | import org.jspecify.annotations.NullMarked; 5 | 6 | import java.math.BigDecimal; 7 | import java.util.Optional; 8 | import java.util.UUID; 9 | 10 | /** 11 | * Account is an interface representing a financial account. 12 | */ 13 | @NullMarked 14 | public interface Account extends Comparable { 15 | /** 16 | * Deposits the specified amount into the account balance. 17 | * 18 | * @param amount the amount to be deposited 19 | * @return the new balance after the deposit 20 | */ 21 | BigDecimal deposit(Number amount); 22 | 23 | /** 24 | * Retrieves the balance of the account. 25 | * 26 | * @return the balance of the account 27 | */ 28 | BigDecimal getBalance(); 29 | 30 | /** 31 | * Withdraws the specified amount from the account balance. 32 | * 33 | * @param amount the amount to be withdrawn 34 | * @return the new balance after the withdrawal 35 | */ 36 | BigDecimal withdraw(Number amount); 37 | 38 | /** 39 | * Returns an optional containing the world associated with this account. 40 | * 41 | * @return an {@code Optional} containing the world associated with this account, or empty 42 | */ 43 | Optional getWorld(); 44 | 45 | /** 46 | * Returns the UUID of the owner of this account. 47 | * 48 | * @return the UUID of the owner 49 | */ 50 | UUID getOwner(); 51 | 52 | /** 53 | * Compares this account to the specified account based on their balance. 54 | * 55 | * @param account the account to be compared 56 | * @return a negative integer, zero, or a positive integer if this account is 57 | * less than, equal to, or greater than the specified account 58 | */ 59 | @Override 60 | default int compareTo(Account account) { 61 | return getBalance().compareTo(account.getBalance()); 62 | } 63 | 64 | /** 65 | * Sets the balance of the account to the specified value. 66 | * 67 | * @param balance the new balance of the account 68 | */ 69 | void setBalance(Number balance); 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.economy.bank; 2 | 3 | import net.thenextlvl.service.api.economy.Account; 4 | import org.bukkit.OfflinePlayer; 5 | import org.jetbrains.annotations.Unmodifiable; 6 | import org.jspecify.annotations.NullMarked; 7 | 8 | import java.util.Set; 9 | import java.util.UUID; 10 | 11 | /** 12 | * The Bank interface represents a financial entity that can be owned and hold members. 13 | * It extends the Account interface, providing additional functionality specific 14 | * to banking, such as depositing or withdrawing money. 15 | */ 16 | @NullMarked 17 | public interface Bank extends Account { 18 | /** 19 | * Retrieves a set of UUIDs representing the members of the bank. 20 | * 21 | * @return an unmodifiable set containing the UUIDs of the members. 22 | */ 23 | @Unmodifiable 24 | Set getMembers(); 25 | 26 | /** 27 | * Retrieves the name associated with the bank. 28 | * 29 | * @return the name of the bank. 30 | */ 31 | String getName(); 32 | 33 | /** 34 | * Adds a member to the bank. 35 | * 36 | * @param player the OfflinePlayer object representing the player to be added as a member 37 | * @return true if the player was successfully added as a member, false otherwise 38 | */ 39 | default boolean addMember(OfflinePlayer player) { 40 | return addMember(player.getUniqueId()); 41 | } 42 | 43 | /** 44 | * Adds a member to the bank. 45 | * 46 | * @param uuid the UUID of the member to be added 47 | * @return true if the member was successfully added, false otherwise 48 | */ 49 | boolean addMember(UUID uuid); 50 | 51 | /** 52 | * Checks if the specified player is a member of the bank. 53 | * 54 | * @param player the OfflinePlayer object representing the player to check for membership 55 | * @return true if the player is a member of the bank, false otherwise 56 | */ 57 | default boolean isMember(OfflinePlayer player) { 58 | return isMember(player.getUniqueId()); 59 | } 60 | 61 | /** 62 | * Checks if the specified UUID is associated with a member of the bank. 63 | * 64 | * @param uuid the UUID of the member to check for membership 65 | * @return true if the UUID corresponds to a member of the bank, false otherwise 66 | */ 67 | boolean isMember(UUID uuid); 68 | 69 | /** 70 | * Removes a member from the bank. 71 | * 72 | * @param player the OfflinePlayer object representing the player to be removed as a member 73 | * @return true if the member was successfully removed, false otherwise 74 | */ 75 | default boolean removeMember(OfflinePlayer player) { 76 | return removeMember(player.getUniqueId()); 77 | } 78 | 79 | /** 80 | * Removes a member from the bank using the specified UUID. 81 | * 82 | * @param uuid the UUID of the member to be removed 83 | * @return true if the member was successfully removed, false otherwise 84 | */ 85 | boolean removeMember(UUID uuid); 86 | 87 | /** 88 | * Sets the specified OfflinePlayer as the owner of the bank. 89 | * 90 | * @param player the OfflinePlayer object representing the player to be set as the owner 91 | * @return true if the player was successfully set as the owner, false otherwise 92 | */ 93 | default boolean setOwner(OfflinePlayer player) { 94 | return setOwner(player.getUniqueId()); 95 | } 96 | 97 | /** 98 | * Sets the owner of the bank to the specified UUID. 99 | * 100 | * @param uuid the UUID of the new owner 101 | * @return true if the owner was successfully set, false otherwise 102 | */ 103 | boolean setOwner(UUID uuid); 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/group/Group.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.group; 2 | 3 | import net.thenextlvl.service.api.model.Display; 4 | import net.thenextlvl.service.api.permission.PermissionHolder; 5 | import org.bukkit.World; 6 | import org.jspecify.annotations.NullMarked; 7 | 8 | import java.util.Optional; 9 | import java.util.OptionalInt; 10 | 11 | /** 12 | * The Group interface represents a group entity that holds permissions and display attributes such as 13 | * a display name, prefix, and suffix. It provides methods to manage these attributes as well as the 14 | * group weight and associated world. 15 | */ 16 | @NullMarked 17 | public interface Group extends PermissionHolder, Display { 18 | /** 19 | * Retrieves the world associated with the group. 20 | * 21 | * @return An Optional containing the world of the group. 22 | * Returns an empty Optional if no world is set. 23 | */ 24 | Optional getWorld(); 25 | 26 | /** 27 | * Retrieves the weight of the group. 28 | * 29 | * @return The weight of the group. 30 | */ 31 | OptionalInt getWeight(); 32 | 33 | /** 34 | * Returns the name of the object. 35 | * 36 | * @return The name of the object. 37 | */ 38 | String getName(); 39 | 40 | /** 41 | * Sets the weight of the group. 42 | * 43 | * @param weight The weight to set for the group. 44 | * @return true if the weight was successfully set, false otherwise. 45 | */ 46 | boolean setWeight(int weight); 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/group/GroupHolder.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.group; 2 | 3 | import net.thenextlvl.service.api.permission.PermissionHolder; 4 | import org.jetbrains.annotations.Unmodifiable; 5 | import org.jspecify.annotations.NullMarked; 6 | 7 | import java.util.Set; 8 | 9 | /** 10 | * The {@code GroupHolder} interface represents an entity that holds groups. 11 | * It extends the {@link PermissionHolder} interface. 12 | * It provides methods to retrieve and manipulate groups for the holder. 13 | */ 14 | @NullMarked 15 | public interface GroupHolder extends PermissionHolder { 16 | /** 17 | * Retrieves the groups associated with the permission holder. 18 | * 19 | * @return A set of Group objects representing the groups associated with the permission holder. 20 | */ 21 | @Unmodifiable 22 | Set getGroups(); 23 | 24 | /** 25 | * Retrieves the primary group of the permission holder. 26 | * The primary group represents the main group assigned to the permission holder. 27 | * 28 | * @return The primary group of the permission holder as a string. 29 | * @see GroupHolder#getGroups() 30 | * @see GroupHolder#setPrimaryGroup(Group) 31 | * @see GroupHolder#setPrimaryGroup(String) 32 | */ 33 | String getPrimaryGroup(); 34 | 35 | /** 36 | * Adds a group to the permission holder. 37 | * 38 | * @param group the group object to be added 39 | * @return true if the group was successfully added, false otherwise 40 | */ 41 | boolean addGroup(Group group); 42 | 43 | /** 44 | * Adds a group to the permission holder. 45 | * 46 | * @param name the name of the group to be added 47 | * @return true if the group was successfully added, false otherwise 48 | */ 49 | boolean addGroup(String name); 50 | 51 | /** 52 | * Checks if the permission holder is in the specified group. 53 | * 54 | * @param group the group to check 55 | * @return true if the permission holder is in the group, false otherwise 56 | */ 57 | boolean inGroup(Group group); 58 | 59 | /** 60 | * Checks if the permission holder is in the specified group. 61 | * 62 | * @param name the name of the group to check 63 | * @return true if the permission holder is in the group, false otherwise 64 | */ 65 | boolean inGroup(String name); 66 | 67 | /** 68 | * Removes a group from the permission holder. 69 | * 70 | * @param group the group to be removed 71 | * @return true if the group was successfully removed, false otherwise 72 | */ 73 | boolean removeGroup(Group group); 74 | 75 | /** 76 | * Removes a group from the permission holder. 77 | * 78 | * @param name the name of the group to be removed 79 | * @return true if the group was successfully removed, false otherwise 80 | */ 81 | boolean removeGroup(String name); 82 | 83 | /** 84 | * Sets the primary group for the permission holder. 85 | * 86 | * @param group the group to set as the primary group 87 | * @return true if the primary group is successfully set, false otherwise 88 | */ 89 | boolean setPrimaryGroup(Group group); 90 | 91 | /** 92 | * Sets the primary group for the permission holder. 93 | * 94 | * @param name the name of the group to set as the primary group 95 | * @return true if the primary group is successfully set, false otherwise 96 | */ 97 | boolean setPrimaryGroup(String name); 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/hologram/HologramCapability.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.hologram; 2 | 3 | import net.kyori.adventure.key.Key; 4 | import net.thenextlvl.service.api.capability.Capability; 5 | import org.jspecify.annotations.NullMarked; 6 | 7 | /** 8 | * An enum representing various capabilities a {@link Hologram} might possess. 9 | *

10 | * Each capability indicates a specific feature or limitation 11 | * in how holograms can be represented or interacted with. 12 | *

13 | * The enum constant values represent specific capabilities that can be 14 | * queried or utilized to determine the functionality of particular hologram 15 | * implementations. 16 | *

17 | * Each capability is associated with a unique {@link Key} that acts as an 18 | * identifier for the capability. 19 | */ 20 | @NullMarked 21 | public enum HologramCapability implements Capability { 22 | /** 23 | * Represents the capability of using block-oriented lines within a hologram. 24 | * This capability determines whether holograms can include lines that 25 | * display blocks as their visual elements. 26 | */ 27 | BLOCK_LINES(Key.key("capability", "block_lines")), 28 | 29 | /** 30 | * Represents the capability of using entity-oriented lines within a hologram. 31 | * This capability determines whether holograms can include lines that display 32 | * entities as their visual elements. 33 | */ 34 | ENTITY_LINES(Key.key("capability", "entity_lines")), 35 | 36 | /** 37 | * Represents the capability of using item-oriented lines within a hologram. 38 | * This capability determines whether holograms can include lines that display 39 | * items as their visual elements. 40 | */ 41 | ITEM_LINES(Key.key("capability", "item_lines")), 42 | 43 | /** 44 | * Represents the capability of using text-oriented lines within a hologram. 45 | * This capability determines whether holograms can include lines that display 46 | * textual content, such as plain or stylized text. 47 | *

48 | * It is generally safe to assume that every hologram will have this capability 49 | */ 50 | TEXT_LINES(Key.key("capability", "text_lines")), 51 | 52 | /** 53 | * Represents the capability of having multiple lines within a hologram. 54 | * This capability determines whether holograms can consist of more than 55 | * a single line. 56 | */ 57 | MULTILINE(Key.key("capability", "multiline")), 58 | 59 | /** 60 | * Represents the capability of text lines supporting line breaks within a hologram. 61 | * This capability determines whether text-oriented hologram lines can include 62 | * multiple lines of text as part of their visual content. 63 | *

64 | * It is mutually exclusive with the {@link #DISPLAY_BACKED} capability. 65 | */ 66 | MULTILINE_TEXT(Key.key("capability", "multiline_text")), 67 | 68 | /** 69 | * Represents the capability of holograms being backed by display entities. 70 | * This capability determines whether holograms are rendered and managed 71 | * using display entities within the underlying system. 72 | *

73 | * It is mutually exclusive with the {@link #MULTILINE_TEXT} capability. 74 | */ 75 | DISPLAY_BACKED(Key.key("capability", "display_backed")); 76 | 77 | private final Key key; 78 | 79 | HologramCapability(Key key) { 80 | this.key = key; 81 | } 82 | 83 | @Override 84 | public Key key() { 85 | return this.key; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/hologram/HologramLine.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.hologram; 2 | 3 | import net.thenextlvl.service.api.model.Positioned; 4 | import org.bukkit.Location; 5 | import org.bukkit.World; 6 | import org.jspecify.annotations.NullMarked; 7 | 8 | import java.util.Optional; 9 | 10 | /** 11 | * Represents a line within a hologram which can have varying content types and positional attributes. 12 | * 13 | * @param the type of content associated with the hologram line 14 | */ 15 | @NullMarked 16 | public interface HologramLine extends Positioned { 17 | /** 18 | * Retrieves the type of the hologram line. 19 | * 20 | * @return the type of the line, which is one of the defined constants in the {@link LineType} enum. 21 | */ 22 | LineType getType(); 23 | 24 | @Override 25 | Location getLocation(); 26 | 27 | /** 28 | * Retrieves the display associated with this hologram line. 29 | * This requires the capability {@link HologramCapability#DISPLAY_BACKED}. 30 | * 31 | * @return an {@link Optional} containing the {@link HologramDisplay} if available, otherwise empty. 32 | */ 33 | Optional getDisplay(); 34 | 35 | @Override 36 | World getWorld(); 37 | 38 | /** 39 | * Retrieves the content of the hologram line. 40 | * 41 | * @return the content of this hologram line 42 | */ 43 | T getContent(); 44 | 45 | /** 46 | * Retrieves the height of the hologram line. 47 | * 48 | * @return the height of the hologram line as a double value 49 | */ 50 | double getHeight(); 51 | 52 | /** 53 | * Retrieves the horizontal offset (X-axis) of this hologram line. 54 | * 55 | * @return the X-axis offset as a double value 56 | */ 57 | double getOffsetX(); 58 | 59 | /** 60 | * Retrieves the vertical offset (Y-axis) of this hologram line. 61 | * 62 | * @return the Y-axis offset as a double value 63 | */ 64 | double getOffsetY(); 65 | 66 | /** 67 | * Retrieves the depth offset (Z-axis) of this hologram line. 68 | * 69 | * @return the Z-axis offset as a double value 70 | */ 71 | double getOffsetZ(); 72 | 73 | /** 74 | * Sets the content of this hologram line. 75 | * 76 | * @param content the content to be set for this hologram line 77 | */ 78 | void setContent(T content); 79 | 80 | /** 81 | * Sets the height of the hologram line. 82 | * 83 | * @param height the new height to set for this hologram line 84 | */ 85 | void setHeight(double height); 86 | 87 | /** 88 | * Sets the horizontal offset (X-axis) for the hologram line. 89 | * 90 | * @param offsetX the new horizontal offset to set, represented as a double value 91 | */ 92 | void setOffsetX(double offsetX); 93 | 94 | /** 95 | * Sets the vertical offset (Y-axis) for the hologram line. 96 | * 97 | * @param offsetY the new vertical offset to set, represented as a double value 98 | */ 99 | void setOffsetY(double offsetY); 100 | 101 | /** 102 | * Sets the depth offset (Z-axis) for the hologram line. 103 | * 104 | * @param offsetZ the new depth offset to set, represented as a double value 105 | */ 106 | void setOffsetZ(double offsetZ); 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/hologram/LineType.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.hologram; 2 | 3 | /** 4 | * Enumeration representing the different types of lines that can be part of a hologram. 5 | * Each line type corresponds to a specific kind of visual content that a hologram can display. 6 | */ 7 | public enum LineType { 8 | /** 9 | * Represents a line type within a hologram that displays block-oriented content. 10 | */ 11 | BLOCK, 12 | /** 13 | * Represents a line type within a hologram that displays entity-oriented content. 14 | */ 15 | ENTITY, 16 | /** 17 | * Represents a line type within a hologram that displays item-oriented content. 18 | */ 19 | ITEM, 20 | /** 21 | * Represents a line type within a hologram that displays text-oriented content. 22 | */ 23 | TEXT 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/model/Display.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.model; 2 | 3 | import org.jetbrains.annotations.Unmodifiable; 4 | import org.jspecify.annotations.NullMarked; 5 | import org.jspecify.annotations.Nullable; 6 | 7 | import java.util.Map; 8 | import java.util.Optional; 9 | 10 | /** 11 | * The Display interface provides methods to manage display names, prefixes, and suffixes associated with an object. 12 | */ 13 | @NullMarked 14 | public interface Display { 15 | /** 16 | * Retrieves the display name associated with the object. 17 | * 18 | * @return An Optional containing the display name of the object. 19 | * Returns an empty Optional if no display name is set. 20 | */ 21 | Optional getDisplayName(); 22 | 23 | /** 24 | * Retrieves the prefix associated with the object. 25 | * 26 | * @return An Optional containing the prefix of the object. 27 | * Returns an empty Optional if no prefix is set. 28 | */ 29 | default Optional getPrefix() { 30 | return getPrefix(0); 31 | } 32 | 33 | /** 34 | * Retrieves the prefix associated with the object based on the given priority. 35 | * 36 | * @param priority The priority for the prefix. Higher values indicate higher precedence. 37 | * @return An Optional containing the prefix of the object. Returns an empty Optional if no prefix is set for the given priority. 38 | */ 39 | Optional getPrefix(int priority); 40 | 41 | /** 42 | * Retrieves the prefixes associated with the object, organized by their priorities. 43 | * 44 | * @return A map where the keys are priorities and the values are the corresponding prefixes. 45 | */ 46 | @Unmodifiable 47 | Map getPrefixes(); 48 | 49 | /** 50 | * Retrieves the suffix associated with the object. 51 | * 52 | * @return An Optional containing the suffix of the object. 53 | * Returns an empty Optional if no suffix is set. 54 | */ 55 | default Optional getSuffix() { 56 | return getSuffix(0); 57 | } 58 | 59 | /** 60 | * Retrieves the suffix associated with the object based on the given priority. 61 | * 62 | * @param priority The priority for the suffix. Higher values indicate higher precedence. 63 | * @return An Optional containing the suffix of the object. Returns an empty Optional if no suffix is set for the given priority. 64 | */ 65 | Optional getSuffix(int priority); 66 | 67 | /** 68 | * Retrieves the suffixes associated with the object, organized by their priorities. 69 | * 70 | * @return A map where the keys are priorities and the values are the corresponding suffixes. 71 | */ 72 | @Unmodifiable 73 | Map getSuffixes(); 74 | 75 | /** 76 | * Sets the display name of the object. 77 | * 78 | * @param displayName The display name to set for the object. 79 | * @return true if the display name was successfully set, false otherwise. 80 | */ 81 | boolean setDisplayName(@Nullable String displayName); 82 | 83 | /** 84 | * Sets the prefix associated with the object. 85 | * 86 | * @param prefix The prefix to set for the object. 87 | * @return true if the prefix was successfully set, false otherwise. 88 | */ 89 | default boolean setPrefix(@Nullable String prefix) { 90 | return setPrefix(prefix, 0); 91 | } 92 | 93 | /** 94 | * Sets the prefix associated with the object. 95 | * 96 | * @param prefix The prefix to set for the object. 97 | * @param priority The priority for the prefix. Higher values indicate higher precedence. 98 | * @return true if the prefix was successfully set, false otherwise. 99 | * @see Display#getPrefix() 100 | * @see Display#setPrefix(String) 101 | */ 102 | boolean setPrefix(@Nullable String prefix, int priority); 103 | 104 | /** 105 | * Sets the suffix associated with the object. 106 | * 107 | * @param suffix The suffix to set for the object. 108 | * @return true if the suffix was successfully set, false otherwise. 109 | */ 110 | default boolean setSuffix(@Nullable String suffix) { 111 | return setSuffix(suffix, 0); 112 | } 113 | 114 | /** 115 | * Sets the suffix associated with the object. 116 | * 117 | * @param suffix The suffix to set for the object. 118 | * @param priority The priority for the suffix. Higher values indicate higher precedence. 119 | * @return true if the suffix was successfully set, false otherwise. 120 | * @see Display#getSuffix() 121 | * @see Display#setSuffix(String) 122 | */ 123 | boolean setSuffix(@Nullable String suffix, int priority); 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/model/InfoNode.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.model; 2 | 3 | import org.jspecify.annotations.NullMarked; 4 | import org.jspecify.annotations.Nullable; 5 | 6 | import java.util.Optional; 7 | import java.util.function.Function; 8 | 9 | /** 10 | * The InfoNode interface provides methods to retrieve, remove, and set information node values associated with keys. 11 | * An information node is a key-value pair where both key and value are stored as string but can be retrieved as any object. 12 | * The value is retrieved as an Optional, allowing for a null-safe operation. 13 | */ 14 | @NullMarked 15 | public interface InfoNode { 16 | /** 17 | * Retrieves the information node value associated with the given key. 18 | * 19 | * @param key the key of the information node to retrieve the value for 20 | * @param mapper the function used to map the string value to the desired type 21 | * @param the type of the value to retrieve 22 | * @return an {@code Optional} containing the information node value if it exists 23 | */ 24 | Optional getInfoNode(String key, Function<@Nullable String, @Nullable T> mapper); 25 | 26 | /** 27 | * Removes the information node with the specified key from the object. 28 | * 29 | * @param key the key of the information node to be removed 30 | * @return true if the information node was successfully removed, false otherwise 31 | */ 32 | boolean removeInfoNode(String key); 33 | 34 | /** 35 | * Removes the information node with the specified key and value from the object. 36 | * 37 | * @param key the key of the information node to be removed 38 | * @param value the value of the information node to be removed 39 | * @return true if the information node was successfully removed, false otherwise 40 | */ 41 | default boolean removeInfoNode(String key, String value) { 42 | var infoNode = getInfoNode(key).orElse(null); 43 | if (!value.equals(infoNode)) return false; 44 | return removeInfoNode(key); 45 | } 46 | 47 | /** 48 | * Sets the information node value for the specified key. 49 | * 50 | * @param key the key to set the value for 51 | * @param value the value to set 52 | * @return true if the information node value was set successfully, false otherwise 53 | */ 54 | boolean setInfoNode(String key, String value); 55 | 56 | /** 57 | * Retrieves the boolean information node value associated with the given key. 58 | * 59 | * @param key the key to retrieve the value for 60 | * @return an {@code Optional} containing the information node value if it exists 61 | */ 62 | default Optional booleanInfoNode(String key) { 63 | return getInfoNode(key, Boolean::parseBoolean); 64 | } 65 | 66 | /** 67 | * Retrieves the information node value associated with the given key. 68 | * 69 | * @param key the key to retrieve the value for 70 | * @return an {@code Optional} containing the information node value if it exists 71 | */ 72 | default Optional getInfoNode(String key) { 73 | return getInfoNode(key, Function.identity()); 74 | } 75 | 76 | /** 77 | * Retrieves the information node value associated with the given key as a {@code OptionalDouble}. 78 | * 79 | * @param key the key to retrieve the value for 80 | * @return an {@code OptionalDouble} containing the information node value if it exists 81 | * @throws NumberFormatException if the value associated with the key cannot be parsed into a double 82 | */ 83 | default Optional doubleInfoNode(String key) throws NumberFormatException { 84 | return getInfoNode(key, s -> s != null ? Double.parseDouble(s) : null); 85 | } 86 | 87 | /** 88 | * Retrieves the information node value associated with the given key as an {@code OptionalInt}. 89 | * 90 | * @param key the key to retrieve the value for 91 | * @return an {@code OptionalInt} containing the information node value if it exists 92 | * @throws NumberFormatException if the value associated with the key cannot be parsed into an integer 93 | */ 94 | default Optional intInfoNode(String key) throws NumberFormatException { 95 | return getInfoNode(key, s -> s != null ? Integer.parseInt(s) : null); 96 | } 97 | 98 | /** 99 | * Checks if the given key exists in the information nodes of the object. 100 | * 101 | * @param key the key to check for existence 102 | * @return true if the key exists in the information nodes, false otherwise 103 | */ 104 | default boolean hasInfoNode(String key) { 105 | return getInfoNode(key).isPresent(); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/model/Persistable.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.model; 2 | 3 | import org.jspecify.annotations.NullMarked; 4 | 5 | /** 6 | * Represents an object that can be persisted in a storage medium. 7 | * A Persistable object provides functionalities to check its persistent state, 8 | * retrieve its name, enable or disable persistence, and persist its current state. 9 | */ 10 | @NullMarked 11 | public interface Persistable { 12 | /** 13 | * Retrieves the name of the object. 14 | * 15 | * @return the name of the object as a String. 16 | */ 17 | String getName(); 18 | 19 | /** 20 | * Determines whether the object is persistent. 21 | * 22 | * @return true if the object is persistent, false otherwise. 23 | */ 24 | boolean isPersistent(); 25 | 26 | /** 27 | * Persists the current state of the object. 28 | * 29 | * @return true if the object was successfully persisted, false otherwise. 30 | */ 31 | boolean persist(); 32 | 33 | /** 34 | * Sets the persistent state of the object. 35 | * 36 | * @param persistent a boolean value indicating whether the object should be marked as persistent. 37 | */ 38 | void setPersistent(boolean persistent); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/model/Positioned.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.model; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.Server; 5 | import org.bukkit.World; 6 | import org.jspecify.annotations.NonNull; 7 | 8 | /** 9 | * The Positioned interface represents an object with a specific position and orientation within a world. 10 | * It provides methods to retrieve coordinates, rotation, and associated world and server information. 11 | */ 12 | public interface Positioned { 13 | /** 14 | * Retrieves the location of the object. 15 | * 16 | * @return the {@link Location} of the object. 17 | */ 18 | Location getLocation(); 19 | 20 | /** 21 | * Retrieves the current server instance. 22 | * 23 | * @return the current {@link Server} instance. 24 | */ 25 | @NonNull 26 | Server getServer(); 27 | 28 | /** 29 | * Retrieves the world associated with the object. 30 | * 31 | * @return the {@link World} in which the object is located. 32 | */ 33 | World getWorld(); 34 | 35 | /** 36 | * Retrieves the X coordinate of the object's position. 37 | * 38 | * @return the X coordinate as a double. 39 | */ 40 | double getX(); 41 | 42 | /** 43 | * Retrieves the Y coordinate of the object's position. 44 | * 45 | * @return the Y coordinate as a double. 46 | */ 47 | double getY(); 48 | 49 | /** 50 | * Retrieves the Z coordinate of the object's position. 51 | * 52 | * @return the Z coordinate as a double. 53 | */ 54 | double getZ(); 55 | 56 | /** 57 | * Retrieves the pitch of the object's position. 58 | * 59 | * @return the pitch, which represents the vertical rotation of the object. 60 | */ 61 | float getPitch(); 62 | 63 | /** 64 | * Retrieves the yaw of the object's position. 65 | * 66 | * @return the yaw, representing the horizontal rotation of the object. 67 | */ 68 | float getYaw(); 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/model/Viewable.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.model; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.jetbrains.annotations.Unmodifiable; 5 | import org.jspecify.annotations.NullMarked; 6 | 7 | import java.util.Collection; 8 | import java.util.Set; 9 | 10 | /** 11 | * The Viewable interface represents an object that can be viewed or tracked by players within a specific range. 12 | * It provides methods to manage visibility, track players, and modify how the object is displayed. 13 | */ 14 | @NullMarked 15 | public interface Viewable extends Positioned { 16 | /** 17 | * Retrieves an unmodifiable set of players currently tracking this viewable object. 18 | * The returned set represents all players for whom this object is actively being tracked. 19 | * 20 | * @return an unmodifiable set of players tracking this viewable object 21 | */ 22 | @Unmodifiable 23 | Set getTrackedBy(); 24 | 25 | /** 26 | * Retrieves an unmodifiable set of players that may be able to view this object. 27 | * The returned set includes all players that meet the required conditions to view this object. 28 | * 29 | * @return an unmodifiable set of players that may view this object 30 | */ 31 | @Unmodifiable 32 | Set getViewers(); 33 | 34 | /** 35 | * Adds a player to the list of viewers of this viewable object. 36 | * 37 | * @param player The player to be added as a viewer. 38 | * @return whether the player was successfully added as a viewer. 39 | */ 40 | boolean addViewer(Player player); 41 | 42 | /** 43 | * Adds multiple players as viewers to this viewable object. 44 | * 45 | * @param players A collection of players to be added as viewers. 46 | * @return true if at least one player was successfully added as a viewer, false otherwise. 47 | */ 48 | boolean addViewers(Collection players); 49 | 50 | /** 51 | * Determines whether the specified player is currently tracking this viewable object. 52 | * 53 | * @param player The player to check for tracking status. 54 | * @return true if the specified player is actively tracking this object; false otherwise. 55 | */ 56 | boolean isTrackedBy(Player player); 57 | 58 | // whether the player meets all conditions to view this object 59 | 60 | /** 61 | * Determines whether the specified player can see this viewable object. 62 | * 63 | * @param player The player to check for visibility conditions. 64 | * @return true if the specified player meets all conditions to view this object; false otherwise. 65 | */ 66 | boolean canSee(Player player); 67 | 68 | /** 69 | * Determines if the viewable object is visible by default. 70 | * 71 | * @return true if the object is visible by default; false otherwise. 72 | */ 73 | boolean isVisibleByDefault(); 74 | 75 | /** 76 | * Removes a player from the list of viewers for this viewable object. 77 | * 78 | * @param player The player to be removed from the viewers list. 79 | * @return true if the player was successfully removed from the viewer list; false otherwise. 80 | */ 81 | boolean removeViewer(Player player); 82 | 83 | /** 84 | * Removes a collection of players from the list of viewers for this viewable object. 85 | * 86 | * @param players A collection of players to be removed as viewers. 87 | * @return true if at least one player was successfully removed from the viewer list, false otherwise. 88 | */ 89 | boolean removeViewers(Collection players); 90 | 91 | /** 92 | * Retrieves the display range for this viewable object. 93 | * 94 | * @return the display range as a double value. 95 | */ 96 | double getDisplayRange(); 97 | 98 | /** 99 | * Sets the display range for this viewable object. 100 | * 101 | * @param range The new display range to set, represented as a double value. 102 | */ 103 | void setDisplayRange(double range); 104 | 105 | /** 106 | * Sets the default visibility state for this viewable object. 107 | * 108 | * @param visible whether the object should be visible by default. 109 | */ 110 | void setVisibleByDefault(boolean visible); 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/net/thenextlvl/service/api/permission/PermissionHolder.java: -------------------------------------------------------------------------------- 1 | package net.thenextlvl.service.api.permission; 2 | 3 | import net.kyori.adventure.util.TriState; 4 | import net.thenextlvl.service.api.model.InfoNode; 5 | import org.jetbrains.annotations.Unmodifiable; 6 | import org.jspecify.annotations.NullMarked; 7 | 8 | import java.util.Map; 9 | 10 | /** 11 | * The {@code PermissionHolder} interface represents an entity that holds permissions. 12 | * It extends the {@link InfoNode} interface. 13 | * It provides methods to check, add, and remove permissions for the holder. 14 | */ 15 | @NullMarked 16 | public interface PermissionHolder extends InfoNode { 17 | /** 18 | * Retrieves the permissions held by the permission holder. 19 | * 20 | * @return a map where the keys are permission names and the values are booleans 21 | * indicating whether the permission is granted (true) or revoked (false) 22 | */ 23 | @Unmodifiable 24 | Map getPermissions(); 25 | 26 | /** 27 | * Checks if the specified permission is granted. 28 | * 29 | * @param permission the permission to check 30 | * @return a TriState value indicating the permission status (true, false, undefined) 31 | */ 32 | TriState checkPermission(String permission); 33 | 34 | /** 35 | * Adds a permission to the permission holder. 36 | * 37 | * @param permission the permission to be added 38 | * @return true if the permission was successfully added, false otherwise 39 | */ 40 | boolean addPermission(String permission); 41 | 42 | /** 43 | * Removes a permission from the permission holder. 44 | * 45 | * @param permission the permission to be removed 46 | * @return true if the permission was successfully removed, false otherwise 47 | */ 48 | boolean removePermission(String permission); 49 | 50 | /** 51 | * Sets the specified permission for the permission holder. 52 | * 53 | * @param permission the name of the permission to set 54 | * @param value a boolean indicating whether the permission is granted (true) or revoked (false) 55 | * @return true if the permission was successfully set, false otherwise 56 | */ 57 | boolean setPermission(String permission, boolean value); 58 | } 59 | --------------------------------------------------------------------------------