Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9db427023b |
No files matched your search
@@ -1,64 +1,36 @@
|
||||
# 👋 Contributing to EternalCombat
|
||||
# Contributing to EternalCombat
|
||||
|
||||
First off, thanks for taking the time to contribute! 🎉
|
||||
We love user contributions and want to make it as easy as possible for you to get involved.
|
||||
We welcome all contributions to the EternalCombat project!
|
||||
|
||||
## 🛠️ Development Setup
|
||||
### How to Contribute
|
||||
|
||||
To start contributing, you'll need to set up your environment:
|
||||
1. Fork the repository.
|
||||
2. Create a new branch for your feature or bug fix.
|
||||
3. Make your changes, and test them thoroughly.
|
||||
4. Commit your changes and push them to your fork.
|
||||
5. Submit a pull request to the main repository.
|
||||
|
||||
1. **Java 21**: We use Java 21 for development. Ensure you have a JDK 21 installed.
|
||||
2. **IDE**: We recommend [IntelliJ IDEA](https://www.jetbrains.com/idea/).
|
||||
3. **Git**: Ensure you have Git installed.
|
||||
### Code of Conduct
|
||||
|
||||
### 📥 Getting the Code
|
||||
We expect all contributors to follow our [code of conduct](CODE_OF_CONDUCT.md).
|
||||
|
||||
```bash
|
||||
# Fork the repository on GitHub first!
|
||||
# https://github.com/EternalCodeTeam/EternalCombat/fork
|
||||
git clone https://github.com/YOUR-USERNAME/EternalCombat.git
|
||||
cd EternalCombat
|
||||
```
|
||||
### Reporting Issues
|
||||
|
||||
### 🔨 Building the Project
|
||||
If you find an issue with the plugin, please report it in
|
||||
the [Issues tab](https://github.com/EternalCodeTeam/EternalCombat/issues). Please provide as much information as
|
||||
possible, including the version of Minecraft and the plugin you are using, as well as any error messagesSettings or logs.
|
||||
|
||||
Run this command in your terminal:
|
||||
### Compatibility
|
||||
|
||||
```bash
|
||||
./gradlew build
|
||||
```
|
||||
CombatLog has been tested on versions 1.17.1 - 1.19.3, but probably works on most versions of Minecraft. If you find
|
||||
compatibility issues, please report them in the Issues tab. CombatLog uses java 11+, so you need to have it installed on
|
||||
your server.
|
||||
|
||||
## 🤝 How to Contribute
|
||||
### Submitting a Pull Request
|
||||
|
||||
1. **Fork & Clone**: Fork the repo to your own account and clone it.
|
||||
2. **Branch**: Create a new branch for your feature or fix.
|
||||
```bash
|
||||
git checkout -b feat/my-awesome-feature
|
||||
```
|
||||
3. **Code**: Hack away! 💻
|
||||
4. **Test**: Run manual test by `runServer` to ensure you haven't broken anything.
|
||||
```bash
|
||||
./gradlew runServer
|
||||
```
|
||||
5. **Push**: Push your changes to your fork.
|
||||
6. **Pull Request**: Open a PR against the `master` branch.
|
||||
When submitting a pull request, please make sure to follow these guidelines:
|
||||
|
||||
## 📏 Code Style
|
||||
|
||||
Make sure that your code adheres to the plugin's existing coding style.
|
||||
|
||||
## 🐛 Reporting Bugs
|
||||
|
||||
If you find a bug, please use the **Bug Report** issue template.
|
||||
- Check if the issue already exists.
|
||||
- Provide a minimal reproduction if possible.
|
||||
- Include logs and screenshots.
|
||||
|
||||
## 💡 Feature Requests
|
||||
|
||||
Have an idea? Use the **Feature Request** issue template.
|
||||
- Explain *why* this feature is useful.
|
||||
- Describe how it should look or behave.
|
||||
|
||||
## 📄 License
|
||||
By contributing, you agree that your contributions will be licensed under the project's [License](../LICENSE).
|
||||
- Make sure that your code adheres to the plugin's existing coding style.
|
||||
- Test your changes thoroughly before submitting the pull request.
|
||||
- If your pull request is related to an existing issue, please reference the issue in your pull request.
|
||||
- Thank you for your contributions to the EternalCombat project!
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a bug report to help us improve EternalCombat <3
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Platform (please complete the following information):**
|
||||
|
||||
- Java Version: [e.g. JDK Temurin 17]
|
||||
- Server software, ex. PaperMC 1.19.3 build #1
|
||||
|
||||
**Additional notes**
|
||||
Add any other context about the problem here.
|
||||
@@ -1,84 +0,0 @@
|
||||
name: 🐛 Bug Report
|
||||
description: File a bug report to help us improve EternalCombat
|
||||
title: "[Bug]: "
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
Please ensure that you have searched the existing issues to see if this bug has already been reported.
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Bug description
|
||||
description: A clear and concise description of what the bug is.
|
||||
placeholder: I was doing X and Y happened...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Please provide a step-by-step guide to reproduce the issue.
|
||||
placeholder: |
|
||||
1. Launch the server
|
||||
2. Tag yourself using the '/combat tag' command
|
||||
3. See error
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: A clear and concise description of what you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
attributes:
|
||||
label: Screenshots/Video
|
||||
description: If applicable, add screenshots or a video to help explain your problem.
|
||||
|
||||
- type: dropdown
|
||||
id: server-software
|
||||
attributes:
|
||||
label: Server Software
|
||||
description: What server software are you using?
|
||||
options:
|
||||
- Paper
|
||||
- Purpur
|
||||
- Spigot
|
||||
- Folia
|
||||
- Other (please specify in logs)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: minecraft-version
|
||||
attributes:
|
||||
label: Minecraft Version
|
||||
description: What version of Minecraft are you running? (e.g. 1.21.11)
|
||||
placeholder: 1.21.11
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: plugin-version
|
||||
attributes:
|
||||
label: Plugin Version
|
||||
description: What version of EternalCombat are you running? (Check with /eternalcombat version)
|
||||
placeholder: v2.4.1
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Logs / Stack Trace
|
||||
description: Please paste any relevant logs or stack traces here. Use a pastebin service if the log is too long.
|
||||
render: shell
|
||||
@@ -1,8 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: 💬 Discord Community
|
||||
url: https://discord.com/invite/FQ7jmGBd6c
|
||||
about: Please ask questions and discuss ideas in our Discord server before opening a generic issue.
|
||||
- name: 📖 Documentation
|
||||
url: https://eternalcode.pl/docs/eternalcombat/introduction
|
||||
about: Read the documentation to see if your question is already answered.
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for EternalCombat <3
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -1,38 +0,0 @@
|
||||
name: 💡 Feature Request
|
||||
description: Suggest an idea for EternalCombat
|
||||
title: "[Feature]: "
|
||||
labels: ["feature"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for suggesting a new feature! Please explain your idea in detail.
|
||||
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: Is your feature request related to a problem?
|
||||
description: Please describe the problem you are trying to solve.
|
||||
placeholder: I'm always frustrated when...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: Describe the solution you'd like
|
||||
description: A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Describe alternatives you've considered
|
||||
description: A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context or screenshots about the feature request here.
|
||||
@@ -1,35 +1 @@
|
||||
---
|
||||
name: Pull Request
|
||||
about: Submit a contribution to EternalCombat
|
||||
title: 'GH-{NUMBER} <title>'
|
||||
labels: []
|
||||
assignees: []
|
||||
---
|
||||
|
||||
## 📝 Description
|
||||
<!--
|
||||
Please submit your PR using the following title format:
|
||||
feat: Description of the new feature
|
||||
fix: Description of the bug fix
|
||||
chore: Maintenance tasks
|
||||
docs: Documentation changes
|
||||
-->
|
||||
|
||||
<!-- Describe your changes clearly and concisely. Why is this change needed? What does it accomplish? -->
|
||||
|
||||
## 🎯 Type of Change
|
||||
<!-- Please check the boxes that apply to your changes -->
|
||||
- [ ] 🐛 Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] ✨ New feature (non-breaking change which adds functionality)
|
||||
- [ ] 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] 🔧 Refactoring (no functional changes, just code improvements)
|
||||
- [ ] 🎨 Style/Cosmetic (formatting, whitespace, visual changes)
|
||||
- [ ] 📚 Documentation (updates to documentation or README)
|
||||
- [ ] 🤖 CI/CD/Build (changes to workflows, gradle, etc.)
|
||||
|
||||
**Test Environment:**
|
||||
- **Minecraft Version:** <!-- e.g. 1.20.4 -->
|
||||
- **Java Version:** <!-- e.g. 21 -->
|
||||
- **Platform:** <!-- e.g. Windows/Linux/MacOS -->
|
||||
|
||||
## 📸 Screenshots (if applicable)
|
||||
**Please describe the changes made by this PR and why they need to be merged:**
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -24,10 +24,10 @@ jobs:
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v6
|
||||
uses: gradle/actions/setup-gradle@v5
|
||||
|
||||
- name: Set Variables & Build
|
||||
uses: actions/github-script@v9
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
script: |
|
||||
const isPR = context.eventName === 'pull_request';
|
||||
@@ -41,8 +41,7 @@ jobs:
|
||||
run: ./gradlew shadowJar
|
||||
|
||||
- name: Upload build artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: ${{ env.FULL_ARTIFACT_NAME }}
|
||||
path: eternalcombat-plugin/build/libs/*.jar
|
||||
archive: false
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
contents: read
|
||||
if: (github.event_name == 'push' && !contains(github.event.head_commit.message, '[ci skip]')) || github.event_name == 'release'
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 21
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v6
|
||||
uses: gradle/actions/setup-gradle@v5
|
||||
|
||||
- name: Publish to Hangar
|
||||
run: ./gradlew :eternalcombat-plugin:publishPluginPublicationToHangar
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
contents: read
|
||||
if: (github.event_name == 'push' && !contains(github.event.head_commit.message, '[ci skip]')) || github.event_name == 'release'
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 21
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v6
|
||||
uses: gradle/actions/setup-gradle@v5
|
||||
|
||||
- name: Publish to Modrinth
|
||||
run: ./gradlew :eternalcombat-plugin:modrinth
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
environment: deployment
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v5
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
.classpath
|
||||
.idea
|
||||
.gradle
|
||||
.kotlin
|
||||
.project
|
||||
.settings
|
||||
bin
|
||||
|
||||
@@ -25,11 +25,11 @@
|
||||
## EternalCombat requires PacketEvents plugin to work.
|
||||
You can download it from [here](https://modrinth.com/plugin/packetevents)
|
||||
|
||||
EternalCombat 2.0 has been tested on Minecraft versions **1.17.1 to 26.1.2**, but it should work seamlessly on most
|
||||
EternalCombat 2.0 has been tested on Minecraft versions **1.17.1 to 1.21.11**, but it should work seamlessly on most
|
||||
other versions too.
|
||||
If you run into any compatibility issues, please let us know in
|
||||
the [Issues tab](https://github.com/EternalCodeTeam/EternalCombat/issues).
|
||||
The plugin requires **Java 21 or later**, so
|
||||
The plugin requires **Java 17 or later**, so
|
||||
ensure your server is ready.
|
||||
Ready for action?
|
||||
Install EternalCombat and dive in now!
|
||||
@@ -43,22 +43,17 @@ fair, heart-pounding battles that keep players on their toes. Here’s a rundown
|
||||
- **Combat Logging**
|
||||
No more dodging fights by logging out! Once players are in combat, they’re committed until the showdown ends. Watch it
|
||||
in action:
|
||||
<img alt="Combat log anti logout feature" src="https://github.com/EternalCodeTeam/EternalCombat/blob/master/assets/combatlog.gif?raw=true" width="420">
|
||||
|
||||
- **Customize combat experience**
|
||||
Add custom effects to players in combat or death. Everything should be configurable and user-friendly:
|
||||
<img alt="Lightning strikes when players die" src="https://github.com/EternalCodeTeam/EternalCombat/blob/master/assets/lightning.gif?raw=true" width="420">
|
||||
<img alt="Flare indicates players death location" src="https://github.com/EternalCodeTeam/EternalCombat/blob/master/assets/flare.gif?raw=true" width="420">
|
||||

|
||||
|
||||
- **Spawn Protection (Configurable)**
|
||||
Stop players from fleeing to safety! Block access to spawn or safe zones during combat – tweak it to fit your server’s
|
||||
rules. See how it works:
|
||||
<img alt="Border around protected region" src="https://github.com/EternalCodeTeam/EternalCombat/blob/master/assets/border.gif?raw=true" width="420">
|
||||

|
||||
|
||||
- **Crystal PvP support**
|
||||
Engage in intense Crystal PvP battles without worrying about players logging out mid-fight! EternalCombat keeps
|
||||
everyone in the game until the last anchor hit. Check it out:
|
||||
<img alt="Crystal PvP showcase" src="https://github.com/EternalCodeTeam/EternalCombat/blob/master/assets/crystals.gif?raw=true" width="420">
|
||||
everyone in the game until the last anchor hit. Check it out:
|
||||

|
||||
|
||||
- **Fully Customizable Combat**
|
||||
Tailor the combat experience to your liking with a ton of options! From disabling elytra to setting drop rates for
|
||||
@@ -87,8 +82,6 @@ Control who can use EternalCombat’s powerful features with these permissions:
|
||||
| `eternalcombat.status` | Check a player’s combat status with `/combatlog status <player>`. |
|
||||
| `eternalcombat.tag` | Start a fight between players using `/combatlog tag <player> [player2]`. |
|
||||
| `eternalcombat.untag` | Remove a player from combat with `/combatlog untag <player>`. |
|
||||
| `eternalcombat.untagall` | Remove all players from combat with `/combatlog untagall`. |
|
||||
| `eternalcombat.stats` | View combat statistics with `/combatlog stats`. |
|
||||
| `eternalcombat.reload` | Reload the plugin with `/combatlog reload`. |
|
||||
| `eternalcombat.receiveupdates` | Receive notifications about new plugin versions on join. |
|
||||
| `eternalcombat.bypass` | When exclude `excludeAdminsFromCombat` is set to `true` users with this permission will not be tagged |
|
||||
@@ -139,7 +132,7 @@ With Maven:
|
||||
With Gradle:
|
||||
|
||||
```kts
|
||||
compileOnly("com.eternalcode:eternalcombat-api:2.5.2-SNAPSHOT")
|
||||
compileOnly("com.eternalcode:eternalcombat-api:2.5.0-SNAPSHOT")
|
||||
```
|
||||
|
||||
With Maven:
|
||||
@@ -149,7 +142,7 @@ With Maven:
|
||||
<dependency>
|
||||
<groupId>com.eternalcode</groupId>
|
||||
<artifactId>eternalcombat-api</artifactId>
|
||||
<version>2.5.2-SNAPSHOT</version>
|
||||
<version>2.5.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
|
Before Width: | Height: | Size: 5.2 MiB After Width: | Height: | Size: 5.9 MiB |
|
Before Width: | Height: | Size: 2.6 MiB After Width: | Height: | Size: 2.9 MiB |
|
Before Width: | Height: | Size: 752 KiB After Width: | Height: | Size: 787 KiB |
|
Before Width: | Height: | Size: 5.4 MiB |
|
Before Width: | Height: | Size: 2.7 MiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 113 KiB |
@@ -8,10 +8,8 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("com.gradleup.shadow:com.gradleup.shadow.gradle.plugin:9.4.2")
|
||||
implementation("com.modrinth.minotaur:com.modrinth.minotaur.gradle.plugin:2.9.0")
|
||||
implementation("io.papermc.hangar-publish-plugin:io.papermc.hangar-publish-plugin.gradle.plugin:0.1.4")
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.4.0")
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.3.0")
|
||||
implementation("com.gradleup.shadow:com.gradleup.shadow.gradle.plugin:9.3.1")
|
||||
implementation("net.minecrell:plugin-yml:0.6.0")
|
||||
implementation("xyz.jpenilla:run-task:3.0.2")
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.provider.Provider
|
||||
|
||||
internal val Project.isRelease: Boolean
|
||||
get() = providers.environmentVariable("GITHUB_EVENT_NAME").orNull == "release"
|
||||
|
||||
internal val Project.releaseChannel: String
|
||||
get() = if (isRelease) "Release" else "Snapshot"
|
||||
|
||||
internal val Project.changelogText: Provider<String>
|
||||
get() = providers.environmentVariable("CHANGELOG")
|
||||
.orElse(providers.exec { commandLine("git", "log", "-1", "--format=%B") }.standardOutput.asText)
|
||||
|
||||
internal val Project.paperVersions: List<String>
|
||||
get() = property("paperVersion").toString()
|
||||
.split(",")
|
||||
.map { paperVersion -> paperVersion.trim() }
|
||||
|
||||
internal fun Project.configureSnapshotVersionFromGit() {
|
||||
val isGithubWorkflow = providers.environmentVariable("GITHUB_RUN_NUMBER").isPresent
|
||||
|
||||
if (!isGithubWorkflow || isRelease) {
|
||||
return
|
||||
}
|
||||
|
||||
if ("-SNAPSHOT+" in version.toString()) {
|
||||
return
|
||||
}
|
||||
|
||||
val describeParts = providers.exec { commandLine("git", "describe", "--tags", "--long") }
|
||||
.standardOutput.asText.get()
|
||||
.trim()
|
||||
.split("-")
|
||||
|
||||
val offset = if (describeParts.size >= 3) describeParts[describeParts.size - 2] else "0"
|
||||
val baseVersion = version.toString().substringBefore("-SNAPSHOT")
|
||||
|
||||
version = "$baseVersion-SNAPSHOT+$offset"
|
||||
}
|
||||
@@ -1,37 +1,37 @@
|
||||
object Versions {
|
||||
|
||||
// Keep this version for best compatibility.
|
||||
const val PAPER_API = "1.19.3-R0.1-SNAPSHOT"
|
||||
const val SPIGOT_API = "1.17.1-R0.1-SNAPSHOT"
|
||||
|
||||
const val JUNIT_JUPITER_API = "6.1.0"
|
||||
const val JUNIT_JUPITER_PARAMS = "6.1.0"
|
||||
const val JUNIT_JUPITER_ENGINE = "6.1.0"
|
||||
const val JUNIT_JUPITER_API = "6.0.2"
|
||||
const val JUNIT_JUPITER_PARAMS = "6.0.2"
|
||||
const val JUNIT_JUPITER_ENGINE = "6.0.2"
|
||||
|
||||
const val JETBRAINS_ANNOTATIONS = "26.1.0"
|
||||
const val JETBRAINS_ANNOTATIONS = "26.0.2-1"
|
||||
|
||||
const val ETERNALCODE_COMMONS = "1.4.1"
|
||||
const val MULTIFICATION = "1.2.5-SNAPSHOT"
|
||||
const val PACKETS_EVENTS = "2.12.2"
|
||||
const val ETERNALCODE_COMMONS = "1.3.2"
|
||||
const val MULTIFICATION = "1.2.4"
|
||||
const val PACKETS_EVENTS = "2.11.1"
|
||||
|
||||
const val LITE_COMMANDS = "3.11.0"
|
||||
const val ADVENTURE_PLATFORM_BUKKIT = "4.4.1"
|
||||
const val ADVENTURE_API = "4.26.1"
|
||||
|
||||
const val LITE_COMMANDS = "3.10.9"
|
||||
const val OKAERI_CONFIGS_SERDES_COMMONS = "5.0.13"
|
||||
const val OKAERI_CONFIGS_SERDES_BUKKIT = "5.0.13"
|
||||
|
||||
const val XSERIES = "13.8.0"
|
||||
const val CAFFEINE = "3.2.3"
|
||||
|
||||
const val CAFFEINE = "3.2.4"
|
||||
const val B_STATS_BUKKIT = "3.1.0"
|
||||
const val WORLD_GUARD_BUKKIT = "7.0.15"
|
||||
|
||||
const val B_STATS_BUKKIT = "3.2.1"
|
||||
const val WORLD_GUARD_BUKKIT = "7.0.17"
|
||||
const val PLACEHOLDER_API = "2.11.7"
|
||||
const val LANDS_API = "7.23.1"
|
||||
const val PAPERLIB = "1.0.8"
|
||||
|
||||
const val PLACEHOLDER_API = "2.12.2"
|
||||
const val LANDS_API = "7.25.4"
|
||||
|
||||
//runServer task
|
||||
const val FAST_ASYNC_WORLD_EDIT = "2.15.2"
|
||||
const val PACKETEVENTS = "2.12.2+spigot"
|
||||
const val WORLDGUARD = "7.0.17"
|
||||
const val LUCKPERMS = "v5.5.53-bukkit"
|
||||
const val WORLDEDIT = "3ISh7ADm" //cannot use numeric version bc of duplicated version on modrinth
|
||||
const val PACKETEVENTS = "2.11.1"
|
||||
const val WORLDGUARD = "7.0.15-beta-01"
|
||||
const val LUCKPERMS = "5.5.17"
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ plugins {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation("io.papermc.paper:paper-api:${Versions.PAPER_API}")
|
||||
testImplementation("org.spigotmc:spigot-api:${Versions.SPIGOT_API}")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:${Versions.JUNIT_JUPITER_API}")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-params:${Versions.JUNIT_JUPITER_PARAMS}")
|
||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Versions.JUNIT_JUPITER_ENGINE}")
|
||||
|
||||
@@ -3,7 +3,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = "com.eternalcode"
|
||||
version = "2.5.2-SNAPSHOT"
|
||||
version = "2.5.0-SNAPSHOT"
|
||||
|
||||
tasks.compileJava {
|
||||
options.compilerArgs = listOf("-Xlint:deprecation", "-parameters")
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import io.papermc.hangarpublishplugin.model.Platforms
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
|
||||
plugins {
|
||||
id("io.papermc.hangar-publish-plugin")
|
||||
}
|
||||
|
||||
configureSnapshotVersionFromGit()
|
||||
|
||||
pluginManager.withPlugin("com.gradleup.shadow") {
|
||||
val shadowJarTask = tasks.named<ShadowJar>("shadowJar")
|
||||
|
||||
hangarPublish {
|
||||
publications.register("plugin") {
|
||||
version.set(project.version.toString())
|
||||
channel.set(project.releaseChannel)
|
||||
changelog.set(project.changelogText)
|
||||
id.set("eternalcombat")
|
||||
apiKey.set(providers.environmentVariable("HANGAR_API_TOKEN"))
|
||||
platforms {
|
||||
register(Platforms.PAPER) {
|
||||
jar.set(shadowJarTask.flatMap { shadowJar -> shadowJar.archiveFile })
|
||||
platformVersions.set(project.paperVersions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
|
||||
plugins {
|
||||
id("com.modrinth.minotaur")
|
||||
}
|
||||
|
||||
configureSnapshotVersionFromGit()
|
||||
|
||||
pluginManager.withPlugin("com.gradleup.shadow") {
|
||||
val shadowJarTask = tasks.named<ShadowJar>("shadowJar")
|
||||
|
||||
modrinth {
|
||||
token.set(providers.environmentVariable("MODRINTH_TOKEN"))
|
||||
projectId.set("eternalcombat")
|
||||
versionNumber.set(project.version.toString())
|
||||
versionType.set(if (project.isRelease) "release" else "beta")
|
||||
uploadFile.set(shadowJarTask)
|
||||
gameVersions.addAll(project.paperVersions)
|
||||
loaders.addAll(listOf("paper", "folia", "purpur"))
|
||||
changelog.set(project.changelogText)
|
||||
syncBodyFrom.set(rootProject.file("README.md").readText())
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = "com.eternalcode"
|
||||
version = "2.5.2-SNAPSHOT"
|
||||
version = "2.5.0-SNAPSHOT"
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
|
||||
@@ -3,10 +3,10 @@ plugins {
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
maven("https://repo.eternalcode.pl/releases")
|
||||
maven("https://repo.eternalcode.pl/snapshots")
|
||||
|
||||
mavenCentral()
|
||||
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
|
||||
maven("https://repo.papermc.io/repository/maven-public/")
|
||||
maven("https://storehouse.okaeri.eu/repository/maven-public/")
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import org.gradle.jvm.toolchain.JavaLanguageVersion
|
||||
import org.gradle.jvm.toolchain.JavaToolchainService
|
||||
|
||||
plugins {
|
||||
id("xyz.jpenilla.run-paper")
|
||||
}
|
||||
|
||||
tasks {
|
||||
val javaToolchains = extensions.getByType<JavaToolchainService>()
|
||||
|
||||
runServer {
|
||||
javaLauncher.set(javaToolchains.launcherFor {
|
||||
languageVersion.set(JavaLanguageVersion.of(25))
|
||||
})
|
||||
|
||||
minecraftVersion("26.1.2")
|
||||
downloadPlugins.modrinth("FastAsyncWorldEdit", Versions.FAST_ASYNC_WORLD_EDIT)
|
||||
downloadPlugins.modrinth("PacketEvents", Versions.PACKETEVENTS)
|
||||
downloadPlugins.modrinth("WorldGuard", Versions.WORLDGUARD)
|
||||
downloadPlugins.modrinth("LuckPerms", Versions.LUCKPERMS)
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ plugins {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Paper api
|
||||
compileOnlyApi("io.papermc.paper:paper-api:${Versions.PAPER_API}")
|
||||
// Spigot api
|
||||
compileOnlyApi("org.spigotmc:spigot-api:${Versions.SPIGOT_API}")
|
||||
api("org.jetbrains:annotations:${Versions.JETBRAINS_ANNOTATIONS}")
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import com.eternalcode.combat.fight.drop.DropKeepInventoryService;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.fight.drop.DropService;
|
||||
import com.eternalcode.combat.fight.effect.FightEffectService;
|
||||
import com.eternalcode.combat.fight.pearl.PearlService;
|
||||
import com.eternalcode.combat.fight.pearl.FightPearlService;
|
||||
import com.eternalcode.combat.region.RegionProvider;
|
||||
import com.eternalcode.combat.fight.tagout.FightTagOutService;
|
||||
|
||||
@@ -14,7 +14,7 @@ public interface EternalCombatApi {
|
||||
|
||||
RegionProvider getRegionProvider();
|
||||
|
||||
PearlService getFightPearlService();
|
||||
FightPearlService getFightPearlService();
|
||||
|
||||
FightTagOutService getFightTagOutService();
|
||||
|
||||
|
||||
@@ -23,17 +23,6 @@ public enum CauseOfTag {
|
||||
*/
|
||||
CRYSTAL,
|
||||
|
||||
/**
|
||||
* Trident usage extending combat tag.
|
||||
*/
|
||||
TRIDENT,
|
||||
|
||||
/**
|
||||
* Ender pearl usage extending combat tag.
|
||||
*/
|
||||
ENDER_PEARL,
|
||||
|
||||
|
||||
/**
|
||||
* A custom cause, typically defined by external plugins or systems, applied the combat tag.
|
||||
*/
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package com.eternalcode.combat.fight.pearl;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public interface PearlService {
|
||||
public interface FightPearlService {
|
||||
|
||||
boolean shouldCancelEvent(UUID playerId);
|
||||
Instant getDelay(UUID uuid);
|
||||
|
||||
Duration getRemainingDelay(UUID uuid);
|
||||
|
||||
boolean hasDelay(UUID uuid);
|
||||
|
||||
void handleDelay(Player uuid);
|
||||
void markDelay(UUID uuid);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.eternalcode.combat.fight.trident;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface TridentService {
|
||||
|
||||
/**
|
||||
* returns remaining delay for the player to use trident again
|
||||
* @param uuid unique id of the player
|
||||
* @return remaining duration left to use trident again by the player or zero
|
||||
*/
|
||||
Duration getRemainingDelay(UUID uuid);
|
||||
|
||||
/**
|
||||
* checks if player still has delay left to use trident
|
||||
* @param uuid unique id of the player
|
||||
* @return true if user still has cooldown left to use trident
|
||||
*/
|
||||
boolean hasDelay(UUID uuid);
|
||||
|
||||
/**
|
||||
* marks start of the delay for the user
|
||||
* @param uuid unique id of the player
|
||||
*/
|
||||
void markDelay(UUID uuid);
|
||||
|
||||
|
||||
void removeDelay(UUID playerId);
|
||||
|
||||
}
|
||||
@@ -1,16 +1,85 @@
|
||||
|
||||
import net.minecrell.pluginyml.paper.PaperPluginDescription
|
||||
import net.minecrell.pluginyml.bukkit.BukkitPluginDescription
|
||||
import io.papermc.hangarpublishplugin.model.Platforms
|
||||
|
||||
plugins {
|
||||
`eternalcombat-java`
|
||||
`eternalcombat-repositories`
|
||||
`eternalcombat-publish-hangar`
|
||||
`eternalcombat-publish-modrinth`
|
||||
`eternalcombat-runserver`
|
||||
|
||||
id("de.eldoria.plugin-yml.paper") version "0.9.0"
|
||||
id("net.minecrell.plugin-yml.bukkit")
|
||||
id("com.gradleup.shadow")
|
||||
id("xyz.jpenilla.run-paper")
|
||||
id("com.modrinth.minotaur") version "2.8.10"
|
||||
id("io.papermc.hangar-publish-plugin") version "0.1.4"
|
||||
}
|
||||
|
||||
val buildNumber = providers.environmentVariable("GITHUB_RUN_NUMBER").orNull
|
||||
val isRelease = providers.environmentVariable("GITHUB_EVENT_NAME").orNull == "release"
|
||||
|
||||
if (buildNumber != null && !isRelease) {
|
||||
val offset = try {
|
||||
val description = providers.exec {
|
||||
commandLine("git", "describe", "--tags", "--long")
|
||||
}.standardOutput.asText.get().trim()
|
||||
val parts = description.split("-")
|
||||
if (parts.size >= 3) parts[parts.size - 2] else "0"
|
||||
} catch (e: Exception) {
|
||||
try {
|
||||
providers.exec {
|
||||
commandLine("git", "rev-list", "--count", "HEAD")
|
||||
}.standardOutput.asText.get().trim()
|
||||
} catch (e: Exception) {
|
||||
"0"
|
||||
}
|
||||
}
|
||||
|
||||
val baseVersion = project.version.toString().replace("-SNAPSHOT", "")
|
||||
version = "$baseVersion-SNAPSHOT+$offset"
|
||||
}
|
||||
|
||||
val changelogText = providers.environmentVariable("CHANGELOG").orElse(providers.exec {
|
||||
commandLine("git", "log", "-1", "--format=%B")
|
||||
}.standardOutput.asText)
|
||||
|
||||
logger.lifecycle("Building version: $version")
|
||||
|
||||
val paperVersions = (property("paperVersion") as String)
|
||||
.split(",")
|
||||
.map { it.trim() }
|
||||
|
||||
val hangarToken = providers.environmentVariable("HANGAR_API_TOKEN")
|
||||
.orElse(providers.gradleProperty("hangarToken"))
|
||||
|
||||
val projectVersion = project.version.toString()
|
||||
val releaseChannel = if (isRelease) "Release" else "Snapshot"
|
||||
val shadowJarTask = tasks.shadowJar
|
||||
|
||||
modrinth {
|
||||
token.set(providers.environmentVariable("MODRINTH_TOKEN"))
|
||||
projectId.set("eternalcombat")
|
||||
versionNumber.set(projectVersion)
|
||||
versionType.set(if (isRelease) "release" else "beta")
|
||||
uploadFile.set(shadowJarTask)
|
||||
gameVersions.addAll(paperVersions)
|
||||
loaders.addAll(listOf("paper", "spigot", "folia", "purpur"))
|
||||
changelog.set(changelogText)
|
||||
syncBodyFrom.set(rootProject.file("README.md").readText())
|
||||
}
|
||||
|
||||
|
||||
hangarPublish {
|
||||
publications.register("plugin") {
|
||||
version.set(projectVersion)
|
||||
channel.set(releaseChannel)
|
||||
changelog.set(changelogText)
|
||||
id.set("eternalcombat")
|
||||
apiKey.set(hangarToken)
|
||||
platforms {
|
||||
register(Platforms.PAPER) {
|
||||
jar.set(shadowJarTask.flatMap { it.archiveFile })
|
||||
platformVersions.set(paperVersions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
@@ -27,8 +96,14 @@ configurations.all {
|
||||
dependencies {
|
||||
implementation(project(":eternalcombat-api"))
|
||||
|
||||
// Paper
|
||||
compileOnly("io.papermc.paper:paper-api:${Versions.PAPER_API}")
|
||||
// kyori
|
||||
implementation("net.kyori:adventure-platform-bukkit:${Versions.ADVENTURE_PLATFORM_BUKKIT}")
|
||||
implementation("net.kyori:adventure-text-minimessage:${Versions.ADVENTURE_API}")
|
||||
implementation("net.kyori:adventure-api") {
|
||||
version {
|
||||
strictly(Versions.ADVENTURE_API)
|
||||
}
|
||||
}
|
||||
|
||||
// litecommands
|
||||
implementation("dev.rollczi:litecommands-bukkit:${Versions.LITE_COMMANDS}")
|
||||
@@ -38,9 +113,6 @@ dependencies {
|
||||
implementation("eu.okaeri:okaeri-configs-serdes-commons:${Versions.OKAERI_CONFIGS_SERDES_COMMONS}")
|
||||
implementation("eu.okaeri:okaeri-configs-serdes-bukkit:${Versions.OKAERI_CONFIGS_SERDES_BUKKIT}")
|
||||
|
||||
// XSeries
|
||||
implementation("com.github.cryptomorin:XSeries:${Versions.XSERIES}")
|
||||
|
||||
// bstats
|
||||
implementation("org.bstats:bstats-bukkit:${Versions.B_STATS_BUKKIT}")
|
||||
|
||||
@@ -58,54 +130,43 @@ dependencies {
|
||||
|
||||
// PlaceholderAPI
|
||||
compileOnly("me.clip:placeholderapi:${Versions.PLACEHOLDER_API}")
|
||||
|
||||
|
||||
// Lands
|
||||
compileOnly("com.github.angeschossen:LandsAPI:${Versions.LANDS_API}")
|
||||
|
||||
// Multification
|
||||
implementation("com.eternalcode:multification-paper:${Versions.MULTIFICATION}")
|
||||
implementation("com.eternalcode:multification-bukkit:${Versions.MULTIFICATION}")
|
||||
implementation("com.eternalcode:multification-okaeri:${Versions.MULTIFICATION}")
|
||||
compileOnly("com.github.retrooper:packetevents-spigot:${Versions.PACKETS_EVENTS}")
|
||||
implementation("io.papermc:paperlib:${Versions.PAPERLIB}")
|
||||
}
|
||||
|
||||
paper {
|
||||
bukkit {
|
||||
main = "com.eternalcode.combat.CombatPlugin"
|
||||
authors = listOf("EternalCodeTeam")
|
||||
apiVersion = "1.19"
|
||||
author = "EternalCodeTeam"
|
||||
apiVersion = "1.13"
|
||||
prefix = "EternalCombat"
|
||||
name = "EternalCombat"
|
||||
generateLibrariesJson = true
|
||||
load = BukkitPluginDescription.PluginLoadOrder.POSTWORLD
|
||||
softDepend = listOf(
|
||||
"Lands",
|
||||
"WorldGuard"
|
||||
)
|
||||
depend = listOf(
|
||||
"packetevents",
|
||||
)
|
||||
version = "${project.version}"
|
||||
|
||||
foliaSupported = true
|
||||
|
||||
serverDependencies {
|
||||
register("packetevents") {
|
||||
required = true
|
||||
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
|
||||
}
|
||||
|
||||
register("Lands") {
|
||||
required = false
|
||||
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
|
||||
}
|
||||
|
||||
register("WorldGuard") {
|
||||
required = false
|
||||
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
|
||||
}
|
||||
|
||||
register("PlaceholderAPI") {
|
||||
required = false
|
||||
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
named("generatePaperPluginDescription") {
|
||||
notCompatibleWithConfigurationCache("The plugin-yml paper generator reads Task.project during execution.")
|
||||
runServer {
|
||||
minecraftVersion("1.21.10")
|
||||
downloadPlugins.modrinth("WorldEdit", Versions.WORLDEDIT)
|
||||
downloadPlugins.modrinth("PacketEvents", "${Versions.PACKETEVENTS}+spigot")
|
||||
downloadPlugins.modrinth("WorldGuard", Versions.WORLDGUARD)
|
||||
downloadPlugins.modrinth("LuckPerms", "v${Versions.LUCKPERMS}-bukkit")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,18 +176,17 @@ tasks.shadowJar {
|
||||
exclude(
|
||||
"org/intellij/lang/annotations/**",
|
||||
"org/jetbrains/annotations/**",
|
||||
"net/kyori/**",
|
||||
"META-INF/**",
|
||||
"kotlin/**",
|
||||
"javax/**",
|
||||
"org/checkerframework/**",
|
||||
"com/google/errorprone/**",
|
||||
"com/google/gson/**"
|
||||
)
|
||||
|
||||
val prefix = "com.eternalcode.combat.libs"
|
||||
listOf(
|
||||
"eu.okaeri",
|
||||
"net.kyori",
|
||||
"org.bstats",
|
||||
"org.yaml",
|
||||
"dev.rollczi.litecommands",
|
||||
@@ -135,8 +195,7 @@ tasks.shadowJar {
|
||||
"com.github.benmanes.caffeine",
|
||||
"com.eternalcode.commons",
|
||||
"com.eternalcode.multification",
|
||||
"com.github.cryptomorin",
|
||||
"com.cryptomorin",
|
||||
"io.papermc.lib"
|
||||
).forEach { pack ->
|
||||
relocate(pack, "$prefix.$pack")
|
||||
}
|
||||
|
||||
@@ -1,62 +1,52 @@
|
||||
package com.eternalcode.combat;
|
||||
|
||||
import com.eternalcode.combat.border.BorderTriggerController;
|
||||
import com.eternalcode.combat.border.BorderService;
|
||||
import com.eternalcode.combat.border.BorderServiceImpl;
|
||||
import com.eternalcode.combat.border.BorderTriggerController;
|
||||
import com.eternalcode.combat.border.animation.block.BorderBlockController;
|
||||
import com.eternalcode.combat.border.animation.particle.ParticleController;
|
||||
import com.eternalcode.combat.bridge.BridgeService;
|
||||
import com.eternalcode.combat.config.ConfigService;
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.crystalpvp.EndCrystalListener;
|
||||
import com.eternalcode.combat.crystalpvp.RespawnAnchorListener;
|
||||
import com.eternalcode.combat.event.EventManager;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.fight.FightManagerImpl;
|
||||
import com.eternalcode.combat.fight.FightTagCommand;
|
||||
import com.eternalcode.combat.fight.FightTask;
|
||||
import com.eternalcode.combat.fight.blocker.CommandsBlocker;
|
||||
import com.eternalcode.combat.fight.blocker.ElytraBlocker;
|
||||
import com.eternalcode.combat.fight.blocker.ElytraEquipBlocker;
|
||||
import com.eternalcode.combat.fight.blocker.FlyingBlocker;
|
||||
import com.eternalcode.combat.crystalpvp.EndCrystalListener;
|
||||
import com.eternalcode.combat.fight.controller.FightBypassAdminController;
|
||||
import com.eternalcode.combat.fight.controller.FightBypassCreativeController;
|
||||
import com.eternalcode.combat.fight.controller.FightBypassPermissionController;
|
||||
import com.eternalcode.combat.fight.blocker.InventoryContainersBlocker;
|
||||
import com.eternalcode.combat.fight.controller.FightMessageController;
|
||||
import com.eternalcode.combat.fight.controller.FightTagController;
|
||||
import com.eternalcode.combat.fight.controller.FightUnTagController;
|
||||
import com.eternalcode.combat.fight.death.DeathFlareController;
|
||||
import com.eternalcode.combat.fight.death.DeathLightningController;
|
||||
import com.eternalcode.combat.fight.drop.DropController;
|
||||
import com.eternalcode.combat.fight.drop.DropKeepInventoryService;
|
||||
import com.eternalcode.combat.fight.drop.DropKeepInventoryServiceImpl;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.fight.drop.DropService;
|
||||
import com.eternalcode.combat.fight.effect.FightEffectService;
|
||||
import com.eternalcode.combat.fight.firework.FireworkController;
|
||||
import com.eternalcode.combat.fight.knockback.KnockbackService;
|
||||
import com.eternalcode.combat.fight.tagout.FightTagOutService;
|
||||
import com.eternalcode.combat.fight.pearl.FightPearlService;
|
||||
import com.eternalcode.combat.handler.InvalidUsageHandlerImpl;
|
||||
import com.eternalcode.combat.handler.MissingPermissionHandlerImpl;
|
||||
import com.eternalcode.combat.config.ConfigService;
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.drop.DropController;
|
||||
import com.eternalcode.combat.fight.drop.DropKeepInventoryServiceImpl;
|
||||
import com.eternalcode.combat.fight.drop.DropServiceImpl;
|
||||
import com.eternalcode.combat.fight.drop.impl.PercentDropModifier;
|
||||
import com.eternalcode.combat.fight.drop.impl.PlayersHealthDropModifier;
|
||||
import com.eternalcode.combat.fight.blocker.PlaceBlockBlocker;
|
||||
import com.eternalcode.combat.fight.FightTagCommand;
|
||||
import com.eternalcode.combat.fight.controller.FightActionBlockerController;
|
||||
import com.eternalcode.combat.fight.controller.FightMessageController;
|
||||
import com.eternalcode.combat.fight.controller.FightTagController;
|
||||
import com.eternalcode.combat.fight.controller.FightUnTagController;
|
||||
import com.eternalcode.combat.fight.effect.FightEffectController;
|
||||
import com.eternalcode.combat.fight.effect.FightEffectService;
|
||||
import com.eternalcode.combat.event.EventManager;
|
||||
import com.eternalcode.combat.fight.FightManagerImpl;
|
||||
import com.eternalcode.combat.fight.FightTask;
|
||||
import com.eternalcode.combat.fight.effect.FightEffectServiceImpl;
|
||||
import com.eternalcode.combat.fight.firework.FireworkController;
|
||||
import com.eternalcode.combat.fight.knockback.KnockbackRegionController;
|
||||
import com.eternalcode.combat.fight.knockback.KnockbackService;
|
||||
import com.eternalcode.combat.fight.logout.LogoutController;
|
||||
import com.eternalcode.combat.fight.logout.LogoutService;
|
||||
import com.eternalcode.combat.fight.pearl.PearlController;
|
||||
import com.eternalcode.combat.fight.pearl.PearlService;
|
||||
import com.eternalcode.combat.fight.pearl.PearlServiceImpl;
|
||||
import com.eternalcode.combat.fight.tagout.FightTagOutCommand;
|
||||
import com.eternalcode.combat.fight.pearl.FightPearlController;
|
||||
import com.eternalcode.combat.fight.pearl.FightPearlServiceImpl;
|
||||
import com.eternalcode.combat.fight.tagout.FightTagOutController;
|
||||
import com.eternalcode.combat.fight.tagout.FightTagOutService;
|
||||
import com.eternalcode.combat.fight.tagout.FightTagOutServiceImpl;
|
||||
import com.eternalcode.combat.fight.trident.TridentController;
|
||||
import com.eternalcode.combat.fight.trident.TridentService;
|
||||
import com.eternalcode.combat.fight.trident.TridentServiceImpl;
|
||||
import com.eternalcode.combat.handler.InvalidUsageHandlerImpl;
|
||||
import com.eternalcode.combat.handler.MissingPermissionHandlerImpl;
|
||||
import com.eternalcode.combat.fight.tagout.FightTagOutCommand;
|
||||
import com.eternalcode.combat.notification.NoticeService;
|
||||
import com.eternalcode.combat.fight.knockback.KnockbackRegionController;
|
||||
import com.eternalcode.combat.region.RegionProvider;
|
||||
import com.eternalcode.combat.updater.UpdaterNotificationController;
|
||||
import com.eternalcode.combat.updater.UpdaterService;
|
||||
@@ -70,6 +60,8 @@ import dev.rollczi.litecommands.bukkit.LiteBukkitFactory;
|
||||
import dev.rollczi.litecommands.bukkit.LiteBukkitMessages;
|
||||
import dev.rollczi.litecommands.folia.FoliaExtension;
|
||||
import java.time.Duration;
|
||||
import net.kyori.adventure.platform.AudienceProvider;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bukkit.Server;
|
||||
@@ -88,8 +80,7 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
|
||||
private static final int BSTATS_METRICS_ID = 17803;
|
||||
|
||||
private FightManager fightManager;
|
||||
private PearlService pearlService;
|
||||
private TridentService tridentService;
|
||||
private FightPearlService fightPearlService;
|
||||
private FightTagOutService fightTagOutService;
|
||||
private FightEffectService fightEffectService;
|
||||
|
||||
@@ -98,8 +89,8 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
|
||||
|
||||
private RegionProvider regionProvider;
|
||||
|
||||
private AudienceProvider audienceProvider;
|
||||
private LiteCommands<CommandSender> liteCommands;
|
||||
private boolean apiInitialized;
|
||||
|
||||
|
||||
@Override
|
||||
@@ -117,8 +108,7 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
|
||||
MinecraftScheduler scheduler = CombatSchedulerAdapter.getAdaptiveScheduler(this);
|
||||
|
||||
this.fightManager = new FightManagerImpl(eventManager);
|
||||
this.pearlService = new PearlServiceImpl(this.fightManager, pluginConfig, scheduler);
|
||||
this.tridentService = new TridentServiceImpl(pluginConfig);
|
||||
this.fightPearlService = new FightPearlServiceImpl(pluginConfig.pearl);
|
||||
this.fightTagOutService = new FightTagOutServiceImpl();
|
||||
this.fightEffectService = new FightEffectServiceImpl();
|
||||
|
||||
@@ -129,12 +119,13 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
|
||||
|
||||
UpdaterService updaterService = new UpdaterService(this.getDescription());
|
||||
|
||||
this.audienceProvider = BukkitAudiences.create(this);
|
||||
MiniMessage miniMessage = MiniMessage.builder()
|
||||
.postProcessor(new AdventureLegacyColorPostProcessor())
|
||||
.preProcessor(new AdventureLegacyColorPreProcessor())
|
||||
.build();
|
||||
|
||||
NoticeService noticeService = new NoticeService(pluginConfig, miniMessage);
|
||||
NoticeService noticeService = new NoticeService(this.audienceProvider, pluginConfig, miniMessage);
|
||||
|
||||
BridgeService bridgeService = new BridgeService(
|
||||
pluginConfig,
|
||||
@@ -187,12 +178,9 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
|
||||
new FightBypassAdminController(server, pluginConfig),
|
||||
new FightBypassPermissionController(server, pluginConfig),
|
||||
new FightBypassCreativeController(server, pluginConfig),
|
||||
new PlaceBlockBlocker(this.fightManager, noticeService, pluginConfig),
|
||||
new PearlController(pluginConfig, this.pearlService, noticeService, fightManager),
|
||||
new TridentController(pluginConfig, noticeService, this.fightManager, this.tridentService, server),
|
||||
new DeathFlareController(pluginConfig, server, scheduler, this),
|
||||
new DeathLightningController(pluginConfig, server),
|
||||
new UpdaterNotificationController(updaterService, pluginConfig, miniMessage),
|
||||
new FightActionBlockerController(this.fightManager, noticeService, pluginConfig, server),
|
||||
new FightPearlController(pluginConfig.pearl, noticeService, this.fightManager, this.fightPearlService),
|
||||
new UpdaterNotificationController(updaterService, pluginConfig, this.audienceProvider, miniMessage),
|
||||
new KnockbackRegionController(noticeService, this.regionProvider, this.fightManager, knockbackService, server),
|
||||
new FightEffectController(pluginConfig.effect, this.fightEffectService, this.fightManager, server),
|
||||
new FightTagOutController(this.fightTagOutService),
|
||||
@@ -202,13 +190,7 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
|
||||
new BorderBlockController(borderService, () -> pluginConfig.border.block, scheduler, server),
|
||||
new EndCrystalListener(this, this.fightManager, pluginConfig),
|
||||
new RespawnAnchorListener(this, this.fightManager, pluginConfig),
|
||||
new FireworkController(this.fightManager, pluginConfig, noticeService),
|
||||
new InventoryContainersBlocker(this.fightManager, pluginConfig, noticeService),
|
||||
new CommandsBlocker(this.fightManager, noticeService, pluginConfig),
|
||||
new ElytraBlocker(this.fightManager, pluginConfig),
|
||||
new ElytraEquipBlocker(this.fightManager, noticeService, pluginConfig, server),
|
||||
new FlyingBlocker(this.fightManager, pluginConfig, server),
|
||||
new PlaceBlockBlocker(this.fightManager, noticeService, pluginConfig)
|
||||
new FireworkController(this.fightManager, pluginConfig, noticeService)
|
||||
);
|
||||
|
||||
eventManager.subscribe(
|
||||
@@ -224,7 +206,6 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
|
||||
);
|
||||
|
||||
EternalCombatProvider.initialize(this);
|
||||
this.apiInitialized = true;
|
||||
|
||||
long millis = started.elapsed(TimeUnit.MILLISECONDS);
|
||||
this.getLogger().info("Successfully loaded EternalCombat in " + millis + "ms");
|
||||
@@ -232,18 +213,17 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
EternalCombatProvider.deinitialize();
|
||||
|
||||
if (this.liteCommands != null) {
|
||||
this.liteCommands.unregister();
|
||||
}
|
||||
|
||||
if (this.fightManager != null) {
|
||||
this.fightManager.untagAll();
|
||||
if (this.audienceProvider != null) {
|
||||
this.audienceProvider.close();
|
||||
}
|
||||
|
||||
if (this.apiInitialized) {
|
||||
EternalCombatProvider.deinitialize();
|
||||
this.apiInitialized = false;
|
||||
}
|
||||
this.fightManager.untagAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -257,8 +237,8 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PearlService getFightPearlService() {
|
||||
return this.pearlService;
|
||||
public FightPearlService getFightPearlService() {
|
||||
return this.fightPearlService;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.eternalcode.combat;
|
||||
|
||||
import com.eternalcode.combat.config.ConfigService;
|
||||
import com.eternalcode.combat.notification.NoticeService;
|
||||
import com.eternalcode.multification.bukkit.notice.BukkitNotice;
|
||||
import com.eternalcode.multification.notice.Notice;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import dev.rollczi.litecommands.annotations.async.Async;
|
||||
@@ -15,7 +16,7 @@ import org.bukkit.command.CommandSender;
|
||||
@Command(name = "combatlog", aliases = "combat")
|
||||
public class EternalCombatReloadCommand {
|
||||
|
||||
private static final Notice RELOAD_MESSAGE = Notice.builder()
|
||||
private static final Notice RELOAD_MESSAGE = BukkitNotice.builder()
|
||||
.chat("<b><gradient:#8a1212:#fc6b03>EternalCombat:</gradient></b> Reloaded EternalCombat in <color:#fce303>{TIME}ms!</color>")
|
||||
.build();
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.eternalcode.combat.border.animation.block;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import org.bukkit.ChunkSnapshot;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@@ -21,7 +22,7 @@ class ChunkCache {
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
ChunkSnapshot chunkSnapshot = player.getWorld().getChunkAtAsync(location.x(), location.z(), false)
|
||||
ChunkSnapshot chunkSnapshot = PaperLib.getChunkAtAsync(player.getWorld(), location.x(), location.z(), false)
|
||||
.thenApply(chunk -> chunk.getChunkSnapshot())
|
||||
.join();
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ package com.eternalcode.combat.config;
|
||||
import com.eternalcode.combat.border.animation.block.BlockTypeTransformer;
|
||||
import com.eternalcode.combat.border.animation.particle.ParticleColorTransformer;
|
||||
import com.eternalcode.combat.border.animation.particle.ParticleTypeTransformer;
|
||||
import com.eternalcode.multification.bukkit.notice.resolver.sound.SoundBukkitResolver;
|
||||
import com.eternalcode.multification.notice.resolver.NoticeResolverDefaults;
|
||||
import com.eternalcode.multification.notice.resolver.NoticeResolverRegistry;
|
||||
import com.eternalcode.multification.notice.resolver.sound.SoundAdventureResolver;
|
||||
import com.eternalcode.multification.okaeri.MultificationSerdesPack;
|
||||
import eu.okaeri.configs.ConfigManager;
|
||||
import eu.okaeri.configs.OkaeriConfig;
|
||||
@@ -28,7 +28,7 @@ public class ConfigService {
|
||||
|
||||
YamlSnakeYamlConfigurer configurer = new YamlSnakeYamlConfigurer();
|
||||
NoticeResolverRegistry noticeRegistry = NoticeResolverDefaults.createRegistry()
|
||||
.registerResolver(new SoundAdventureResolver());
|
||||
.registerResolver(new SoundBukkitResolver());
|
||||
|
||||
configFile.withConfigurer(configurer,
|
||||
new SerdesCommons(),
|
||||
|
||||
@@ -33,20 +33,18 @@ public class CombatSettings extends OkaeriConfig {
|
||||
})
|
||||
public boolean disableFlying = true;
|
||||
|
||||
@Comment({
|
||||
"# Forcefully unequip elytra when a player enters combat.",
|
||||
"# This prevents players from abusing glide by jumping before being tagged.",
|
||||
"# The elytra will be moved to the player's inventory.",
|
||||
"# Recommended: true"
|
||||
})
|
||||
public boolean unequipElytraOnCombat = true;
|
||||
|
||||
@Comment({
|
||||
"# Prevent players from boosting themselves while flying with fireworks",
|
||||
"# This setting blocks usage of fireworks to boost elytra flight during combat"
|
||||
})
|
||||
public boolean disableFireworks = true;
|
||||
|
||||
@Comment({
|
||||
"# Prevent players from opening their inventory during combat.",
|
||||
"# Set to 'true' to block inventory access while in combat."
|
||||
})
|
||||
public boolean disableInventoryAccess = false;
|
||||
|
||||
@Comment({
|
||||
"# Enable or disable combat logging for damage caused by non-player entities.",
|
||||
"# Set to 'true' to log damage from non-player sources, or 'false' to disable this feature."
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.eternalcode.combat.config.implementation;
|
||||
|
||||
public enum InventoryAccessMode {
|
||||
/**
|
||||
* Allow access to all inventories during combat
|
||||
*/
|
||||
ALLOW_ALL,
|
||||
|
||||
/**
|
||||
* Block access to all inventories during combat
|
||||
*/
|
||||
BLOCK_ALL,
|
||||
|
||||
/**
|
||||
* Only block inventories in the restricted list
|
||||
*/
|
||||
BLACKLIST,
|
||||
|
||||
/**
|
||||
* Only allow inventories in the allowed list
|
||||
*/
|
||||
WHITELIST;
|
||||
|
||||
/**
|
||||
* Determines if an inventory type should be blocked based on the mode and whether it's in the list
|
||||
*
|
||||
* @param isInList whether the inventory type is in the configured list
|
||||
* @return true if the inventory should be blocked
|
||||
*/
|
||||
public boolean shouldBlock(boolean isInList) {
|
||||
return switch (this) {
|
||||
case ALLOW_ALL -> false;
|
||||
case BLOCK_ALL -> true;
|
||||
case BLACKLIST -> isInList;
|
||||
case WHITELIST -> !isInList;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.eternalcode.combat.config.implementation;
|
||||
|
||||
import eu.okaeri.configs.OkaeriConfig;
|
||||
import eu.okaeri.configs.annotation.Comment;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class InventorySettings extends OkaeriConfig {
|
||||
|
||||
@Comment({
|
||||
"# Inventory access restriction mode during combat",
|
||||
"# ALLOW_ALL - Players can open all inventories during combat",
|
||||
"# BLOCK_ALL - Players cannot open any inventories during combat",
|
||||
"# BLACKLIST - Block only inventories listed in restrictedInventoryTypes",
|
||||
"# WHITELIST - Allow only inventories listed in restrictedInventoryTypes"
|
||||
})
|
||||
public InventoryAccessMode inventoryAccessMode = InventoryAccessMode.ALLOW_ALL;
|
||||
|
||||
@Comment({
|
||||
"# List of inventory types to restrict or allow (depending on the mode)",
|
||||
"# In BLACKLIST mode: these inventories will be blocked",
|
||||
"# In WHITELIST mode: only these inventories will be allowed",
|
||||
"# Available types: CHEST, ENDER_CHEST, DISPENSER, DROPPER, FURNACE, WORKBENCH,",
|
||||
"# CRAFTING, ENCHANTING, BREWING, MERCHANT, BEACON, ANVIL, SMITHING, HOPPER,",
|
||||
"# SHULKER_BOX, BARREL, BLAST_FURNACE, LECTERN, SMOKER, LOOM, CARTOGRAPHY,",
|
||||
"# GRINDSTONE, STONECUTTER, COMPOSTER, CHISELED_BOOKSHELF, JUKEBOX, SMITHING_NEW,",
|
||||
"# CRAFTER, DECORATED_POT",
|
||||
"# Note: PLAYER and CREATIVE inventories are never blocked to prevent game-breaking issues",
|
||||
"# Full list: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/event/inventory/InventoryType.html"
|
||||
})
|
||||
public List<InventoryType> restrictedInventoryTypes = List.of(
|
||||
InventoryType.CHEST,
|
||||
InventoryType.ENDER_CHEST,
|
||||
InventoryType.BARREL,
|
||||
InventoryType.SHULKER_BOX
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.eternalcode.combat.config.implementation;
|
||||
|
||||
import com.eternalcode.multification.bukkit.notice.BukkitNotice;
|
||||
import com.eternalcode.multification.notice.Notice;
|
||||
import eu.okaeri.configs.OkaeriConfig;
|
||||
import eu.okaeri.configs.annotation.Comment;
|
||||
@@ -7,205 +8,189 @@ import eu.okaeri.configs.annotation.Comment;
|
||||
public class MessagesSettings extends OkaeriConfig {
|
||||
|
||||
@Comment({
|
||||
"# Customize messages related to admin commands and notifications.",
|
||||
"# These messages are displayed to server administrators."
|
||||
"# Customize messages related to admin commands and notifications.",
|
||||
"# These messages are displayed to server administrators."
|
||||
})
|
||||
public AdminMessages admin = new AdminMessages();
|
||||
|
||||
@Comment({
|
||||
" ",
|
||||
"# Configure the combat log notification displayed to players.",
|
||||
"# You can use the {TIME} variable to display the remaining combat time.",
|
||||
"# Placeholder {OPPONENT} will be replaced with player name or 'unknownPlayerPlaceholder' variable",
|
||||
" ",
|
||||
" ",
|
||||
"# Configure the combat log notification displayed to players.",
|
||||
"# You can use the {TIME} variable to display the remaining combat time.",
|
||||
" ",
|
||||
})
|
||||
public Notice combatNotification = Notice.builder()
|
||||
.actionBar("Combat ends in: <red>{TIME}</red>")
|
||||
.build();
|
||||
public Notice combatNotification = BukkitNotice.builder()
|
||||
.actionBar("Combat ends in: <red>{TIME}</red>")
|
||||
.build();
|
||||
|
||||
@Comment({
|
||||
"# Would you like to display milliseconds instead of seconds in combat notification "
|
||||
"# Would you like to display milliseconds instead of seconds in combat notification "
|
||||
})
|
||||
public boolean withoutMillis = true;
|
||||
|
||||
@Comment({
|
||||
" ",
|
||||
"# When player is not known this text will be used as {OPPONENT} in 'combatNotification'"
|
||||
})
|
||||
public String unknownPlayerPlaceholder = "Unknown";
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when a player lacks permission to execute a command.",
|
||||
"# The {PERMISSION} placeholder is replaced with the required permission."
|
||||
"# Message displayed when a player lacks permission to execute a command.",
|
||||
"# The {PERMISSION} placeholder is replaced with the required permission."
|
||||
})
|
||||
public Notice noPermission = Notice.chat(
|
||||
"<gradient:red:dark_red>You don't have permission <dark_gray>(<gray>{PERMISSION}</gray>)</dark_gray> to perform this command!</gradient>");
|
||||
"<gradient:red:dark_red>You don't have permission <dark_gray>(<gray>{PERMISSION}</gray>)</dark_gray> to perform this command!</gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when a specified player is not found.",
|
||||
"# This message is shown when a command targets a player who is not online or does not exist."
|
||||
"# Message displayed when a specified player is not found.",
|
||||
"# This message is shown when a command targets a player who is not online or does not exist."
|
||||
})
|
||||
public Notice playerNotFound = Notice
|
||||
.chat("<gradient:#ff0000:#ff6b6b>The specified player could not be found!</gradient>");
|
||||
public Notice playerNotFound =
|
||||
Notice.chat("<gradient:#ff0000:#ff6b6b>The specified player could not be found!</gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when a player enters combat.",
|
||||
"# This message warns the player not to leave the server while in combat."
|
||||
"# Message displayed when a player enters combat.",
|
||||
"# This message warns the player not to leave the server while in combat."
|
||||
})
|
||||
public Notice playerTagged = Notice.chat(
|
||||
"<gradient:red:yellow>⚠ <white>You are in combat!</white> <u>Do not leave the server!</gradient>");
|
||||
"<gradient:red:yellow>⚠ <white>You are in combat!</white> <u>Do not leave the server!</gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when a player leaves combat.",
|
||||
"# This message informs the player that they can safely leave the server."
|
||||
"# Message displayed when a player leaves combat.",
|
||||
"# This message informs the player that they can safely leave the server."
|
||||
})
|
||||
public Notice playerUntagged = Notice.chat(
|
||||
"<gradient:#00ff00:#00b300>✌ <white>Combat ended!</white> You can now safely leave!</gradient>");
|
||||
"<gradient:#00ff00:#00b300>✌ <white>Combat ended!</white> You can now safely leave!</gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Broadcast message displayed when a player logs out during combat.",
|
||||
"# The {PLAYER} placeholder is replaced with the player's name."
|
||||
"# Broadcast message displayed when a player logs out during combat.",
|
||||
"# The {PLAYER} placeholder is replaced with the player's name."
|
||||
})
|
||||
public Notice playerLoggedOutDuringCombat = Notice
|
||||
.chat("<gradient:red:dark_red>⚠ <white>{PLAYER}</white> logged off during combat!</gradient>");
|
||||
public Notice playerLoggedOutDuringCombat =
|
||||
Notice.chat("<gradient:red:dark_red>⚠ <white>{PLAYER}</white> logged off during combat!</gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when a player attempts to use a disabled command during combat.",
|
||||
"# This message informs the player that the command is prohibited while in combat."
|
||||
"# Message displayed when a player attempts to use a disabled command during combat.",
|
||||
"# This message informs the player that the command is prohibited while in combat."
|
||||
})
|
||||
public Notice commandDisabledDuringCombat = Notice.chat(
|
||||
"<gradient:red:yellow>⚠ <white>Command blocked!</white> Cannot use this during combat!</gradient>");
|
||||
"<gradient:red:yellow>⚠ <white>Command blocked!</white> Cannot use this during combat!</gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when a player attempts to use an elytra during combat.",
|
||||
"# This includes gliding, equipping, or having it forcefully removed.",
|
||||
"# Informs the player that elytra usage is disabled in combat."
|
||||
})
|
||||
public Notice elytraDisabledDuringCombat = Notice.chat(
|
||||
"<gradient:red:yellow>⚠ <white>Elytra disabled!</white> Cannot use elytra during combat!</gradient>"
|
||||
);
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when a player uses a command with incorrect arguments.",
|
||||
"# The {USAGE} placeholder is replaced with the correct command syntax."
|
||||
"# Message displayed when a player uses a command with incorrect arguments.",
|
||||
"# The {USAGE} placeholder is replaced with the correct command syntax."
|
||||
})
|
||||
public Notice invalidCommandUsage = Notice.chat("<gray>Usage: <gradient:gold:yellow>{USAGE}</gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when a player attempts to open their inventory during combat.",
|
||||
"# This message informs the player that inventory access is blocked while in combat."
|
||||
"# Message displayed when a player attempts to open their inventory during combat.",
|
||||
"# This message informs the player that inventory access is blocked while in combat."
|
||||
})
|
||||
public Notice inventoryBlockedDuringCombat = Notice.chat(
|
||||
"<gradient:red:dark_red>⚠ <white>Inventory access</white> is restricted during combat!</gradient>");
|
||||
"<gradient:red:dark_red>⚠ <white>Inventory access</white> is restricted during combat!</gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when a player attempts to place a block during combat.",
|
||||
"# The {MODE} placeholder is replaced with the block placement mode (ABOVE/BELOW).",
|
||||
"# The {Y} placeholder is replaced with the Y coordinate set in the config."
|
||||
"# Message displayed when a player attempts to place a block during combat.",
|
||||
"# The {MODE} placeholder is replaced with the block placement mode (ABOVE/BELOW).",
|
||||
"# The {Y} placeholder is replaced with the Y coordinate set in the config."
|
||||
})
|
||||
public Notice blockPlacingBlockedDuringCombat = Notice
|
||||
.chat("<gradient:red:yellow>⚠ Block placement <white>{MODE} Y:{Y}</white> is restricted!</gradient>");
|
||||
public Notice blockPlacingBlockedDuringCombat =
|
||||
Notice.chat("<gradient:red:yellow>⚠ Block placement <white>{MODE} Y:{Y}</white> is restricted!</gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message sent to the player using fireworks when fireworks during elytra flight are disabled"
|
||||
"# Message sent to the player using fireworks when fireworks during elytra flight are disabled"
|
||||
})
|
||||
public Notice fireworksDisabled = Notice
|
||||
.actionbar("<gradient:red:yellow>⚠ You can't use fireworks during combat ⚠</gradient>");
|
||||
|
||||
public Notice fireworksDisabled = Notice.actionbar("<gradient:red:yellow>⚠ You can't use fireworks during combat ⚠</gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when a player attempts to enter a restricted region during combat.",
|
||||
"# This message informs the player that they cannot enter the region while in combat."
|
||||
"# Message displayed when a player attempts to enter a restricted region during combat.",
|
||||
"# This message informs the player that they cannot enter the region while in combat."
|
||||
})
|
||||
public Notice cantEnterOnRegion = Notice.chat(
|
||||
"<gradient:red:dark_red>⚠ Restricted area!</gradient> <white>Cannot enter during combat!</white>");
|
||||
"<gradient:red:dark_red>⚠ Restricted area!</gradient> <white>Cannot enter during combat!</white>");
|
||||
|
||||
public static class AdminMessages extends OkaeriConfig {
|
||||
@Comment({
|
||||
"# Message displayed when the console attempts to use a player-only command.",
|
||||
"# This message informs the console that the command is not available for non-players."
|
||||
"# Message displayed when the console attempts to use a player-only command.",
|
||||
"# This message informs the console that the command is not available for non-players."
|
||||
})
|
||||
public Notice onlyForPlayers = Notice.chat("<gradient:red:dark_red>❌ This command is player-only!</gradient>");
|
||||
public Notice onlyForPlayers =
|
||||
Notice.chat("<gradient:red:dark_red>❌ This command is player-only!</gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed to an admin when they tag a player.",
|
||||
"# The {PLAYER} placeholder is replaced with the tagged player's name."
|
||||
"# Message displayed to an admin when they tag a player.",
|
||||
"# The {PLAYER} placeholder is replaced with the tagged player's name."
|
||||
})
|
||||
public Notice adminTagPlayer = Notice
|
||||
.chat("<gradient:#00b3ff:#0066ff>⚔ <gray>Tagged player:</gray> <white>{PLAYER}</white></gradient>");
|
||||
public Notice adminTagPlayer =
|
||||
Notice.chat("<gradient:#00b3ff:#0066ff>⚔ <gray>Tagged player:</gray> <white>{PLAYER}</white></gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when an admin tags multiple players.",
|
||||
"# The {FIRST_PLAYER} and {SECOND_PLAYER} placeholders are replaced with the players' names."
|
||||
"# Message displayed when an admin tags multiple players.",
|
||||
"# The {FIRST_PLAYER} and {SECOND_PLAYER} placeholders are replaced with the players' names."
|
||||
})
|
||||
public Notice adminTagMultiplePlayers = Notice.chat(
|
||||
"<gradient:#00b3ff:#0066ff>⚔ <gray>Tagged:</gray> <white>{FIRST_PLAYER}</white> <gray>and</gray> <white>{SECOND_PLAYER}</white></gradient>");
|
||||
"<gradient:#00b3ff:#0066ff>⚔ <gray>Tagged:</gray> <white>{FIRST_PLAYER}</white> <gray>and</gray> <white>{SECOND_PLAYER}</white></gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed to an admin when they remove a player from combat.",
|
||||
"# The {PLAYER} placeholder is replaced with the player's name."
|
||||
"# Message displayed to an admin when they remove a player from combat.",
|
||||
"# The {PLAYER} placeholder is replaced with the player's name."
|
||||
})
|
||||
public Notice adminUntagPlayer = Notice.chat(
|
||||
"<gradient:#00ff88:#00b300>✌ <gray>Removed</gray> <white>{PLAYER}</white> <gray>from combat</gray></gradient>");
|
||||
"<gradient:#00ff88:#00b300>✌ <gray>Removed</gray> <white>{PLAYER}</white> <gray>from combat</gray></gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed to an admin when they remove a player from combat.",
|
||||
"# The {PLAYER} placeholder is replaced with the player's name."
|
||||
"# Message displayed to an admin when they remove a player from combat.",
|
||||
"# The {PLAYER} placeholder is replaced with the player's name."
|
||||
})
|
||||
public Notice adminUntagAll = Notice.chat(
|
||||
"<gradient:#00ff88:#00b300>✌ <gray>Removed</gray> <white>{COUNT}</white> <gray> players from combat</gray></gradient>");
|
||||
"<gradient:#00ff88:#00b300>✌ <gray>Removed</gray> <white>{COUNT}</white> <gray> players from combat</gray></gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when an admin attempts to untag a player who is not in combat.",
|
||||
"# This message informs the admin that the player is not currently in combat."
|
||||
"# Message displayed when an admin attempts to untag a player who is not in combat.",
|
||||
"# This message informs the admin that the player is not currently in combat."
|
||||
})
|
||||
public Notice adminPlayerNotInCombat = Notice
|
||||
.chat("<gradient:red:dark_red>❌ <white>{PLAYER}</white> is not in combat!</gradient>");
|
||||
public Notice adminPlayerNotInCombat =
|
||||
Notice.chat("<gradient:red:dark_red>❌ <white>{PLAYER}</white> is not in combat!</gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when a player is in combat.",
|
||||
"# The {PLAYER} placeholder is replaced with the player's name."
|
||||
"# Message displayed when a player is in combat.",
|
||||
"# The {PLAYER} placeholder is replaced with the player's name."
|
||||
})
|
||||
public Notice playerInCombat = Notice
|
||||
.chat("<gradient:#ff6666:#ff0000>⚔ <white>{PLAYER}</white> <gray>is in combat!</gray></gradient>");
|
||||
public Notice playerInCombat =
|
||||
Notice.chat("<gradient:#ff6666:#ff0000>⚔ <white>{PLAYER}</white> <gray>is in combat!</gray></gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when a player is not in combat.",
|
||||
"# The {PLAYER} placeholder is replaced with the player's name."
|
||||
"# Message displayed when a player is not in combat.",
|
||||
"# The {PLAYER} placeholder is replaced with the player's name."
|
||||
})
|
||||
public Notice playerNotInCombat = Notice
|
||||
.chat("<gradient:#00ff00:#00b300>✌ <white>{PLAYER}</white> <gray>is safe</gray></gradient>");
|
||||
public Notice playerNotInCombat =
|
||||
Notice.chat("<gradient:#00ff00:#00b300>✌ <white>{PLAYER}</white> <gray>is safe</gray></gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when an admin attempts to tag themselves.",
|
||||
"# This message informs the admin that they cannot tag themselves."
|
||||
"# Message displayed when an admin attempts to tag themselves.",
|
||||
"# This message informs the admin that they cannot tag themselves."
|
||||
})
|
||||
public Notice adminCannotTagSelf = Notice.chat("<gradient:red:dark_red>❌ Cannot tag yourself!</gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when an admin disables combat tagging for themselves.",
|
||||
"# The {TIME} placeholder is replaced with the remaining fight time."
|
||||
"# Message displayed when an admin disables combat tagging for themselves.",
|
||||
"# The {TIME} placeholder is replaced with the remaining fight time."
|
||||
})
|
||||
public Notice adminTagOutSelf = Notice.chat(
|
||||
"<gradient:#00b3ff:#0066ff>🛡 <gray>Self-protection active for</gray> <white>{TIME}</white></gradient>");
|
||||
"<gradient:#00b3ff:#0066ff>🛡 <gray>Self-protection active for</gray> <white>{TIME}</white></gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when an admin disables combat tagging for another player.",
|
||||
"# The {PLAYER} placeholder is replaced with the player's name.",
|
||||
"# The {TIME} placeholder is replaced with the remaining fight time."
|
||||
"# Message displayed when an admin disables combat tagging for another player.",
|
||||
"# The {PLAYER} placeholder is replaced with the player's name.",
|
||||
"# The {TIME} placeholder is replaced with the remaining fight time."
|
||||
})
|
||||
public Notice adminTagOut = Notice.chat(
|
||||
"<gradient:#00b3ff:#0066ff>🛡 <gray>Protected</gray> <white>{PLAYER}</white> <gray>for</gray> <white>{TIME}</white></gradient>");
|
||||
"<gradient:#00b3ff:#0066ff>🛡 <gray>Protected</gray> <white>{PLAYER}</white> <gray>for</gray> <white>{TIME}</white></gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed to a player when their combat tagging is disabled.",
|
||||
"# The {TIME} placeholder is replaced with the remaining fight time."
|
||||
"# Message displayed to a player when their combat tagging is disabled.",
|
||||
"# The {TIME} placeholder is replaced with the remaining fight time."
|
||||
})
|
||||
public Notice playerTagOut = Notice.chat(
|
||||
"<gradient:#00ff88:#00b300>🛡 <gray>Protection active for</gray> <white>{TIME}</white></gradient>");
|
||||
"<gradient:#00ff88:#00b300>🛡 <gray>Protection active for</gray> <white>{TIME}</white></gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when an admin reenables combat tagging for a player.",
|
||||
"# The {PLAYER} placeholder is replaced with the player's name."
|
||||
"# Message displayed when an admin reenables combat tagging for a player.",
|
||||
"# The {PLAYER} placeholder is replaced with the player's name."
|
||||
})
|
||||
public Notice adminTagOutOff = Notice.chat(
|
||||
"<gradient:#00ff88:#00b300>✌ <gray>Re-enabled tagging for</gray> <white>{PLAYER}</white></gradient>");
|
||||
@@ -220,14 +205,7 @@ public class MessagesSettings extends OkaeriConfig {
|
||||
"# Message displayed when an admin attempts to tag a player who has tag-out enabled.",
|
||||
"# This message informs the admin that the player cannot be tagged at this time."
|
||||
})
|
||||
public Notice adminTagOutCanceled = Notice
|
||||
.chat("<gradient:red:dark_red>❌ Player has tag-out protection!</gradient>");
|
||||
|
||||
@Comment({
|
||||
"# Message displayed when an admin checks combat statistics.",
|
||||
"# The {COUNT} placeholder is replaced with the number of players currently in combat."
|
||||
})
|
||||
public Notice combatStats = Notice
|
||||
.chat("<gradient:#ff6666:#ff0000>⚔ <gray>Players in combat:</gray> <white>{COUNT}</white></gradient>");
|
||||
public Notice adminTagOutCanceled =
|
||||
Notice.chat("<gradient:red:dark_red>❌ Player has tag-out protection!</gradient>");
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
package com.eternalcode.combat.config.implementation;
|
||||
|
||||
import com.eternalcode.combat.border.BorderSettings;
|
||||
import com.eternalcode.combat.fight.death.DeathSettings;
|
||||
import com.eternalcode.combat.fight.drop.DropSettings;
|
||||
import com.eternalcode.combat.fight.effect.FightEffectSettings;
|
||||
import com.eternalcode.combat.fight.knockback.KnockbackSettings;
|
||||
import com.eternalcode.combat.fight.pearl.PearlSettings;
|
||||
import com.eternalcode.combat.fight.trident.TridentSettings;
|
||||
import com.eternalcode.combat.fight.pearl.FightPearlSettings;
|
||||
import eu.okaeri.configs.OkaeriConfig;
|
||||
import eu.okaeri.configs.annotation.Comment;
|
||||
import java.time.Duration;
|
||||
@@ -35,14 +33,7 @@ public class PluginConfig extends OkaeriConfig {
|
||||
"# Settings related to Ender Pearls.",
|
||||
"# Configure cooldowns, restrictions, and other behaviors for Ender Pearls during combat."
|
||||
})
|
||||
public PearlSettings pearl = new PearlSettings();
|
||||
|
||||
@Comment({
|
||||
" ",
|
||||
"# Settings related to Trident",
|
||||
"# Configure cooldowns, restrictions, and other behaviors for Trident during combat."
|
||||
})
|
||||
public TridentSettings trident = new TridentSettings();
|
||||
public FightPearlSettings pearl = new FightPearlSettings();
|
||||
|
||||
@Comment({
|
||||
" ",
|
||||
@@ -51,12 +42,6 @@ public class PluginConfig extends OkaeriConfig {
|
||||
})
|
||||
public FightEffectSettings effect = new FightEffectSettings();
|
||||
|
||||
@Comment({
|
||||
" ",
|
||||
"# This section contains effects displayed on death of the player"
|
||||
})
|
||||
public DeathSettings death = new DeathSettings();
|
||||
|
||||
@Comment({
|
||||
" ",
|
||||
"# Customize how items are dropped when a player dies during combat.",
|
||||
@@ -120,13 +105,6 @@ public class PluginConfig extends OkaeriConfig {
|
||||
})
|
||||
public CombatSettings combat = new CombatSettings();
|
||||
|
||||
@Comment({
|
||||
" ",
|
||||
"# Settings related to inventory access during combat.",
|
||||
"# Configure which inventories players can or cannot access while in combat."
|
||||
})
|
||||
public InventorySettings inventory = new InventorySettings();
|
||||
|
||||
@Comment({
|
||||
" ",
|
||||
"# Settings related to placeholders used in the plugin.",
|
||||
|
||||
@@ -3,11 +3,12 @@ package com.eternalcode.combat.crystalpvp;
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.fight.event.CauseOfTag;
|
||||
import com.eternalcode.combat.util.ReflectUtil;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.entity.EnderCrystal;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.entity.EntityDamageByBlockEvent;
|
||||
@@ -22,6 +23,21 @@ public class CrystalPvpConstants {
|
||||
public static final String CRYSTAL_METADATA = "eternalcombat:crystal";
|
||||
public static final String ANCHOR_METADATA = "eternalcombat:anchor";
|
||||
|
||||
private static final boolean HAS_DAMAGER_BLOCK_STATE = checkForDamagerBlockState();
|
||||
|
||||
private static boolean checkForDamagerBlockState() {
|
||||
try {
|
||||
return EntityDamageByBlockEvent.class.getDeclaredMethod("getDamagerBlockState") != null;
|
||||
}
|
||||
catch (NoSuchMethodException exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static boolean hasDamagerBlockState() {
|
||||
return HAS_DAMAGER_BLOCK_STATE;
|
||||
}
|
||||
|
||||
public static Optional<UUID> getDamagerUniqueIdFromEndCrystal(EntityDamageByEntityEvent event) {
|
||||
if (event.getDamager() instanceof EnderCrystal enderCrystal) {
|
||||
List<MetadataValue> metadataValues = enderCrystal.getMetadata(CRYSTAL_METADATA);
|
||||
@@ -36,16 +52,20 @@ public class CrystalPvpConstants {
|
||||
}
|
||||
|
||||
public static Optional<UUID> getDamagerUniqueIdFromRespawnAnchor(EntityDamageByBlockEvent event) {
|
||||
Block damager = event.getDamager();
|
||||
if (damager == null) {
|
||||
if (!CrystalPvpConstants.hasDamagerBlockState()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (damager.getType() != Material.RESPAWN_ANCHOR) {
|
||||
Object maybeState = ReflectUtil.invokeMethod(event, "getDamagerBlockState");
|
||||
if (!(maybeState instanceof BlockState state)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
Material type = state.getType();
|
||||
if (!type.equals(Material.RESPAWN_ANCHOR)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return damager.getMetadata(ANCHOR_METADATA).stream()
|
||||
return state.getMetadata(ANCHOR_METADATA).stream()
|
||||
.filter(source -> source instanceof CrystalMetadata)
|
||||
.map(meta -> (CrystalMetadata) meta)
|
||||
.findFirst()
|
||||
|
||||
@@ -16,8 +16,10 @@ import dev.rollczi.litecommands.annotations.permission.Permission;
|
||||
import dev.rollczi.litecommands.annotations.priority.Priority;
|
||||
import dev.rollczi.litecommands.annotations.priority.PriorityValue;
|
||||
import java.time.Duration;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@@ -47,6 +49,7 @@ public class FightTagCommand {
|
||||
.placeholder("{PLAYER}", target.getName())
|
||||
.viewer(sender)
|
||||
.send();
|
||||
|
||||
}
|
||||
|
||||
@Execute(name = "tag")
|
||||
@@ -71,6 +74,7 @@ public class FightTagCommand {
|
||||
.placeholder("{PLAYER}", target.getName())
|
||||
.viewer(sender)
|
||||
.send();
|
||||
|
||||
}
|
||||
|
||||
@Execute(name = "tag")
|
||||
@@ -118,6 +122,7 @@ public class FightTagCommand {
|
||||
.placeholder("{SECOND_PLAYER}", secondTarget.getName())
|
||||
.viewer(sender)
|
||||
.send();
|
||||
|
||||
}
|
||||
|
||||
@Execute(name = "untag")
|
||||
@@ -139,6 +144,7 @@ public class FightTagCommand {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.noticeService.create()
|
||||
.notice(this.config.messagesSettings.admin.adminUntagPlayer)
|
||||
.placeholder("{PLAYER}", target.getName())
|
||||
@@ -163,28 +169,13 @@ public class FightTagCommand {
|
||||
.send();
|
||||
}
|
||||
|
||||
@Execute(name = "stats")
|
||||
@Permission("eternalcombat.stats")
|
||||
void stats(@Context CommandSender sender) {
|
||||
long activeCombatPlayers = this.fightManager.getFights().stream()
|
||||
.filter(fightTag -> !fightTag.isExpired())
|
||||
.count();
|
||||
|
||||
this.noticeService.create()
|
||||
.notice(this.config.messagesSettings.admin.combatStats)
|
||||
.placeholder("{COUNT}", String.valueOf(activeCombatPlayers))
|
||||
.viewer(sender)
|
||||
.send();
|
||||
}
|
||||
|
||||
private void tagoutReasonHandler(
|
||||
CommandSender sender, CancelTagReason cancelReason,
|
||||
MessagesSettings messagesSettings) {
|
||||
private void tagoutReasonHandler(CommandSender sender, CancelTagReason cancelReason, MessagesSettings messagesSettings) {
|
||||
if (cancelReason == CancelTagReason.TAGOUT) {
|
||||
this.noticeService.create()
|
||||
.notice(messagesSettings.admin.adminTagOutCanceled)
|
||||
.viewer(sender)
|
||||
.send();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.event.CauseOfUnTag;
|
||||
import com.eternalcode.combat.notification.NoticeService;
|
||||
import com.eternalcode.combat.util.DurationUtil;
|
||||
import java.util.Optional;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@@ -18,7 +17,7 @@ public class FightTask implements Runnable {
|
||||
private final FightManager fightManager;
|
||||
private final NoticeService noticeService;
|
||||
|
||||
public FightTask(Server server, PluginConfig config, FightManager fightManager, NoticeService noticeService) {
|
||||
public FightTask(Server server, PluginConfig config, FightManager fightManager, NoticeService noticeService) {
|
||||
this.server = server;
|
||||
this.config = config;
|
||||
this.fightManager = fightManager;
|
||||
@@ -43,17 +42,10 @@ public class FightTask implements Runnable {
|
||||
|
||||
Duration remaining = fightTag.getRemainingDuration();
|
||||
|
||||
String opponent = Optional.ofNullable(fightTag.getTagger())
|
||||
.filter(uuid -> !uuid.equals(playerUniqueId))
|
||||
.map(this.server::getPlayer)
|
||||
.map(Player::getName)
|
||||
.orElse(this.config.messagesSettings.unknownPlayerPlaceholder);
|
||||
|
||||
this.noticeService.create()
|
||||
.player(player.getUniqueId())
|
||||
.notice(this.config.messagesSettings.combatNotification)
|
||||
.placeholder("{TIME}", DurationUtil.format(remaining, this.config.messagesSettings.withoutMillis))
|
||||
.placeholder("{OPPONENT}", opponent)
|
||||
.send();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
package com.eternalcode.combat.fight.blocker;
|
||||
|
||||
import com.eternalcode.combat.WhitelistBlacklistMode;
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.notification.NoticeService;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.util.StringUtil;
|
||||
|
||||
public class CommandsBlocker implements Listener {
|
||||
|
||||
private final FightManager fightManager;
|
||||
private final NoticeService noticeService;
|
||||
private final PluginConfig config;
|
||||
|
||||
public CommandsBlocker(FightManager fightManager, NoticeService noticeService, PluginConfig config) {
|
||||
this.fightManager = fightManager;
|
||||
this.noticeService = noticeService;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
UUID playerUniqueId = player.getUniqueId();
|
||||
|
||||
if (!this.fightManager.isInCombat(playerUniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String command = event.getMessage().substring(1);
|
||||
|
||||
boolean isAnyMatch = this.config.commands.restrictedCommands.stream()
|
||||
.anyMatch(restrictedCommand -> StringUtil.startsWithIgnoreCase(command, restrictedCommand));
|
||||
|
||||
WhitelistBlacklistMode mode = this.config.commands.commandRestrictionMode;
|
||||
|
||||
boolean shouldCancel = mode.shouldBlock(isAnyMatch);
|
||||
|
||||
if (shouldCancel) {
|
||||
event.setCancelled(true);
|
||||
this.noticeService.create()
|
||||
.player(playerUniqueId)
|
||||
.notice(this.config.messagesSettings.commandDisabledDuringCombat)
|
||||
.send();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
package com.eternalcode.combat.fight.blocker;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import java.time.Duration;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.EntityToggleGlideEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
|
||||
public class ElytraBlocker implements Listener {
|
||||
|
||||
private final FightManager fightManager;
|
||||
private final PluginConfig config;
|
||||
private final Cache<UUID, Boolean> fallProtection = Caffeine.newBuilder()
|
||||
.expireAfterWrite(Duration.ofSeconds(10))
|
||||
.build();
|
||||
|
||||
public ElytraBlocker(FightManager fightManager, PluginConfig config) {
|
||||
this.fightManager = fightManager;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onToggleGlide(EntityToggleGlideEvent event) {
|
||||
if (!this.config.combat.disableElytraUsage) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(event.getEntity() instanceof Player player)) {
|
||||
return;
|
||||
}
|
||||
UUID uniqueId = player.getUniqueId();
|
||||
|
||||
if (!this.fightManager.isInCombat(uniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.isGliding()) {
|
||||
event.setCancelled(true);
|
||||
player.setGliding(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
void onMoveWhileGliding(PlayerMoveEvent event) {
|
||||
if (!this.config.combat.disableElytraUsage) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
UUID uniqueId = player.getUniqueId();
|
||||
|
||||
if (!this.fightManager.isInCombat(uniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.isGliding()) {
|
||||
player.setGliding(false);
|
||||
|
||||
player.setVelocity(player.getVelocity().setY(-10));
|
||||
player.setFallDistance(0f);
|
||||
fallProtection.put(uniqueId, true);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEntityDamage(EntityDamageEvent event) {
|
||||
if (!(event.getEntity() instanceof Player player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getCause() != EntityDamageEvent.DamageCause.FALL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fallProtection.get(player.getUniqueId(), key -> false)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onDamage(EntityDamageEvent event) {
|
||||
if (!this.config.combat.disableElytraOnDamage) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(event.getEntity() instanceof Player player)) {
|
||||
return;
|
||||
}
|
||||
UUID uniqueId = player.getUniqueId();
|
||||
|
||||
if (this.fightManager.isInCombat(uniqueId) && player.isGliding()) {
|
||||
player.setGliding(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
package com.eternalcode.combat.fight.blocker;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.fight.event.FightTagEvent;
|
||||
import com.eternalcode.combat.notification.NoticeService;
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class ElytraEquipBlocker implements Listener {
|
||||
|
||||
private final FightManager fightManager;
|
||||
private final NoticeService noticeService;
|
||||
private final PluginConfig config;
|
||||
private final Server server;
|
||||
|
||||
public ElytraEquipBlocker(FightManager fightManager, NoticeService noticeService, PluginConfig config, Server server) {
|
||||
this.fightManager = fightManager;
|
||||
this.noticeService = noticeService;
|
||||
this.config = config;
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onInventoryClick(InventoryClickEvent event) {
|
||||
if (!(event.getWhoClicked() instanceof Player player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.config.combat.unequipElytraOnCombat) {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID uniqueId = player.getUniqueId();
|
||||
|
||||
if (!this.fightManager.isInCombat(uniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getCurrentItem() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getCurrentItem().getType() == Material.ELYTRA) {
|
||||
event.setCancelled(true);
|
||||
|
||||
this.noticeService.create()
|
||||
.player(uniqueId)
|
||||
.notice(this.config.messagesSettings.elytraDisabledDuringCombat)
|
||||
.send();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
void onTag(FightTagEvent event) {
|
||||
UUID uniqueId = event.getPlayer();
|
||||
Player player = this.server.getPlayer(uniqueId);
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.config.combat.unequipElytraOnCombat) {
|
||||
ItemStack chest = player.getInventory().getChestplate();
|
||||
|
||||
if (chest != null && chest.getType() == Material.ELYTRA) {
|
||||
removeChestplateIfElytra(player);
|
||||
|
||||
this.noticeService.create()
|
||||
.player(uniqueId)
|
||||
.notice(this.config.messagesSettings.elytraDisabledDuringCombat)
|
||||
.send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeChestplateIfElytra(Player player) {
|
||||
ItemStack chestplate = player.getInventory().getChestplate();
|
||||
|
||||
if (chestplate != null && chestplate.getType() == Material.ELYTRA) {
|
||||
player.getInventory().setChestplate(null);
|
||||
|
||||
HashMap<Integer, ItemStack> leftover = player.getInventory().addItem(chestplate);
|
||||
leftover.values().forEach(item ->
|
||||
player.getWorld().dropItemNaturally(player.getLocation(), item)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onInteract(PlayerInteractEvent event) {
|
||||
if (!this.config.combat.unequipElytraOnCombat) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getItem() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getItem().getType() != Material.ELYTRA) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
UUID uniqueId = player.getUniqueId();
|
||||
|
||||
if (!this.fightManager.isInCombat(uniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.getAction()) {
|
||||
case RIGHT_CLICK_AIR, RIGHT_CLICK_BLOCK -> {
|
||||
event.setCancelled(true);
|
||||
|
||||
this.noticeService.create()
|
||||
.player(uniqueId)
|
||||
.notice(this.config.messagesSettings.elytraDisabledDuringCombat)
|
||||
.send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package com.eternalcode.combat.fight.blocker;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.fight.event.FightTagEvent;
|
||||
import com.eternalcode.combat.fight.event.FightUntagEvent;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerToggleFlightEvent;
|
||||
|
||||
public class FlyingBlocker implements Listener {
|
||||
|
||||
private final FightManager fightManager;
|
||||
private final PluginConfig config;
|
||||
private final Server server;
|
||||
|
||||
public FlyingBlocker(FightManager fightManager, PluginConfig config, Server server) {
|
||||
this.fightManager = fightManager;
|
||||
this.config = config;
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
void onFly(PlayerToggleFlightEvent event) {
|
||||
if (!this.config.combat.disableFlying) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
UUID uniqueId = player.getUniqueId();
|
||||
|
||||
if (!this.fightManager.isInCombat(uniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.isFlying()) {
|
||||
player.setAllowFlight(false);
|
||||
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
void onTag(FightTagEvent event) {
|
||||
UUID uniqueId = event.getPlayer();
|
||||
Player player = this.server.getPlayer(uniqueId);
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.config.combat.disableFlying) {
|
||||
GameMode gameMode = player.getGameMode();
|
||||
|
||||
if (gameMode != GameMode.CREATIVE && gameMode != GameMode.SPECTATOR) {
|
||||
player.setAllowFlight(false);
|
||||
player.setFlying(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onUnTag(FightUntagEvent event) {
|
||||
if (!this.config.combat.disableFlying) {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID uniqueId = event.getPlayer();
|
||||
Player player = this.server.getPlayer(uniqueId);
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
GameMode playerGameMode = player.getGameMode();
|
||||
if (playerGameMode == GameMode.CREATIVE || playerGameMode == GameMode.SPECTATOR) {
|
||||
player.setAllowFlight(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package com.eternalcode.combat.fight.blocker;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.notification.NoticeService;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryOpenEvent;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
|
||||
public class InventoryContainersBlocker implements Listener {
|
||||
|
||||
private final FightManager fightManager;
|
||||
private final PluginConfig config;
|
||||
private final NoticeService noticeService;
|
||||
|
||||
public InventoryContainersBlocker(FightManager fightManager, PluginConfig config, NoticeService noticeService) {
|
||||
this.fightManager = fightManager;
|
||||
this.config = config;
|
||||
this.noticeService = noticeService;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onOpenInventory(InventoryOpenEvent event) {
|
||||
Player player = (Player) event.getPlayer();
|
||||
UUID uniqueId = player.getUniqueId();
|
||||
|
||||
if (!this.fightManager.isInCombat(uniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
InventoryType inventoryType = event.getInventory().getType();
|
||||
|
||||
|
||||
boolean isInRestrictedList = this.config.inventory.restrictedInventoryTypes.contains(inventoryType);
|
||||
boolean shouldBlock = this.config.inventory.inventoryAccessMode.shouldBlock(isInRestrictedList);
|
||||
|
||||
if (shouldBlock) {
|
||||
event.setCancelled(true);
|
||||
|
||||
this.noticeService.create()
|
||||
.player(uniqueId)
|
||||
.notice(this.config.messagesSettings.inventoryBlockedDuringCombat)
|
||||
.send();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package com.eternalcode.combat.fight.blocker;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.config.implementation.BlockPlacementSettings;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.notification.NoticeService;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlaceBlockBlocker implements Listener {
|
||||
|
||||
private final FightManager fightManager;
|
||||
private final NoticeService noticeService;
|
||||
private final PluginConfig config;
|
||||
|
||||
public PlaceBlockBlocker(FightManager fightManager, NoticeService noticeService, PluginConfig config) {
|
||||
this.fightManager = fightManager;
|
||||
this.noticeService = noticeService;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onPlace(BlockPlaceEvent event) {
|
||||
if (!this.config.blockPlacement.disableBlockPlacing) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
UUID uniqueId = player.getUniqueId();
|
||||
|
||||
if (!this.fightManager.isInCombat(uniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Block block = event.getBlock();
|
||||
int level = block.getY();
|
||||
|
||||
List<Material> specificBlocksToPreventPlacing = this.config.blockPlacement.restrictedBlockTypes;
|
||||
|
||||
boolean isPlacementBlocked = this.isPlacementBlocked(level);
|
||||
|
||||
if (isPlacementBlocked && specificBlocksToPreventPlacing.isEmpty()) {
|
||||
event.setCancelled(true);
|
||||
this.noticeService.create()
|
||||
.player(uniqueId)
|
||||
.notice(this.config.messagesSettings.blockPlacingBlockedDuringCombat)
|
||||
.placeholder("{Y}", String.valueOf(this.config.blockPlacement.blockPlacementYCoordinate))
|
||||
.placeholder("{MODE}", this.config.blockPlacement.blockPlacementModeDisplayName)
|
||||
.send();
|
||||
|
||||
}
|
||||
|
||||
Material blockMaterial = block.getType();
|
||||
boolean isBlockInDisabledList = specificBlocksToPreventPlacing.contains(blockMaterial);
|
||||
if (isPlacementBlocked && isBlockInDisabledList) {
|
||||
event.setCancelled(true);
|
||||
|
||||
this.noticeService.create()
|
||||
.player(uniqueId)
|
||||
.notice(this.config.messagesSettings.blockPlacingBlockedDuringCombat)
|
||||
.placeholder("{Y}", String.valueOf(this.config.blockPlacement.blockPlacementYCoordinate))
|
||||
.placeholder("{MODE}", this.config.blockPlacement.blockPlacementModeDisplayName)
|
||||
.send();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPlacementBlocked(int level) {
|
||||
return this.config.blockPlacement.blockPlacementMode == BlockPlacementSettings.BlockPlacingMode.ABOVE
|
||||
? level > this.config.blockPlacement.blockPlacementYCoordinate
|
||||
: level < this.config.blockPlacement.blockPlacementYCoordinate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
package com.eternalcode.combat.fight.controller;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.WhitelistBlacklistMode;
|
||||
import com.eternalcode.combat.config.implementation.BlockPlacementSettings;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.fight.event.FightUntagEvent;
|
||||
import com.eternalcode.combat.notification.NoticeService;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.EntityToggleGlideEvent;
|
||||
import org.bukkit.event.inventory.InventoryOpenEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerToggleFlightEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.util.StringUtil;
|
||||
|
||||
public class FightActionBlockerController implements Listener {
|
||||
|
||||
private final FightManager fightManager;
|
||||
private final NoticeService noticeService;
|
||||
private final PluginConfig config;
|
||||
private final Server server;
|
||||
|
||||
public FightActionBlockerController(FightManager fightManager, NoticeService noticeService, PluginConfig config, Server server) {
|
||||
this.fightManager = fightManager;
|
||||
this.noticeService = noticeService;
|
||||
this.config = config;
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onPlace(BlockPlaceEvent event) {
|
||||
if (!this.config.blockPlacement.disableBlockPlacing) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
UUID uniqueId = player.getUniqueId();
|
||||
|
||||
if (!this.fightManager.isInCombat(uniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Block block = event.getBlock();
|
||||
int level = block.getY();
|
||||
|
||||
List<Material> specificBlocksToPreventPlacing = this.config.blockPlacement.restrictedBlockTypes;
|
||||
|
||||
boolean isPlacementBlocked = this.isPlacementBlocked(level);
|
||||
|
||||
if (isPlacementBlocked && specificBlocksToPreventPlacing.isEmpty()) {
|
||||
event.setCancelled(true);
|
||||
this.noticeService.create()
|
||||
.player(uniqueId)
|
||||
.notice(this.config.messagesSettings.blockPlacingBlockedDuringCombat)
|
||||
.placeholder("{Y}", String.valueOf(this.config.blockPlacement.blockPlacementYCoordinate))
|
||||
.placeholder("{MODE}", this.config.blockPlacement.blockPlacementModeDisplayName)
|
||||
.send();
|
||||
|
||||
}
|
||||
|
||||
Material blockMaterial = block.getType();
|
||||
boolean isBlockInDisabledList = specificBlocksToPreventPlacing.contains(blockMaterial);
|
||||
if (isPlacementBlocked && isBlockInDisabledList) {
|
||||
event.setCancelled(true);
|
||||
|
||||
this.noticeService.create()
|
||||
.player(uniqueId)
|
||||
.notice(this.config.messagesSettings.blockPlacingBlockedDuringCombat)
|
||||
.placeholder("{Y}", String.valueOf(this.config.blockPlacement.blockPlacementYCoordinate))
|
||||
.placeholder("{MODE}", this.config.blockPlacement.blockPlacementModeDisplayName)
|
||||
.send();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPlacementBlocked(int level) {
|
||||
return this.config.blockPlacement.blockPlacementMode == BlockPlacementSettings.BlockPlacingMode.ABOVE
|
||||
? level > this.config.blockPlacement.blockPlacementYCoordinate
|
||||
: level < this.config.blockPlacement.blockPlacementYCoordinate;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onToggleGlide(EntityToggleGlideEvent event) {
|
||||
if (!this.config.combat.disableElytraUsage) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(event.getEntity() instanceof Player player)) {
|
||||
return;
|
||||
}
|
||||
UUID uniqueId = player.getUniqueId();
|
||||
|
||||
if (!this.fightManager.isInCombat(uniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.isGliding()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onMoveWhileGliding(PlayerMoveEvent event) {
|
||||
if (!this.config.combat.disableElytraUsage) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
UUID uniqueId = player.getUniqueId();
|
||||
|
||||
if (!this.fightManager.isInCombat(uniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.isGliding()) {
|
||||
player.setGliding(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@EventHandler
|
||||
void onFly(PlayerToggleFlightEvent event) {
|
||||
if (!this.config.combat.disableFlying) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
UUID uniqueId = player.getUniqueId();
|
||||
|
||||
if (!this.fightManager.isInCombat(uniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.isFlying()) {
|
||||
player.setAllowFlight(false);
|
||||
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onUnTag(FightUntagEvent event) {
|
||||
if (!this.config.combat.disableFlying) {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID uniqueId = event.getPlayer();
|
||||
Player player = this.server.getPlayer(uniqueId);
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
GameMode playerGameMode = player.getGameMode();
|
||||
if (playerGameMode == GameMode.CREATIVE || playerGameMode == GameMode.SPECTATOR) {
|
||||
player.setAllowFlight(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onDamage(EntityDamageEvent event) {
|
||||
if (!this.config.combat.disableElytraOnDamage) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(event.getEntity() instanceof Player player)) {
|
||||
return;
|
||||
}
|
||||
UUID uniqueId = player.getUniqueId();
|
||||
|
||||
if (this.fightManager.isInCombat(uniqueId) && player.isGliding()) {
|
||||
player.setGliding(false);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onOpenInventory(InventoryOpenEvent event) {
|
||||
if (!this.config.combat.disableInventoryAccess) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = (Player) event.getPlayer();
|
||||
UUID uniqueId = player.getUniqueId();
|
||||
|
||||
if (!this.fightManager.isInCombat(uniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.setCancelled(true);
|
||||
|
||||
this.noticeService.create()
|
||||
.player(uniqueId)
|
||||
.notice(this.config.messagesSettings.inventoryBlockedDuringCombat)
|
||||
.send();
|
||||
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
UUID playerUniqueId = player.getUniqueId();
|
||||
|
||||
if (!this.fightManager.isInCombat(playerUniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String command = event.getMessage().substring(1);
|
||||
|
||||
boolean isAnyMatch = this.config.commands.restrictedCommands.stream()
|
||||
.anyMatch(restrictedCommand -> StringUtil.startsWithIgnoreCase(command, restrictedCommand));
|
||||
|
||||
WhitelistBlacklistMode mode = this.config.commands.commandRestrictionMode;
|
||||
|
||||
boolean shouldCancel = mode.shouldBlock(isAnyMatch);
|
||||
|
||||
if (shouldCancel) {
|
||||
event.setCancelled(true);
|
||||
this.noticeService.create()
|
||||
.player(playerUniqueId)
|
||||
.notice(this.config.messagesSettings.commandDisabledDuringCombat)
|
||||
.send();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
package com.eternalcode.combat.fight.death;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.event.CauseOfUnTag;
|
||||
import com.eternalcode.combat.fight.event.FightUntagEvent;
|
||||
import com.eternalcode.commons.scheduler.Scheduler;
|
||||
import java.time.Duration;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.FireworkEffect;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Firework;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.inventory.meta.FireworkMeta;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class DeathFlareController implements Listener {
|
||||
|
||||
private final PluginConfig pluginConfig;
|
||||
private final Server server;
|
||||
private final Scheduler scheduler;
|
||||
private final NamespacedKey key;
|
||||
|
||||
public DeathFlareController(PluginConfig pluginConfig, Server server, Scheduler scheduler, Plugin plugin) {
|
||||
this.pluginConfig = pluginConfig;
|
||||
this.server = server;
|
||||
this.scheduler = scheduler;
|
||||
this.key = NamespacedKey.fromString("eternalcombat_firework", plugin);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onFightUntagEvent(FightUntagEvent event) {
|
||||
CauseOfUnTag cause = event.getCause();
|
||||
if (cause != CauseOfUnTag.DEATH && cause != CauseOfUnTag.DEATH_BY_PLAYER) {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID uniqueId = event.getPlayer();
|
||||
Player player = this.server.getPlayer(uniqueId);
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.pluginConfig.death.firework.inCombat && !this.pluginConfig.death.firework.afterEveryDeath) {
|
||||
this.spawnFlare(player);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onPlayerDeathEventFlare(PlayerDeathEvent event) {
|
||||
Player player = event.getEntity();
|
||||
|
||||
if (this.pluginConfig.death.firework.afterEveryDeath) {
|
||||
this.spawnFlare(player);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
|
||||
if (event.getDamager() instanceof Firework firework && firework.getPersistentDataContainer().has(key, PersistentDataType.STRING)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void spawnFlare(Player player) {
|
||||
Location deathLocation = player.getLocation();
|
||||
World world = deathLocation.getWorld();
|
||||
|
||||
Firework flare = world.spawn(deathLocation, Firework.class);
|
||||
flare.getPersistentDataContainer().set(key, PersistentDataType.STRING, "true");
|
||||
|
||||
FireworkMeta meta = flare.getFireworkMeta();
|
||||
|
||||
Color primaryColor = this.decodeColor(this.pluginConfig.death.firework.primaryColor, "primary");
|
||||
Color fadeColor = this.decodeColor(this.pluginConfig.death.firework.fadeColor, "fade");
|
||||
|
||||
FireworkEffect effect = FireworkEffect.builder()
|
||||
.with(this.pluginConfig.death.firework.fireworkType)
|
||||
.withColor(primaryColor)
|
||||
.withFade(fadeColor)
|
||||
.trail(true)
|
||||
.flicker(true)
|
||||
.build();
|
||||
|
||||
meta.addEffect(effect);
|
||||
meta.setPower(this.pluginConfig.death.firework.power);
|
||||
flare.setFireworkMeta(meta);
|
||||
|
||||
if (this.pluginConfig.death.firework.particlesEnabled) {
|
||||
scheduleParticles(flare, world);
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleParticles(Firework flare, World world) {
|
||||
this.scheduler.runLaterAsync(
|
||||
() -> {
|
||||
if (flare.isDead() || !flare.isValid()) {
|
||||
return;
|
||||
}
|
||||
this.spawnParticles(world, flare);
|
||||
this.scheduleParticles(flare, world);
|
||||
}, Duration.ofMillis(50)
|
||||
);
|
||||
}
|
||||
|
||||
private Color decodeColor(String firework, String name) {
|
||||
try {
|
||||
return Color.fromRGB(Integer.decode(firework));
|
||||
}
|
||||
catch (NumberFormatException exception) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid " + name + " format in plugin configuration" + firework,
|
||||
exception
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void spawnParticles(World world, Firework flare) {
|
||||
Location location = flare.getLocation();
|
||||
|
||||
world.spawnParticle(
|
||||
this.pluginConfig.death.firework.mainParticle.get(),
|
||||
location,
|
||||
this.pluginConfig.death.firework.mainParticleCount,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.01
|
||||
);
|
||||
|
||||
world.spawnParticle(
|
||||
this.pluginConfig.death.firework.secondaryParticle.get(),
|
||||
location,
|
||||
this.pluginConfig.death.firework.secondaryParticleCount,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.01
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.eternalcode.combat.fight.death;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.event.CauseOfUnTag;
|
||||
import com.eternalcode.combat.fight.event.FightUntagEvent;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
|
||||
public class DeathLightningController implements Listener {
|
||||
|
||||
private final PluginConfig pluginConfig;
|
||||
private final Server server;
|
||||
|
||||
public DeathLightningController(PluginConfig pluginConfig, Server server) {
|
||||
this.pluginConfig = pluginConfig;
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onFightUntagEvent(FightUntagEvent event) {
|
||||
CauseOfUnTag cause = event.getCause();
|
||||
if (cause != CauseOfUnTag.DEATH && cause != CauseOfUnTag.DEATH_BY_PLAYER) {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID uniqueId = event.getPlayer();
|
||||
Player player = this.server.getPlayer(uniqueId);
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.pluginConfig.death.lightning.inCombat && !this.pluginConfig.death.lightning.afterEveryDeath) {
|
||||
this.lightningStrike(player);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onPlayerDeathEventLightning(PlayerDeathEvent event) {
|
||||
Player player = event.getEntity();
|
||||
|
||||
if (this.pluginConfig.death.lightning.afterEveryDeath) {
|
||||
lightningStrike(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void lightningStrike(Player player) {
|
||||
player.getWorld().strikeLightningEffect(player.getLocation());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package com.eternalcode.combat.fight.death;
|
||||
|
||||
import com.cryptomorin.xseries.particles.XParticle;
|
||||
import eu.okaeri.configs.OkaeriConfig;
|
||||
import eu.okaeri.configs.annotation.Comment;
|
||||
import org.bukkit.FireworkEffect;
|
||||
|
||||
public class DeathSettings extends OkaeriConfig {
|
||||
|
||||
@Comment({
|
||||
"Settings related to lightning effect upon death",
|
||||
"Setting both afterEveryDeath and inCombat to false will disable this feature completely"
|
||||
})
|
||||
public LightningSettings lightning = new LightningSettings();
|
||||
|
||||
public static class LightningSettings extends OkaeriConfig {
|
||||
|
||||
@Comment("Should lightning spawn on every death?")
|
||||
public boolean afterEveryDeath = false;
|
||||
|
||||
@Comment("Should lightning spawn on ONLY deaths in combat?")
|
||||
public boolean inCombat = true;
|
||||
}
|
||||
|
||||
@Comment({
|
||||
"Settings for the Arc Raiders style flare (firework)",
|
||||
"Setting both afterEveryDeath and inCombat to false will disable this feature completely"
|
||||
})
|
||||
public FlareSettings firework = new FlareSettings();
|
||||
|
||||
public static class FlareSettings extends OkaeriConfig {
|
||||
|
||||
@Comment("Should firework (flare) spawn on every death?")
|
||||
public boolean afterEveryDeath = false;
|
||||
|
||||
@Comment("Should firework (flare) spawn on ONLY deaths in combat?")
|
||||
public boolean inCombat = false;
|
||||
|
||||
@Comment("Power of firework - how long till explosion (please enter positive number)")
|
||||
public int power = 2;
|
||||
|
||||
@Comment({
|
||||
"The firework (flare) effect type (BALL, BALL_LARGE, STAR, BURST, CREEPER)",
|
||||
"Reference: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/FireworkEffect.Type.html"
|
||||
})
|
||||
public FireworkEffect.Type fireworkType = FireworkEffect.Type.BALL;
|
||||
|
||||
@Comment("Hex color for the firework (flare)")
|
||||
public String primaryColor = "#a80022";
|
||||
|
||||
@Comment("Hex color for the fade of firework (flare)")
|
||||
public String fadeColor = "#0a0a0a";
|
||||
|
||||
@Comment("Toggle on/off additional particles spawned in the firework (flare) path")
|
||||
public boolean particlesEnabled = true;
|
||||
|
||||
@Comment({
|
||||
"The main trail particle (e.g., CAMPFIRE_COSY_SMOKE, SMOKE_LARGE)",
|
||||
"Reference: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Particle.html"
|
||||
})
|
||||
public XParticle mainParticle = XParticle.CAMPFIRE_COSY_SMOKE;
|
||||
|
||||
@Comment("Count of main particles spawned on each tick")
|
||||
public int mainParticleCount = 3;
|
||||
|
||||
@Comment({
|
||||
"The secondary trail particle (e.g., CAMPFIRE_COSY_SMOKE, SMOKE_LARGE)",
|
||||
"Reference: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Particle.html"
|
||||
})
|
||||
|
||||
public XParticle secondaryParticle = XParticle.SMALL_FLAME;
|
||||
|
||||
@Comment("Count of secondary particles spawned on each tick")
|
||||
public int secondaryParticleCount = 3;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -47,11 +47,15 @@ public class DropController implements DynamicListener<PlayerDeathEvent> {
|
||||
DropType dropType = this.dropSettings.dropType;
|
||||
boolean inCombat = this.fightManager.isInCombat(uuid);
|
||||
|
||||
if (dropType == DropType.UNCHANGED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (shouldHeadDrop(inCombat)) {
|
||||
addHeadDrop(event, player);
|
||||
}
|
||||
|
||||
if (dropType == DropType.UNCHANGED || !inCombat) {
|
||||
if (!inCombat) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.fight.event.CauseOfUnTag;
|
||||
import com.eternalcode.combat.fight.event.FightTagEvent;
|
||||
import com.eternalcode.combat.fight.event.FightUntagEvent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -49,11 +50,9 @@ public class FightEffectController implements Listener {
|
||||
}
|
||||
|
||||
if (event.getCause() == CauseOfUnTag.LOGOUT) {
|
||||
Player player = this.server.getPlayer(event.getPlayer());
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
Player player = Bukkit.getPlayer(event.getPlayer());
|
||||
|
||||
assert player != null;
|
||||
this.effectService.clearStoredEffects(player);
|
||||
}
|
||||
}
|
||||
@@ -81,11 +80,9 @@ public class FightEffectController implements Listener {
|
||||
return;
|
||||
}
|
||||
if (event.getCause() == CauseOfUnTag.DEATH_BY_PLAYER || event.getCause() == CauseOfUnTag.DEATH) {
|
||||
Player player = this.server.getPlayer(event.getPlayer());
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
Player player = Bukkit.getPlayer(event.getPlayer());
|
||||
|
||||
assert player != null;
|
||||
this.effectService.clearStoredEffects(player);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package com.eternalcode.combat.fight.effect;
|
||||
|
||||
import com.cryptomorin.xseries.XPotion;
|
||||
import eu.okaeri.configs.OkaeriConfig;
|
||||
import eu.okaeri.configs.annotation.Comment;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class FightEffectSettings extends OkaeriConfig {
|
||||
|
||||
@Comment({"# Do you want to add effects to players in combat?"})
|
||||
@@ -15,20 +16,11 @@ public class FightEffectSettings extends OkaeriConfig {
|
||||
"# If the option above is set to true, you can add effects to players in combat below",
|
||||
"# You can find a list of all potion effects here: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/potion/PotionEffectType.html",
|
||||
"# Correct format: 'EFFECT_TYPE:AMPLIFIER' Amplifier strength starts from 0, so level 1 gives effect strength 2",
|
||||
"# Example: SPEED:1, RESISTANCE:0",
|
||||
"# Example: SPEED:1, DAMAGE_RESISTANCE:0",
|
||||
})
|
||||
public Map<PotionEffectType, Integer> customEffects = Map.of(
|
||||
requirePotionEffectType(XPotion.SPEED), 1,
|
||||
requirePotionEffectType(XPotion.RESISTANCE), 0
|
||||
PotionEffectType.SPEED, 1,
|
||||
PotionEffectType.DAMAGE_RESISTANCE, 0
|
||||
);
|
||||
|
||||
private static PotionEffectType requirePotionEffectType(XPotion potion) {
|
||||
PotionEffectType potionEffectType = potion.get();
|
||||
if (potionEffectType == null) {
|
||||
throw new IllegalStateException("Potion effect " + potion.name() + " is not supported by this server version");
|
||||
}
|
||||
|
||||
return potionEffectType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,21 +3,53 @@ package com.eternalcode.combat.fight.knockback;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Function;
|
||||
import org.bukkit.Location;
|
||||
|
||||
class KnockbackOutsideRegionGenerator {
|
||||
|
||||
static Optional<Location> generate(Point2D min, Point2D max, Location playerLocation, Function<Location, Optional<Location>> safeMapper) {
|
||||
return generatePoints(min, max, Point2D.from(playerLocation)).entrySet().stream()
|
||||
.flatMap(entry -> entry.getValue().stream())
|
||||
.map(point2D -> point2D.toLocation(playerLocation))
|
||||
.flatMap(safeMapper.andThen(validPoint -> validPoint.stream()))
|
||||
.findFirst();
|
||||
static Location generate(Point2D min, Point2D max, Location playerLocation) {
|
||||
NavigableMap<Double, List<Point2D>> points = generatePoints(min, max, Point2D.from(playerLocation));
|
||||
NavigableMap<Double, Double> distances = new TreeMap<>();
|
||||
double totalWeight = 0;
|
||||
|
||||
Double maxDistance = points.lastKey();
|
||||
|
||||
for (double distance : points.keySet()) {
|
||||
double weight = createWeight(distance, maxDistance);
|
||||
distances.put(distance, weight);
|
||||
totalWeight += weight;
|
||||
}
|
||||
|
||||
double rand = Math.random() * totalWeight;
|
||||
double cumulativeWeight = 0;
|
||||
|
||||
for (Map.Entry<Double, Double> entry : distances.entrySet()) {
|
||||
double distance = entry.getKey();
|
||||
double weight = entry.getValue();
|
||||
|
||||
cumulativeWeight += weight;
|
||||
if (rand <= cumulativeWeight) {
|
||||
return getRandom(points.get(distance))
|
||||
.toLocation(playerLocation);
|
||||
}
|
||||
}
|
||||
|
||||
return getRandom(points.firstEntry().getValue())
|
||||
.toLocation(playerLocation);
|
||||
}
|
||||
|
||||
private static Point2D getRandom(List<Point2D> points) {
|
||||
return points.get((int) (Math.random() * points.size()));
|
||||
}
|
||||
|
||||
private static double createWeight(double distance, double maxDistance) {
|
||||
double last = Math.log(maxDistance);
|
||||
double weight = last - Math.log(distance);
|
||||
return Math.pow(weight, 10);
|
||||
}
|
||||
|
||||
private static NavigableMap<Double, List<Point2D>> generatePoints(Point2D min, Point2D max, Point2D location) {
|
||||
@@ -46,4 +78,5 @@ class KnockbackOutsideRegionGenerator {
|
||||
return Math.sqrt(Math.pow(p2.x() - p1.x(), 2) + Math.pow(p2.z() - p1.z(), 2));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -9,15 +9,12 @@ import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.event.vehicle.VehicleMoveEvent;
|
||||
import org.spigotmc.event.entity.EntityMountEvent;
|
||||
|
||||
public class KnockbackRegionController implements Listener {
|
||||
|
||||
@@ -92,67 +89,6 @@ public class KnockbackRegionController implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
void onVehicleMove(VehicleMoveEvent event) {
|
||||
Location locationTo = event.getTo();
|
||||
Location locationFrom = event.getFrom();
|
||||
|
||||
if (locationTo.getBlockX() == locationFrom.getBlockX()
|
||||
&& locationTo.getBlockY() == locationFrom.getBlockY()
|
||||
&& locationTo.getBlockZ() == locationFrom.getBlockZ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Entity passenger : event.getVehicle().getPassengers()) {
|
||||
if (!(passenger instanceof Player player)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.fightManager.isInCombat(player.getUniqueId())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Optional<Region> regionOptional = this.regionProvider.getRegion(locationTo);
|
||||
if (regionOptional.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Region region = regionOptional.get();
|
||||
if (region.contains(locationFrom)) {
|
||||
this.knockbackService.knockback(region, player);
|
||||
this.knockbackService.forceKnockbackLater(player, region);
|
||||
} else {
|
||||
this.knockbackService.knockbackLater(region, player, Duration.ofMillis(50));
|
||||
}
|
||||
|
||||
this.noticeService.create()
|
||||
.player(player.getUniqueId())
|
||||
.notice(config -> config.messagesSettings.cantEnterOnRegion)
|
||||
.send();
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
void onEntityMount(EntityMountEvent event) {
|
||||
if (!(event.getEntity() instanceof Player player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.fightManager.isInCombat(player.getUniqueId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.regionProvider.isInRegion(event.getMount().getLocation())) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.setCancelled(true);
|
||||
this.noticeService.create()
|
||||
.player(player.getUniqueId())
|
||||
.notice(config -> config.messagesSettings.cantEnterOnRegion)
|
||||
.send();
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
void onTag(FightTagEvent event) {
|
||||
Player player = this.server.getPlayer(event.getPlayer());
|
||||
|
||||
@@ -1,29 +1,23 @@
|
||||
package com.eternalcode.combat.fight.knockback;
|
||||
|
||||
import com.cryptomorin.xseries.XMaterial;
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.region.Point;
|
||||
import com.eternalcode.combat.region.Region;
|
||||
import com.eternalcode.combat.region.RegionProvider;
|
||||
import com.eternalcode.commons.bukkit.scheduler.MinecraftScheduler;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public final class KnockbackService {
|
||||
|
||||
private static final int FORCE_TELEPORT_MAX_ATTEMPTS = 10;
|
||||
private static final double KNOCKBACK_DAMPEN_FACTOR = 0.8;
|
||||
public static final int DEPTH_OF_SEARCHING = 10;
|
||||
|
||||
private final PluginConfig config;
|
||||
private final MinecraftScheduler scheduler;
|
||||
private final RegionProvider regionProvider;
|
||||
@@ -37,141 +31,50 @@ public final class KnockbackService {
|
||||
}
|
||||
|
||||
public void knockbackLater(Region region, Player player, Duration duration) {
|
||||
scheduler.runLater(() -> this.knockback(region, player), duration);
|
||||
}
|
||||
|
||||
public void knockback(Region region, Player player) {
|
||||
if (player.isInsideVehicle()) {
|
||||
player.leaveVehicle();
|
||||
}
|
||||
|
||||
Location currentLocation = player.getLocation();
|
||||
Vector shortestDirection = getShortestDirectionToEdge(region, currentLocation);
|
||||
|
||||
// Reduces player's current velocity BEFORE applying knockback. Helps create a smoother and more consistent knockback.
|
||||
player.setVelocity(player.getVelocity().multiply(KNOCKBACK_DAMPEN_FACTOR));
|
||||
|
||||
double y = Math.min(player.getVelocity().getY(), config.knockback.vertical);
|
||||
Vector velocity = shortestDirection.multiply(config.knockback.multiplier).setY(y);
|
||||
|
||||
player.setFallDistance(0);
|
||||
player.setVelocity(velocity);
|
||||
}
|
||||
|
||||
private Vector getShortestDirectionToEdge(Region region, Location current) {
|
||||
double directionToBottomEdge = current.getX() - region.getMin().getX();
|
||||
double directionToTopEdge = region.getMax().getX() - current.getX();
|
||||
double directionToLeftEdge = current.getZ() - region.getMin().getZ();
|
||||
double directionToRightEdge = region.getMax().getZ() - current.getZ();
|
||||
|
||||
double shortestDirection = Math.min(
|
||||
Math.min(directionToBottomEdge, directionToTopEdge),
|
||||
Math.min(directionToLeftEdge, directionToRightEdge)
|
||||
);
|
||||
|
||||
if (shortestDirection == directionToBottomEdge)
|
||||
return new Vector(-1, 0, 0);
|
||||
if (shortestDirection == directionToTopEdge)
|
||||
return new Vector(1, 0, 0);
|
||||
if (shortestDirection == directionToLeftEdge)
|
||||
return new Vector(0, 0, -1);
|
||||
if (shortestDirection == directionToRightEdge)
|
||||
return new Vector(0, 0, 1);
|
||||
throw new IllegalStateException("Failed to determine direction to edge");
|
||||
this.scheduler.runLater(() -> this.knockback(region, player), duration);
|
||||
}
|
||||
|
||||
public void forceKnockbackLater(Player player, Region region) {
|
||||
UUID playerId = player.getUniqueId();
|
||||
|
||||
if (insideRegion.containsKey(playerId)) {
|
||||
if (insideRegion.containsKey(player.getUniqueId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
insideRegion.put(playerId, region);
|
||||
insideRegion.put(player.getUniqueId(), region);
|
||||
|
||||
scheduler.runLater(player.getLocation(), () -> {
|
||||
insideRegion.remove(playerId);
|
||||
scheduler.runLater(
|
||||
player.getLocation(), () -> {
|
||||
insideRegion.remove(player.getUniqueId());
|
||||
Location playerLocation = player.getLocation();
|
||||
if (!region.contains(playerLocation) && !regionProvider.isInRegion(playerLocation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Location playerLocation = player.getLocation();
|
||||
Location location =
|
||||
generate(playerLocation, Point2D.from(region.getMin()), Point2D.from(region.getMax()));
|
||||
|
||||
if (!region.contains(playerLocation) && !regionProvider.isInRegion(playerLocation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.isInsideVehicle()) {
|
||||
player.leaveVehicle();
|
||||
}
|
||||
|
||||
generate(playerLocation, Point2D.from(region.getMin()), Point2D.from(region.getMax()), 0)
|
||||
.ifPresent(location -> player.teleportAsync(location, TeleportCause.PLUGIN));
|
||||
}, config.knockback.forceTeleport.delay);
|
||||
PaperLib.teleportAsync(player, location, TeleportCause.PLUGIN);
|
||||
}, this.config.knockback.forceDelay);
|
||||
}
|
||||
|
||||
private Optional<Location> generate(Location playerLocation, Point2D min, Point2D max, int attempts) {
|
||||
if (attempts >= FORCE_TELEPORT_MAX_ATTEMPTS) {
|
||||
return Optional.of(playerLocation);
|
||||
}
|
||||
|
||||
Optional<Location> location = KnockbackOutsideRegionGenerator.generate(min, max, playerLocation, candidate -> makeSafe(candidate));
|
||||
if (location.isEmpty()) {
|
||||
int expand = (attempts + 1) * (attempts + 1);
|
||||
return generate(playerLocation, min.expandMin(expand, expand), max.expandMax(expand, expand), attempts + 1);
|
||||
}
|
||||
|
||||
Optional<Region> otherRegion = regionProvider.getRegion(location.get());
|
||||
private Location generate(Location playerLocation, Point2D minX, Point2D maxX) {
|
||||
Location location = KnockbackOutsideRegionGenerator.generate(minX, maxX, playerLocation);
|
||||
Optional<Region> otherRegion = regionProvider.getRegion(location);
|
||||
if (otherRegion.isPresent()) {
|
||||
Region region = otherRegion.get();
|
||||
return generate(playerLocation, min.min(region.getMin()), max.max(region.getMax()), attempts + 1);
|
||||
return generate(playerLocation, minX.min(region.getMin()), maxX.max(region.getMax()));
|
||||
}
|
||||
|
||||
return location.map(loc -> loc.add(0.5, 0, 0.5));
|
||||
return location;
|
||||
}
|
||||
|
||||
private Optional<Location> makeSafe(Location random) {
|
||||
Location maybeSafe = random.clone();
|
||||
int minY = maybeSafe.getBlockY() - DEPTH_OF_SEARCHING;
|
||||
public void knockback(Region region, Player player) {
|
||||
Point point = region.getCenter();
|
||||
Location subtract = player.getLocation().subtract(point.x(), 0, point.z());
|
||||
|
||||
CachedPillarOfBlocks pillar = new CachedPillarOfBlocks(maybeSafe.getBlockX(), maybeSafe.getBlockZ(), maybeSafe.getWorld());
|
||||
Vector knockbackVector = new Vector(subtract.getX(), 0, subtract.getZ()).normalize();
|
||||
double multiplier = this.config.knockback.multiplier;
|
||||
Vector configuredVector = new Vector(multiplier, 0.5, multiplier);
|
||||
|
||||
for (int y = maybeSafe.getBlockY(); y > minY; y--) {
|
||||
maybeSafe.setY(y);
|
||||
|
||||
Material ground = pillar.get(maybeSafe.getBlockY() - 1);
|
||||
Material legs = pillar.get(maybeSafe.getBlockY());
|
||||
Material head = pillar.get(maybeSafe.getBlockY() + 1);
|
||||
|
||||
if (ground.isSolid()
|
||||
&& !containsMaterial(config.knockback.forceTeleport.unsafeGroundBlocks, ground)
|
||||
&& containsMaterial(config.knockback.forceTeleport.airBlocks, legs)
|
||||
&& containsMaterial(config.knockback.forceTeleport.airBlocks, head)
|
||||
) {
|
||||
return Optional.of(maybeSafe);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
player.setVelocity(knockbackVector.multiply(configuredVector));
|
||||
}
|
||||
|
||||
private boolean containsMaterial(Set<XMaterial> materials, Material material) {
|
||||
return materials.contains(XMaterial.matchXMaterial(material));
|
||||
}
|
||||
|
||||
private static class CachedPillarOfBlocks {
|
||||
|
||||
private final int x;
|
||||
private final int z;
|
||||
private final World world;
|
||||
private final Map<Integer, Material> blocksTypes = new HashMap<>();
|
||||
|
||||
private CachedPillarOfBlocks(int x, int z, World world) {
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public Material get(int y) {
|
||||
return this.blocksTypes.computeIfAbsent(y, __ -> world.getType(x, y, z));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,138 +1,19 @@
|
||||
package com.eternalcode.combat.fight.knockback;
|
||||
|
||||
import com.cryptomorin.xseries.XMaterial;
|
||||
import eu.okaeri.configs.OkaeriConfig;
|
||||
import eu.okaeri.configs.annotation.Comment;
|
||||
import java.time.Duration;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class KnockbackSettings extends OkaeriConfig {
|
||||
|
||||
@Comment({
|
||||
"# Horizontal knockback strength multiplier.",
|
||||
"# This controls how far the player is pushed horizontally.",
|
||||
"#",
|
||||
"# Applied in: direction.multiply(multiplier)",
|
||||
"# Example: 1.0 ≈ 2–4 blocks push"
|
||||
"# Adjust the knockback multiplier for restricted regions.",
|
||||
"# Higher values increase the knockback distance. Avoid using negative values.",
|
||||
"# A value of 1.0 typically knocks players 2-4 blocks away."
|
||||
})
|
||||
public double multiplier = 1.0;
|
||||
|
||||
@Comment({
|
||||
"# Vertical velocity applied when the player is considered on ground.",
|
||||
"#",
|
||||
"# Used when Y velocity is near zero (< 0.08).",
|
||||
"# Higher values = more upward knockback.",
|
||||
"# Recommended: 0.15 - 0.3"
|
||||
})
|
||||
public double vertical = 0.2;
|
||||
|
||||
@Comment({
|
||||
"# Force teleport settings for players that fail to be knocked back outside the region.",
|
||||
"# If a player cannot be knocked back outside the region after multiple attempts,",
|
||||
"# they will be teleported to a safe location outside the region after a short delay.",
|
||||
"# This ensures players don't get stuck inside the region due to knockback failures."
|
||||
})
|
||||
public ForceTeleport forceTeleport = new ForceTeleport();
|
||||
|
||||
public static class ForceTeleport extends OkaeriConfig {
|
||||
|
||||
@Comment({
|
||||
"# Delay before force teleport is applied after entering a region.",
|
||||
"# Recommended: 1-3 seconds to allow knockback attempts before teleporting.",
|
||||
})
|
||||
public Duration delay = Duration.ofSeconds(1);
|
||||
|
||||
@Comment({
|
||||
"# Blocks that are considered unsafe to stand on when searching for ground.",
|
||||
"# These blocks will be ignored during safe ground detection.",
|
||||
"#",
|
||||
"# Used in findSafeGround():",
|
||||
"# - Skips these blocks even if they are solid",
|
||||
"# - Prevents teleporting onto dangerous or invalid blocks",
|
||||
"#",
|
||||
"# Examples:",
|
||||
"# - BARRIER (invisible collision)",
|
||||
"# - LAVA / WATER (damage / movement issues)",
|
||||
"# - CACTUS / MAGMA (damage blocks)",
|
||||
})
|
||||
public Set<XMaterial> unsafeGroundBlocks = EnumSet.of(
|
||||
XMaterial.BARRIER,
|
||||
XMaterial.LAVA,
|
||||
XMaterial.WATER,
|
||||
XMaterial.CACTUS,
|
||||
XMaterial.MAGMA_BLOCK,
|
||||
XMaterial.FIRE,
|
||||
XMaterial.SOUL_FIRE,
|
||||
XMaterial.COBWEB,
|
||||
XMaterial.SWEET_BERRY_BUSH,
|
||||
XMaterial.BEDROCK,
|
||||
XMaterial.TNT,
|
||||
XMaterial.SEAGRASS,
|
||||
XMaterial.TALL_SEAGRASS,
|
||||
XMaterial.BUBBLE_COLUMN,
|
||||
XMaterial.POWDER_SNOW,
|
||||
XMaterial.WITHER_ROSE
|
||||
);
|
||||
|
||||
@Comment({
|
||||
"# Safe blocks that players can be teleported into",
|
||||
"# These blocks don't cause damage and allow free movement",
|
||||
"# Players can safely spawn in these blocks or pass through them",
|
||||
"# Includes air, grass, flowers, and other non-solid blocks"
|
||||
})
|
||||
public Set<XMaterial> airBlocks = EnumSet.of(
|
||||
XMaterial.AIR,
|
||||
XMaterial.CAVE_AIR,
|
||||
XMaterial.VOID_AIR,
|
||||
XMaterial.TALL_SEAGRASS,
|
||||
XMaterial.SEAGRASS,
|
||||
XMaterial.SHORT_GRASS,
|
||||
XMaterial.TALL_GRASS,
|
||||
XMaterial.VINE,
|
||||
XMaterial.STRUCTURE_VOID,
|
||||
XMaterial.DEAD_BUSH,
|
||||
XMaterial.DANDELION,
|
||||
XMaterial.POPPY,
|
||||
XMaterial.BLUE_ORCHID,
|
||||
XMaterial.ALLIUM,
|
||||
XMaterial.AZURE_BLUET,
|
||||
XMaterial.RED_TULIP,
|
||||
XMaterial.ORANGE_TULIP,
|
||||
XMaterial.WHITE_TULIP,
|
||||
XMaterial.PINK_TULIP,
|
||||
XMaterial.OXEYE_DAISY,
|
||||
XMaterial.CORNFLOWER,
|
||||
XMaterial.LILY_OF_THE_VALLEY,
|
||||
XMaterial.SUNFLOWER,
|
||||
XMaterial.LILAC,
|
||||
XMaterial.ROSE_BUSH,
|
||||
XMaterial.PEONY,
|
||||
XMaterial.WITHER_ROSE,
|
||||
XMaterial.LARGE_FERN,
|
||||
XMaterial.RAIL,
|
||||
XMaterial.POWERED_RAIL,
|
||||
XMaterial.DETECTOR_RAIL,
|
||||
XMaterial.ACTIVATOR_RAIL,
|
||||
XMaterial.REDSTONE_WIRE,
|
||||
XMaterial.COMPARATOR,
|
||||
XMaterial.REPEATER,
|
||||
XMaterial.LEVER,
|
||||
XMaterial.STRING,
|
||||
XMaterial.SNOW,
|
||||
XMaterial.CRIMSON_ROOTS,
|
||||
XMaterial.WARPED_ROOTS,
|
||||
XMaterial.CRIMSON_FUNGUS,
|
||||
XMaterial.WARPED_FUNGUS,
|
||||
XMaterial.TORCH,
|
||||
XMaterial.WALL_TORCH,
|
||||
XMaterial.REDSTONE_TORCH,
|
||||
XMaterial.REDSTONE_WALL_TORCH,
|
||||
XMaterial.SOUL_TORCH,
|
||||
XMaterial.SOUL_WALL_TORCH
|
||||
);
|
||||
|
||||
}
|
||||
public double multiplier = 1;
|
||||
|
||||
@Comment({ "# Time after which the player will be force knocked back outside the safe zone" })
|
||||
public Duration forceDelay = Duration.ofSeconds(1);
|
||||
|
||||
}
|
||||
@@ -5,13 +5,11 @@ import org.bukkit.World;
|
||||
|
||||
record Point2D(int x, int z) {
|
||||
|
||||
Location toLocation(Location playerLocation) {
|
||||
World world = playerLocation.getWorld();
|
||||
int y = world.getEnvironment() == World.Environment.NETHER
|
||||
? playerLocation.getBlockY() + 1
|
||||
: world.getHighestBlockYAt(x, z) + 1;
|
||||
Location toLocation(Location location) {
|
||||
World world = location.getWorld();
|
||||
int y = world.getHighestBlockYAt(x, z) + 1;
|
||||
|
||||
return new Location(world, x, y, z, playerLocation.getYaw(), playerLocation.getPitch());
|
||||
return new Location(world, x, y, z, location.getYaw(), location.getPitch());
|
||||
}
|
||||
|
||||
static Point2D from(Location location) {
|
||||
@@ -26,12 +24,4 @@ record Point2D(int x, int z) {
|
||||
return new Point2D(Math.max(this.x, max.getBlockX()), Math.max(this.z, max.getBlockZ()));
|
||||
}
|
||||
|
||||
public Point2D expandMax(int x, int z) {
|
||||
return new Point2D(this.x + x, this.z + z);
|
||||
}
|
||||
|
||||
public Point2D expandMin(int x, int z) {
|
||||
return new Point2D(this.x - x, this.z - z);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.eternalcode.combat.fight.pearl;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.notification.NoticeService;
|
||||
import com.eternalcode.combat.util.DurationUtil;
|
||||
import java.time.Duration;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.EnderPearl;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -14,26 +14,28 @@ import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.ProjectileLaunchEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class PearlController implements Listener {
|
||||
public class FightPearlController implements Listener {
|
||||
|
||||
private final PluginConfig pluginConfig;
|
||||
private final PearlService pearlService;
|
||||
private final FightPearlSettings settings;
|
||||
private final NoticeService noticeService;
|
||||
private final FightManager fightManager;
|
||||
private final FightPearlService fightPearlService;
|
||||
|
||||
public PearlController(
|
||||
PluginConfig pluginConfig,
|
||||
PearlService pearlService, NoticeService noticeService, FightManager fightManager
|
||||
public FightPearlController(
|
||||
FightPearlSettings settings,
|
||||
NoticeService noticeService,
|
||||
FightManager fightManager,
|
||||
FightPearlService fightPearlService
|
||||
) {
|
||||
this.pluginConfig = pluginConfig;
|
||||
this.pearlService = pearlService;
|
||||
this.settings = settings;
|
||||
this.noticeService = noticeService;
|
||||
this.fightManager = fightManager;
|
||||
this.fightPearlService = fightPearlService;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPearlThrow(ProjectileLaunchEvent event) {
|
||||
if (!(event.getEntity() instanceof EnderPearl)) {
|
||||
return;
|
||||
@@ -45,68 +47,58 @@ public class PearlController implements Listener {
|
||||
|
||||
UUID playerId = player.getUniqueId();
|
||||
|
||||
if (this.pearlService.shouldCancelEvent(playerId)) {
|
||||
event.setCancelled(true);
|
||||
|
||||
if (this.pluginConfig.pearl.pearlThrowDisabledDuringCombat) {
|
||||
this.noticeService.create()
|
||||
.player(playerId)
|
||||
.notice(this.pluginConfig.pearl.pearlThrowBlockedDuringCombat)
|
||||
.send();
|
||||
return;
|
||||
}
|
||||
|
||||
Duration remainingDelay = this.pearlService.getRemainingDelay(playerId);
|
||||
this.noticeService.create()
|
||||
.player(playerId)
|
||||
.notice(this.pluginConfig.pearl.pearlThrowBlockedDelayDuringCombat)
|
||||
.placeholder("{TIME}", DurationUtil.format(remainingDelay))
|
||||
.send();
|
||||
|
||||
if (!this.fightManager.isInCombat(playerId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pearlService.handleDelay(player);
|
||||
if (this.settings.pearlThrowDisabledDuringCombat) {
|
||||
event.setCancelled(true);
|
||||
this.noticeService.create()
|
||||
.player(playerId)
|
||||
.notice(this.settings.pearlThrowBlockedDuringCombat)
|
||||
.send();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.settings.pearlCooldownEnabled) {
|
||||
handlePearlCooldown(event, player, playerId);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onPearlDamage(EntityDamageByEntityEvent event) {
|
||||
if (this.pluginConfig.pearl.pearlThrowDamageEnabled) {
|
||||
if (this.settings.pearlThrowDamageEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(event.getEntity() instanceof Player) ||
|
||||
!(event.getDamager() instanceof EnderPearl) ||
|
||||
event.getCause() != EntityDamageEvent.DamageCause.PROJECTILE) {
|
||||
event.getCause() != EntityDamageEvent.DamageCause.FALL) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.setDamage(0.0);
|
||||
}
|
||||
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPearlTeleport(PlayerTeleportEvent event) {
|
||||
if (event.getCause() != PlayerTeleportEvent.TeleportCause.ENDER_PEARL) {
|
||||
private void handlePearlCooldown(ProjectileLaunchEvent event, Player player, UUID playerId) {
|
||||
if (this.settings.pearlThrowDelay.isZero()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.pluginConfig.pearl.pearlThrowDisabledDuringCombat) {
|
||||
if (this.fightPearlService.hasDelay(playerId)) {
|
||||
event.setCancelled(true);
|
||||
Duration remainingDelay = this.fightPearlService.getRemainingDelay(playerId);
|
||||
|
||||
this.noticeService.create()
|
||||
.player(playerId)
|
||||
.notice(this.settings.pearlThrowBlockedDelayDuringCombat)
|
||||
.placeholder("{TIME}", DurationUtil.format(remainingDelay))
|
||||
.send();
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
UUID playerId = player.getUniqueId();
|
||||
|
||||
if (!this.fightManager.isInCombat(playerId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.setCancelled(true);
|
||||
|
||||
this.noticeService.create()
|
||||
.player(playerId)
|
||||
.notice(this.pluginConfig.pearl.pearlThrowBlockedDuringCombat)
|
||||
.send();
|
||||
this.fightPearlService.markDelay(playerId);
|
||||
int cooldownTicks = (int) (this.settings.pearlThrowDelay.toMillis() / 50);
|
||||
player.setCooldown(Material.ENDER_PEARL, cooldownTicks);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.eternalcode.combat.fight.pearl;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
public class FightPearlServiceImpl implements FightPearlService {
|
||||
|
||||
private final FightPearlSettings pearlSettings;
|
||||
private final Cache<UUID, Instant> pearlStartTimes;
|
||||
|
||||
public FightPearlServiceImpl(FightPearlSettings pearlSettings) {
|
||||
this.pearlSettings = pearlSettings;
|
||||
this.pearlStartTimes = Caffeine.newBuilder()
|
||||
.expireAfterWrite(pearlSettings.pearlThrowDelay)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markDelay(UUID uuid) {
|
||||
this.pearlStartTimes.put(uuid, Instant.now());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDelay(UUID uuid) {
|
||||
return this.pearlStartTimes.getIfPresent(uuid) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getRemainingDelay(UUID uuid) {
|
||||
Instant startTime = this.pearlStartTimes.getIfPresent(uuid);
|
||||
if (startTime == null) {
|
||||
return Duration.ZERO;
|
||||
}
|
||||
|
||||
Duration elapsed = Duration.between(startTime, Instant.now());
|
||||
Duration remaining = this.pearlSettings.pearlThrowDelay.minus(elapsed);
|
||||
|
||||
return remaining.isNegative() ? Duration.ZERO : remaining;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant getDelay(UUID uuid) {
|
||||
Instant startTime = this.pearlStartTimes.getIfPresent(uuid);
|
||||
return startTime != null ? startTime.plus(this.pearlSettings.pearlThrowDelay) : Instant.MIN;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
package com.eternalcode.combat.fight.pearl;
|
||||
|
||||
import com.eternalcode.multification.bukkit.notice.BukkitNotice;
|
||||
import com.eternalcode.multification.notice.Notice;
|
||||
import eu.okaeri.configs.OkaeriConfig;
|
||||
import eu.okaeri.configs.annotation.Comment;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
public class PearlSettings extends OkaeriConfig {
|
||||
public class FightPearlSettings extends OkaeriConfig {
|
||||
|
||||
@Comment({ "# Is pearl damage to be enabled?", "# This will work globally" })
|
||||
public boolean pearlThrowDamageEnabled = true;
|
||||
@@ -20,9 +21,6 @@ public class PearlSettings extends OkaeriConfig {
|
||||
@Comment("# Set true, If you want add cooldown to pearls")
|
||||
public boolean pearlCooldownEnabled = false;
|
||||
|
||||
@Comment("# Set true, If you want to reset timer when player throws ender pearl")
|
||||
public boolean pearlExtendsCombatTag = false;
|
||||
|
||||
@Comment({
|
||||
"# Block throwing pearls with delay?",
|
||||
"# If you set this to for example 3s, player will have to wait 3 seconds before throwing another pearl"
|
||||
@@ -30,12 +28,12 @@ public class PearlSettings extends OkaeriConfig {
|
||||
public Duration pearlThrowDelay = Duration.ofSeconds(3);
|
||||
|
||||
@Comment("# Message sent when player tries to throw ender pearl, but are disabled")
|
||||
public Notice pearlThrowBlockedDuringCombat = Notice.builder()
|
||||
public Notice pearlThrowBlockedDuringCombat = BukkitNotice.builder()
|
||||
.chat("<red>Throwing ender pearls is prohibited during combat!")
|
||||
.build();
|
||||
|
||||
@Comment("# Message sent when player tries to throw ender pearl, but has delay")
|
||||
public Notice pearlThrowBlockedDelayDuringCombat = Notice.builder()
|
||||
public Notice pearlThrowBlockedDelayDuringCombat = BukkitNotice.builder()
|
||||
.chat("<red>You must wait {TIME} before next throw!")
|
||||
.build();
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
package com.eternalcode.combat.fight.pearl;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.fight.event.CauseOfTag;
|
||||
import com.eternalcode.commons.delay.Delay;
|
||||
import com.eternalcode.commons.scheduler.Scheduler;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PearlServiceImpl implements PearlService {
|
||||
|
||||
private final FightManager fightManager;
|
||||
private final PluginConfig pluginConfig;
|
||||
private final Scheduler scheduler;
|
||||
|
||||
private final Delay<UUID> pearlStartTimes;
|
||||
|
||||
public PearlServiceImpl(FightManager fightManager, PluginConfig pluginConfig, Scheduler scheduler) {
|
||||
this.fightManager = fightManager;
|
||||
this.pluginConfig = pluginConfig;
|
||||
|
||||
this.pearlStartTimes = Delay.withDefault(() -> pluginConfig.pearl.pearlThrowDelay);
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldCancelEvent(UUID playerId) {
|
||||
if (fightManager.isInCombat(playerId)) {
|
||||
if (this.pluginConfig.pearl.pearlCooldownEnabled) {
|
||||
return this.pearlStartTimes.hasDelay(playerId);
|
||||
}
|
||||
|
||||
return pluginConfig.pearl.pearlThrowDisabledDuringCombat;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleDelay(Player player) {
|
||||
UUID uniqueId = player.getUniqueId();
|
||||
|
||||
if (this.hasDelay(uniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.fightManager.isInCombat(uniqueId)) {
|
||||
if (this.pluginConfig.pearl.pearlExtendsCombatTag) {
|
||||
Duration combatTime = this.pluginConfig.settings.combatTimerDuration;
|
||||
this.fightManager.tag(uniqueId, combatTime, CauseOfTag.ENDER_PEARL);
|
||||
}
|
||||
|
||||
if (this.pluginConfig.pearl.pearlCooldownEnabled && !this.pluginConfig.pearl.pearlThrowDelay.isZero()) {
|
||||
this.pearlStartTimes.markDelay(uniqueId);
|
||||
this.scheduler.runLater(
|
||||
() -> player.setCooldown(
|
||||
Material.ENDER_PEARL,
|
||||
(int) this.pluginConfig.pearl.pearlThrowDelay.toMillis() / 50
|
||||
), Duration.ofMillis(50)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDelay(UUID uuid) {
|
||||
return this.pearlStartTimes.hasDelay(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getRemainingDelay(UUID uuid) {
|
||||
return this.pearlStartTimes.getRemaining(uuid);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
package com.eternalcode.combat.fight.trident;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.fight.event.CauseOfTag;
|
||||
import com.eternalcode.combat.fight.event.FightUntagEvent;
|
||||
import com.eternalcode.combat.notification.NoticeService;
|
||||
import com.eternalcode.combat.util.DurationUtil;
|
||||
import java.time.Duration;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerRiptideEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class TridentController implements Listener {
|
||||
|
||||
private final PluginConfig pluginConfig;
|
||||
private final NoticeService noticeService;
|
||||
private final FightManager fightManager;
|
||||
private final TridentService tridentService;
|
||||
private final Server server;
|
||||
|
||||
public TridentController(
|
||||
PluginConfig pluginConfig,
|
||||
NoticeService noticeService,
|
||||
FightManager fightManager,
|
||||
TridentService tridentService, Server server
|
||||
) {
|
||||
this.pluginConfig = pluginConfig;
|
||||
this.noticeService = noticeService;
|
||||
this.fightManager = fightManager;
|
||||
this.tridentService = tridentService;
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onRiptideInteract(PlayerInteractEvent event) {
|
||||
if (!this.isRiptideInteract(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
UUID playerId = player.getUniqueId();
|
||||
|
||||
if (!this.fightManager.isInCombat(playerId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.pluginConfig.trident.tridentRiptideDisabledDuringCombat) {
|
||||
event.setCancelled(true);
|
||||
|
||||
this.noticeService.create()
|
||||
.player(playerId)
|
||||
.notice(this.pluginConfig.trident.tridentRiptideBlocked)
|
||||
.send();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.tridentService.hasDelay(playerId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
// we need to send message without ignoring canceled event because of riptide cooldown
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void messageOnRiptideCooldown(PlayerInteractEvent event) {
|
||||
if (!this.isRiptideInteract(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID playerId = event.getPlayer().getUniqueId();
|
||||
if (!this.tridentService.hasDelay(playerId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Duration remainingDelay = this.tridentService.getRemainingDelay(playerId);
|
||||
this.noticeService.create()
|
||||
.player(playerId)
|
||||
.notice(this.pluginConfig.trident.tridentRiptideOnCooldown)
|
||||
.placeholder("{TIME}", DurationUtil.format(remainingDelay))
|
||||
.send();
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onRiptide(PlayerRiptideEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
UUID uniqueId = player.getUniqueId();
|
||||
|
||||
if (this.pluginConfig.trident.tridentRiptideDisabledDuringCombat) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.fightManager.isInCombat(uniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.tridentService.hasDelay(uniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.tridentService.markDelay(player.getUniqueId());
|
||||
player.setCooldown(Material.TRIDENT, (int) this.pluginConfig.trident.tridentRiptideDelay.toMillis() / 50);
|
||||
|
||||
if (this.pluginConfig.trident.tridentRiptideExtendsCombatTag) {
|
||||
this.fightManager.tag(uniqueId, this.pluginConfig.settings.combatTimerDuration, CauseOfTag.TRIDENT);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onUntag(FightUntagEvent event) {
|
||||
Player player = server.getPlayer(event.getPlayer());
|
||||
player.setCooldown(Material.TRIDENT, 0);
|
||||
this.tridentService.removeDelay(player.getUniqueId());
|
||||
}
|
||||
|
||||
private boolean isRiptideInteract(PlayerInteractEvent event) {
|
||||
EquipmentSlot hand = event.getHand();
|
||||
if (hand != EquipmentSlot.HAND && hand != EquipmentSlot.OFF_HAND) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Action action = event.getAction();
|
||||
if (action != Action.RIGHT_CLICK_AIR && action != Action.RIGHT_CLICK_BLOCK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.isRiptideTrident(event.getItem());
|
||||
}
|
||||
|
||||
private boolean isRiptideTrident(ItemStack itemStack) {
|
||||
return itemStack != null
|
||||
&& itemStack.getType() == Material.TRIDENT
|
||||
&& itemStack.containsEnchantment(Enchantment.RIPTIDE);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.eternalcode.combat.fight.trident;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.commons.delay.Delay;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.UUID;
|
||||
|
||||
public class TridentServiceImpl implements TridentService {
|
||||
|
||||
private final Delay<UUID> delay;
|
||||
|
||||
public TridentServiceImpl(PluginConfig pluginConfig) {
|
||||
this.delay = Delay.withDefault(() -> pluginConfig.trident.tridentRiptideDelay);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void markDelay(UUID uuid) {
|
||||
this.delay.markDelay(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDelay(UUID uuid) {
|
||||
return this.delay.hasDelay(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDelay(UUID playerId) {
|
||||
this.delay.unmarkDelay(playerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getRemainingDelay(UUID uuid) {
|
||||
return this.delay.getRemaining(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.eternalcode.combat.fight.trident;
|
||||
|
||||
import com.eternalcode.multification.notice.Notice;
|
||||
import eu.okaeri.configs.OkaeriConfig;
|
||||
import eu.okaeri.configs.annotation.Comment;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
public class TridentSettings extends OkaeriConfig {
|
||||
|
||||
@Comment({
|
||||
"# Set to true to disable riptide usage during combat",
|
||||
"# This setting works globally, but can be overridden by region settings"
|
||||
})
|
||||
public boolean tridentRiptideDisabledDuringCombat = false;
|
||||
|
||||
@Comment("# Set to true so then riptide usage during combat will extend combat tag duration, works only if riptide usage is not disabled")
|
||||
public boolean tridentRiptideExtendsCombatTag = false;
|
||||
|
||||
@Comment({
|
||||
"# Should riptide enchantment be on cooldown during combat?",
|
||||
"# Setting this option to 3s will make players wait 3 seconds between trident throws",
|
||||
"# Setting this to 0s or below will remove cooldown"
|
||||
})
|
||||
public Duration tridentRiptideDelay = Duration.ofSeconds(10);
|
||||
|
||||
@Comment("# Message shown when riptide is blocked during combat")
|
||||
public Notice tridentRiptideBlocked = Notice.builder()
|
||||
.chat("<red>Using riptide is prohibited during combat!")
|
||||
.build();
|
||||
|
||||
@Comment({
|
||||
"# Message sent to the player when riptide is on cooldown",
|
||||
"# Available placeholder: {TIME} - remaining time left to use riptide again"
|
||||
})
|
||||
public Notice tridentRiptideOnCooldown = Notice.builder()
|
||||
.chat("<red>You must wait {TIME} before next riptide!")
|
||||
.build();
|
||||
}
|
||||
@@ -2,20 +2,24 @@ package com.eternalcode.combat.notification;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.multification.adventure.AudienceConverter;
|
||||
import com.eternalcode.multification.paper.PaperMultification;
|
||||
import com.eternalcode.multification.bukkit.BukkitMultification;
|
||||
import com.eternalcode.multification.translation.TranslationProvider;
|
||||
import net.kyori.adventure.platform.AudienceProvider;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.serializer.ComponentSerializer;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class NoticeService extends PaperMultification<PluginConfig> {
|
||||
public final class NoticeService extends BukkitMultification<PluginConfig> {
|
||||
|
||||
private final AudienceProvider audienceProvider;
|
||||
private final PluginConfig pluginConfig;
|
||||
private final MiniMessage miniMessage;
|
||||
|
||||
public NoticeService(PluginConfig pluginConfig, MiniMessage miniMessage) {
|
||||
public NoticeService(AudienceProvider audienceProvider, PluginConfig pluginConfig, MiniMessage miniMessage) {
|
||||
this.audienceProvider = audienceProvider;
|
||||
this.pluginConfig = pluginConfig;
|
||||
this.miniMessage = miniMessage;
|
||||
}
|
||||
@@ -32,7 +36,13 @@ public final class NoticeService extends PaperMultification<PluginConfig> {
|
||||
|
||||
@Override
|
||||
protected @NotNull AudienceConverter<CommandSender> audienceConverter() {
|
||||
return commandSender -> commandSender;
|
||||
return commandSender -> {
|
||||
if (commandSender instanceof Player player) {
|
||||
return this.audienceProvider.player(player.getUniqueId());
|
||||
}
|
||||
|
||||
return this.audienceProvider.console();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -8,14 +8,13 @@ import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
||||
record WorldGuardRegion(World world, ProtectedRegion region) implements Region {
|
||||
|
||||
@Override
|
||||
public Point getCenter() {
|
||||
BlockVector3 min = this.region.getMinimumPoint();
|
||||
BlockVector3 max = this.region.getMaximumPoint();
|
||||
|
||||
double x = (min.x() + max.x()) / 2.0;
|
||||
double z = (min.z() + max.z()) / 2.0;
|
||||
double x = (double) (min.getX() + max.getX()) / 2;
|
||||
double z = (double) (min.getZ() + max.getZ()) / 2;
|
||||
|
||||
return new Point(this.world, x, z);
|
||||
}
|
||||
@@ -23,13 +22,12 @@ record WorldGuardRegion(World world, ProtectedRegion region) implements Region {
|
||||
@Override
|
||||
public Location getMin() {
|
||||
BlockVector3 min = this.region.getMinimumPoint();
|
||||
return new Location(this.world, min.x(), min.y(), min.z());
|
||||
return new Location(this.world, min.getX(), min.getY(), min.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getMax() {
|
||||
BlockVector3 max = this.region.getMaximumPoint();
|
||||
return new Location(this.world, max.x(), max.y(), max.z());
|
||||
return new Location(this.world, max.getX(), max.getY(), max.getZ());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package com.eternalcode.combat.updater;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.commons.concurrent.FutureHandler;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.platform.AudienceProvider;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -14,17 +16,20 @@ public class UpdaterNotificationController implements Listener {
|
||||
|
||||
private final UpdaterService updaterService;
|
||||
private final PluginConfig pluginConfig;
|
||||
private final AudienceProvider audienceProvider;
|
||||
private final MiniMessage miniMessage;
|
||||
|
||||
public UpdaterNotificationController(UpdaterService updaterService, PluginConfig pluginConfig, MiniMessage miniMessage) {
|
||||
public UpdaterNotificationController(UpdaterService updaterService, PluginConfig pluginConfig, AudienceProvider audienceProvider, MiniMessage miniMessage) {
|
||||
this.updaterService = updaterService;
|
||||
this.pluginConfig = pluginConfig;
|
||||
this.audienceProvider = audienceProvider;
|
||||
this.miniMessage = miniMessage;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
Audience audience = this.audienceProvider.player(player.getUniqueId());
|
||||
|
||||
if (!shouldNotify(player)) {
|
||||
return;
|
||||
@@ -33,7 +38,7 @@ public class UpdaterNotificationController implements Listener {
|
||||
this.updaterService.checkForUpdate()
|
||||
.thenAccept(result -> {
|
||||
if (result.isUpdateAvailable()) {
|
||||
player.sendMessage(this.miniMessage.deserialize(NEW_VERSION_AVAILABLE));
|
||||
audience.sendMessage(this.miniMessage.deserialize(NEW_VERSION_AVAILABLE));
|
||||
}
|
||||
})
|
||||
.exceptionally(FutureHandler::handleException);
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.eternalcode.combat.util;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public final class ReflectUtil {
|
||||
|
||||
private ReflectUtil() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T invokeMethod(Object object, String name) {
|
||||
try {
|
||||
if (object == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Method method = object.getClass().getDeclaredMethod(name);
|
||||
method.setAccessible(true);
|
||||
return (T) method.invoke(object);
|
||||
}
|
||||
catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException exception) {
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,4 +4,4 @@ org.gradle.configuration-cache=true
|
||||
org.gradle.configuration-cache.parallel=true
|
||||
|
||||
# Platforms
|
||||
paperVersion=1.19.3,1.19.4,1.20,1.20.1,1.20.2,1.20.4,1.20.5,1.20.6,1.21,1.21.1,1.21.3,1.21.4,1.21.5,1.21.6,1.21.7,1.21.8,1.21.9,1.21.10,1.21.11,26.1.1,26.1.2
|
||||
paperVersion=1.17,1.17.1,1.18,1.18.1,1.18.2,1.19,1.19.1,1.19.2,1.19.3,1.19.4,1.20,1.20.1,1.20.2,1.20.3,1.20.4,1.20.5,1.20.6,1.21,1.21.1,1.21.2,1.21.3,1.21.4,1.21.5,1.21.6,1.21.7,1.21.8,1.21.9,1.21.10,1.21.11
|
||||
@@ -1,9 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip
|
||||
networkTimeout=10000
|
||||
retries=0
|
||||
retryBackOffMs=500
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# gradlew start up script for POSIX generated by Gradle.
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
@@ -29,7 +29,7 @@
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh gradlew
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
@@ -57,7 +57,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem gradlew startup script for Windows
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables, and ensure extensions are enabled
|
||||
setlocal EnableExtensions
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@@ -51,7 +51,7 @@ echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
"%COMSPEC%" /c exit 1
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
@@ -65,18 +65,29 @@ echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
"%COMSPEC%" /c exit 1
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
|
||||
|
||||
@rem Execute gradlew
|
||||
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
|
||||
@rem which allows us to clear the local environment before executing the java command
|
||||
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:exitWithErrorLevel
|
||||
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
|
||||
"%COMSPEC%" /c exit %ERRORLEVEL%
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||