Merge branch 'pr-5'
# Conflicts: # .github/CONTRIBUTING.md # .github/PULL_REQUEST_TEMPLATE.md # .github/workflows/gradle.yml # .github/workflows/hangar-publish.yml # .github/workflows/modrinth-publish.yml # buildSrc/src/main/kotlin/Versions.kt # eternalcombat-plugin/build.gradle.kts # eternalcombat-plugin/src/main/java/com/eternalcode/combat/CombatPlugin.java
No files matched your search
@@ -0,0 +1,64 @@
|
||||
# 👋 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.
|
||||
|
||||
## 🛠️ Development Setup
|
||||
|
||||
To start contributing, you'll need to set up your environment:
|
||||
|
||||
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.
|
||||
|
||||
### 📥 Getting the Code
|
||||
|
||||
```bash
|
||||
# Fork the repository on GitHub first!
|
||||
# https://github.com/EternalCodeTeam/EternalCombat/fork
|
||||
git clone https://github.com/YOUR-USERNAME/EternalCombat.git
|
||||
cd EternalCombat
|
||||
```
|
||||
|
||||
### 🔨 Building the Project
|
||||
|
||||
Run this command in your terminal:
|
||||
|
||||
```bash
|
||||
./gradlew build
|
||||
```
|
||||
|
||||
## 🤝 How to Contribute
|
||||
|
||||
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.
|
||||
|
||||
## 📏 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).
|
||||
@@ -0,0 +1,84 @@
|
||||
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
|
||||
@@ -0,0 +1,8 @@
|
||||
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,38 @@
|
||||
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.
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
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)
|
||||
@@ -0,0 +1,48 @@
|
||||
name: Java CI with Gradle
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v6
|
||||
|
||||
- name: Set Variables & Build
|
||||
uses: actions/github-script@v9
|
||||
with:
|
||||
script: |
|
||||
const isPR = context.eventName === 'pull_request';
|
||||
const branch = isPR ? context.payload.pull_request.head.ref.replace(/\//g, '-') : 'master';
|
||||
const sha = (isPR ? context.payload.pull_request.head.sha : context.sha).substring(0, 7);
|
||||
|
||||
const artifactName = `EternalCombat ${branch}+${sha}`;
|
||||
core.exportVariable('FULL_ARTIFACT_NAME', artifactName);
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew shadowJar
|
||||
|
||||
- name: Upload build artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ env.FULL_ARTIFACT_NAME }}
|
||||
path: eternalcombat-plugin/build/libs/*.jar
|
||||
archive: false
|
||||
@@ -0,0 +1,34 @@
|
||||
name: Publish to Hangar
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
if: (github.event_name == 'push' && !contains(github.event.head_commit.message, '[ci skip]')) || github.event_name == 'release'
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v6
|
||||
|
||||
- name: Publish to Hangar
|
||||
run: ./gradlew :eternalcombat-plugin:publishPluginPublicationToHangar
|
||||
env:
|
||||
HANGAR_API_TOKEN: ${{ secrets.HANGAR_API_TOKEN }}
|
||||
GITHUB_EVENT_NAME: ${{ github.event_name }}
|
||||
CHANGELOG: ${{ github.event_name == 'release' && github.event.release.body || github.event.head_commit.message }}
|
||||
@@ -0,0 +1,34 @@
|
||||
name: Publish to Modrinth
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
if: (github.event_name == 'push' && !contains(github.event.head_commit.message, '[ci skip]')) || github.event_name == 'release'
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v6
|
||||
|
||||
- name: Publish to Modrinth
|
||||
run: ./gradlew :eternalcombat-plugin:modrinth
|
||||
env:
|
||||
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
||||
GITHUB_EVENT_NAME: ${{ github.event_name }}
|
||||
CHANGELOG: ${{ github.event_name == 'release' && github.event.release.body || github.event.head_commit.message }}
|
||||
@@ -10,7 +10,7 @@
|
||||
[](https://docs.eternalcode.pl/eternalcombat/introduction)
|
||||
[](https://bstats.org/plugin/bukkit/EternalCombat/17803)
|
||||
|
||||
[Report Bug](https://github.com/EternalCodeTeam/EternalCombat/issues) • [Request Feature](https://github.com/EternalCodeTeam/EternalCombat/issues) • [Join Discord](https://discord.gg/eternalcode)
|
||||
[Report Bug](https://github.com/EternalCodeTeam/EternalCombat/issues) • [Request Feature](https://github.com/EternalCodeTeam/EternalCombat/issues) • [Join Discord](https://discord.com/invite/FQ7jmGBd6c)
|
||||
|
||||
<br>
|
||||
|
||||
@@ -29,7 +29,7 @@ EternalCombat 2.0 has been tested on Minecraft versions **1.17.1 to 1.21.11**, b
|
||||
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 17 or later**, so
|
||||
The plugin requires **Java 21 or later**, so
|
||||
ensure your server is ready.
|
||||
Ready for action?
|
||||
Install EternalCombat and dive in now!
|
||||
@@ -43,17 +43,22 @@ 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:
|
||||

|
||||
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">
|
||||
|
||||
- **Fully Customizable Combat**
|
||||
Tailor the combat experience to your liking with a ton of options! From disabling elytra to setting drop rates for
|
||||
@@ -132,7 +137,7 @@ With Maven:
|
||||
With Gradle:
|
||||
|
||||
```kts
|
||||
compileOnly("com.eternalcode:eternalcombat-api:2.4.0")
|
||||
compileOnly("com.eternalcode:eternalcombat-api:2.5.0-SNAPSHOT")
|
||||
```
|
||||
|
||||
With Maven:
|
||||
@@ -142,7 +147,7 @@ With Maven:
|
||||
<dependency>
|
||||
<groupId>com.eternalcode</groupId>
|
||||
<artifactId>eternalcombat-api</artifactId>
|
||||
<version>2.4.0</version>
|
||||
<version>2.5.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
|
Before Width: | Height: | Size: 5.9 MiB After Width: | Height: | Size: 5.2 MiB |
|
Before Width: | Height: | Size: 2.9 MiB After Width: | Height: | Size: 2.6 MiB |
|
Before Width: | Height: | Size: 787 KiB After Width: | Height: | Size: 752 KiB |
|
After Width: | Height: | Size: 5.4 MiB |
|
After Width: | Height: | Size: 2.7 MiB |
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 98 KiB |
@@ -11,8 +11,8 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.3.0")
|
||||
implementation("com.gradleup.shadow:com.gradleup.shadow.gradle.plugin:9.3.1")
|
||||
implementation("com.gradleup.shadow:com.gradleup.shadow.gradle.plugin:9.4.1")
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.3.20")
|
||||
implementation("net.minecrell:plugin-yml:0.6.0")
|
||||
implementation("xyz.jpenilla:run-task:3.0.2")
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@ object Versions {
|
||||
|
||||
const val SPIGOT_API = "1.17.1-R0.1-SNAPSHOT"
|
||||
|
||||
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 JUNIT_JUPITER_API = "6.0.3"
|
||||
const val JUNIT_JUPITER_PARAMS = "6.0.3"
|
||||
const val JUNIT_JUPITER_ENGINE = "6.0.3"
|
||||
|
||||
const val JETBRAINS_ANNOTATIONS = "26.0.2-1"
|
||||
const val JETBRAINS_ANNOTATIONS = "26.1.0"
|
||||
|
||||
const val ETERNALCODE_COMMONS = "1.3.2"
|
||||
const val ETERNALCODE_COMMONS = "1.3.4"
|
||||
const val MULTIFICATION = "1.2.4"
|
||||
const val PACKETEVENTS = "2.11.2"
|
||||
|
||||
@@ -19,6 +19,8 @@ object Versions {
|
||||
const val OKAERI_CONFIGS_SERDES_COMMONS = "5.0.13"
|
||||
const val OKAERI_CONFIGS_SERDES_BUKKIT = "5.0.13"
|
||||
|
||||
const val XSERIES = "13.6.0"
|
||||
|
||||
const val CAFFEINE = "3.2.3"
|
||||
|
||||
const val WORLD_GUARD_BUKKIT = "7.0.8"
|
||||
@@ -33,4 +35,3 @@ object Versions {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = "com.eternalcode"
|
||||
version = "2.4.1"
|
||||
version = "2.5.0-SNAPSHOT"
|
||||
|
||||
tasks.compileJava {
|
||||
options.compilerArgs = listOf("-Xlint:deprecation", "-parameters")
|
||||
|
||||
@@ -4,7 +4,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = "com.eternalcode"
|
||||
version = "2.4.0"
|
||||
version = "2.5.0-SNAPSHOT"
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import net.minecrell.pluginyml.bukkit.BukkitPluginDescription
|
||||
import io.papermc.hangarpublishplugin.model.Platforms
|
||||
|
||||
plugins {
|
||||
`eternalcombat-java`
|
||||
`eternalcombat-repositories`
|
||||
@@ -8,7 +7,7 @@ plugins {
|
||||
id("net.minecrell.plugin-yml.bukkit")
|
||||
id("com.gradleup.shadow")
|
||||
id("xyz.jpenilla.run-paper")
|
||||
id("com.modrinth.minotaur") version "2.8.10"
|
||||
id("com.modrinth.minotaur") version "2.9.0"
|
||||
id("io.papermc.hangar-publish-plugin") version "0.1.4"
|
||||
}
|
||||
|
||||
@@ -126,6 +125,8 @@ 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}")
|
||||
// caffeine
|
||||
implementation("com.github.ben-manes.caffeine:caffeine:${Versions.CAFFEINE}")
|
||||
|
||||
@@ -139,7 +140,7 @@ dependencies {
|
||||
|
||||
// PlaceholderAPI
|
||||
compileOnly("me.clip:placeholderapi:${Versions.PLACEHOLDER_API}")
|
||||
|
||||
|
||||
// Multification
|
||||
implementation("com.eternalcode:multification-bukkit:${Versions.MULTIFICATION}")
|
||||
implementation("com.eternalcode:multification-okaeri:${Versions.MULTIFICATION}")
|
||||
@@ -208,7 +209,8 @@ tasks.shadowJar {
|
||||
"com.github.benmanes.caffeine",
|
||||
"com.eternalcode.commons",
|
||||
"com.eternalcode.multification",
|
||||
"io.papermc.lib"
|
||||
"com.github.cryptomorin",
|
||||
"io.papermc.lib",
|
||||
).forEach { pack ->
|
||||
relocate(pack, "$prefix.$pack")
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ import com.eternalcode.combat.fight.controller.FightActionBlockerController;
|
||||
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.controller.FightInventoryController;
|
||||
import com.eternalcode.combat.fight.death.DeathFlareController;
|
||||
import com.eternalcode.combat.fight.death.DeathLightningController;
|
||||
import com.eternalcode.combat.fight.controller.FightMessageController;
|
||||
import com.eternalcode.combat.fight.controller.FightTagController;
|
||||
import com.eternalcode.combat.fight.controller.FightUnTagController;
|
||||
@@ -96,15 +99,11 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
|
||||
Server server = this.getServer();
|
||||
|
||||
File dataFolder = this.getDataFolder();
|
||||
File configFile = new File(dataFolder, CONFIG_RESOURCE_PATH);
|
||||
if (!configFile.exists()) {
|
||||
this.saveResource(CONFIG_RESOURCE_PATH, false);
|
||||
}
|
||||
|
||||
ConfigService configService = new ConfigService();
|
||||
|
||||
EventManager eventManager = new EventManager(this);
|
||||
PluginConfig pluginConfig = configService.create(PluginConfig.class, configFile);
|
||||
PluginConfig pluginConfig = configService.create(PluginConfig.class, new File(dataFolder, CONFIG_RESOURCE_PATH));
|
||||
|
||||
MinecraftScheduler scheduler = CombatSchedulerAdapter.getAdaptiveScheduler(this);
|
||||
|
||||
@@ -177,6 +176,8 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
|
||||
new FightBypassCreativeController(server, pluginConfig),
|
||||
new FightActionBlockerController(this.fightManager, noticeService, pluginConfig, server),
|
||||
new FightPearlController(pluginConfig.pearl, noticeService, this.fightManager, this.fightPearlService),
|
||||
new DeathFlareController(pluginConfig, server, scheduler, this),
|
||||
new DeathLightningController(pluginConfig, server),
|
||||
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),
|
||||
@@ -187,7 +188,8 @@ 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 FireworkController(this.fightManager, pluginConfig, noticeService),
|
||||
new FightInventoryController(this.fightManager, pluginConfig, noticeService)
|
||||
);
|
||||
|
||||
eventManager.subscribe(
|
||||
@@ -222,8 +224,6 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
|
||||
|
||||
this.fightManager.untagAll();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FightManager getFightManager() {
|
||||
return this.fightManager;
|
||||
|
||||
@@ -39,12 +39,6 @@ public class CombatSettings extends OkaeriConfig {
|
||||
})
|
||||
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."
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
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,6 +1,7 @@
|
||||
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;
|
||||
@@ -42,6 +43,12 @@ 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.",
|
||||
@@ -105,6 +112,13 @@ 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.",
|
||||
|
||||
@@ -17,6 +17,7 @@ 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.inventory.InventoryType;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerToggleFlightEvent;
|
||||
@@ -185,28 +186,6 @@ public class FightActionBlockerController implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@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();
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.eternalcode.combat.fight.controller;
|
||||
|
||||
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 FightInventoryController implements Listener {
|
||||
|
||||
private final FightManager fightManager;
|
||||
private final PluginConfig config;
|
||||
private final NoticeService noticeService;
|
||||
|
||||
public FightInventoryController(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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -9,12 +9,15 @@ 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 {
|
||||
|
||||
@@ -89,6 +92,67 @@ 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());
|
||||
|
||||
@@ -41,19 +41,22 @@ public final class KnockbackService {
|
||||
|
||||
insideRegion.put(player.getUniqueId(), region);
|
||||
|
||||
scheduler.runLater(
|
||||
player.getLocation(), () -> {
|
||||
insideRegion.remove(player.getUniqueId());
|
||||
Location playerLocation = player.getLocation();
|
||||
if (!region.contains(playerLocation) && !regionProvider.isInRegion(playerLocation)) {
|
||||
return;
|
||||
}
|
||||
scheduler.runLater(player.getLocation(), () -> {
|
||||
insideRegion.remove(player.getUniqueId());
|
||||
|
||||
Location location =
|
||||
generate(playerLocation, Point2D.from(region.getMin()), Point2D.from(region.getMax()));
|
||||
Location playerLocation = player.getLocation();
|
||||
if (!region.contains(playerLocation) && !regionProvider.isInRegion(playerLocation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PaperLib.teleportAsync(player, location, TeleportCause.PLUGIN);
|
||||
}, this.config.knockback.forceDelay);
|
||||
if (player.isInsideVehicle()) {
|
||||
player.leaveVehicle();
|
||||
}
|
||||
|
||||
Location location = generate(playerLocation, Point2D.from(region.getMin()), Point2D.from(region.getMax()));
|
||||
|
||||
PaperLib.teleportAsync(player, location, TeleportCause.PLUGIN);
|
||||
}, this.config.knockback.forceDelay);
|
||||
}
|
||||
|
||||
private Location generate(Location playerLocation, Point2D minX, Point2D maxX) {
|
||||
@@ -68,6 +71,10 @@ public final class KnockbackService {
|
||||
}
|
||||
|
||||
public void knockback(Region region, Player player) {
|
||||
if (player.isInsideVehicle()) {
|
||||
player.leaveVehicle();
|
||||
}
|
||||
|
||||
Point point = region.getCenter();
|
||||
Location subtract = player.getLocation().subtract(point.x(), 0, point.z());
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/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/.
|
||||
|
||||