v2.4.1 merge from upstream
This commit is contained in:
commit
c57e22fd22
43 files changed
+676
-601
No files matched your search
@@ -1,2 +0,0 @@
|
||||
* @EternalCodeTeam/eternalcodeteam-maintainers
|
||||
/.github/CODEOWNERS @EternalCodeTeam/eternalcodeteam-maintainers
|
||||
@@ -1,128 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
https://discord.gg/FQ7jmGBd6c.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
@@ -1,36 +0,0 @@
|
||||
# Contributing to EternalCombat
|
||||
|
||||
We welcome all contributions to the EternalCombat project!
|
||||
|
||||
### How to Contribute
|
||||
|
||||
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.
|
||||
|
||||
### Code of Conduct
|
||||
|
||||
We expect all contributors to follow our [code of conduct](CODE_OF_CONDUCT.md).
|
||||
|
||||
### Reporting Issues
|
||||
|
||||
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.
|
||||
|
||||
### Compatibility
|
||||
|
||||
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.
|
||||
|
||||
### Submitting a Pull Request
|
||||
|
||||
When submitting a pull request, please make sure to follow these guidelines:
|
||||
|
||||
- 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!
|
||||
@@ -1,33 +0,0 @@
|
||||
---
|
||||
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,20 +0,0 @@
|
||||
---
|
||||
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 +0,0 @@
|
||||
**Please describe the changes made by this PR and why they need to be merged:**
|
||||
@@ -1,42 +0,0 @@
|
||||
name: Java CI with Gradle
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
- name: Cache Gradle
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: >-
|
||||
${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*',
|
||||
'**/gradle-wrapper.properties') }}
|
||||
restore-keys: '${{ runner.os }}-gradle-'
|
||||
- name: Make gradlew executable
|
||||
run: chmod +x gradlew
|
||||
- name: Build with Gradle
|
||||
uses: gradle/gradle-build-action@093dfe9d598ec5a42246855d09b49dc76803c005
|
||||
with:
|
||||
arguments: shadowJar
|
||||
- name: Upload a Build Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: 'Successfully build EternalCombat'
|
||||
path: eternalcombat-plugin/build/libs/*.jar
|
||||
@@ -1,28 +0,0 @@
|
||||
name: Publish EternalCombat API
|
||||
on:
|
||||
release:
|
||||
branches: [ master ]
|
||||
types: [ published ]
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
environment: deployment
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
cache: 'gradle'
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
|
||||
- name: Publish with Gradle
|
||||
run: ./gradlew clean build eternalcombat-api:publish
|
||||
env:
|
||||
ETERNAL_CODE_MAVEN_USERNAME: ${{ secrets.ETERNAL_CODE_MAVEN_USERNAME }}
|
||||
ETERNAL_CODE_MAVEN_PASSWORD: ${{ secrets.ETERNAL_CODE_MAVEN_PASSWORD }}
|
||||
@@ -9,6 +9,15 @@
|
||||
[](https://discord.com/invite/FQ7jmGBd6c)
|
||||
[](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)
|
||||
|
||||
<br>
|
||||
|
||||
<a href="https://ko-fi.com/eternalcodeteam">
|
||||
<img src="https://github.com/intergrav/devins-badges/blob/v3/assets/cozy/donate/kofi-plural-alt_64h.png?raw=true" height="64" alt="Support us on Ko-fi">
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
### Information
|
||||
@@ -16,7 +25,7 @@
|
||||
## 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 1.21.8**, 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).
|
||||
@@ -68,14 +77,14 @@ EternalCombat in full swing and learn why it’s a game-changer for your server!
|
||||
|
||||
Control who can use EternalCombat’s powerful features with these permissions:
|
||||
|
||||
| Permission | Description |
|
||||
|--------------------------------|--------------------------------------------------------------------------|
|
||||
| `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.reload` | Reload the plugin with `/combatlog reload`. |
|
||||
| `eternalcombat.receiveupdates` | Receive notifications about new plugin versions on join. |
|
||||
| `eternalcombat.bypass` | Bypass combat tagging, need's `excludeAdminsFromCombat` to be enabled |
|
||||
| Permission | Description |
|
||||
|--------------------------------|-------------------------------------------------------------------------------------------------------|
|
||||
| `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.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 |
|
||||
|
||||
## PlaceholderAPI
|
||||
|
||||
@@ -123,7 +132,7 @@ With Maven:
|
||||
With Gradle:
|
||||
|
||||
```kts
|
||||
compileOnly("com.eternalcode:eternalcombat-api:2.3.0-SNAPSHOT")
|
||||
compileOnly("com.eternalcode:eternalcombat-api:2.4.0")
|
||||
```
|
||||
|
||||
With Maven:
|
||||
@@ -133,7 +142,7 @@ With Maven:
|
||||
<dependency>
|
||||
<groupId>com.eternalcode</groupId>
|
||||
<artifactId>eternalcombat-api</artifactId>
|
||||
<version>2.3.0-SNAPSHOT</version>
|
||||
<version>2.4.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 188 KiB After Width: | Height: | Size: 113 KiB |
@@ -1,7 +1,6 @@
|
||||
plugins {
|
||||
java
|
||||
eclipse
|
||||
id("xyz.jpenilla.run-paper") version "2.2.3" apply false
|
||||
}
|
||||
|
||||
tasks.jar {
|
||||
|
||||
@@ -1,4 +1,32 @@
|
||||
plugins { `kotlin-dsl` }
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
eclipse
|
||||
}
|
||||
repositories { gradlePluginPortal(); mavenCentral() }
|
||||
kotlin { jvmToolchain(17) }
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
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")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java.setSrcDirs(emptyList<String>())
|
||||
groovy.setSrcDirs(emptyList<String>())
|
||||
resources.setSrcDirs(emptyList<String>())
|
||||
}
|
||||
test {
|
||||
java.setSrcDirs(emptyList<String>())
|
||||
kotlin.setSrcDirs(emptyList<String>())
|
||||
groovy.setSrcDirs(emptyList<String>())
|
||||
resources.setSrcDirs(emptyList<String>())
|
||||
}
|
||||
}
|
||||
@@ -2,34 +2,36 @@ object Versions {
|
||||
|
||||
const val SPIGOT_API = "1.17.1-R0.1-SNAPSHOT"
|
||||
|
||||
const val JUNIT_JUPITER_API = "5.13.4"
|
||||
const val JUNIT_JUPITER_PARAMS = "5.13.4"
|
||||
const val JUNIT_JUPITER_ENGINE = "5.13.4"
|
||||
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.0.2-1"
|
||||
|
||||
const val ETERNALCODE_COMMONS = "1.3.1"
|
||||
const val MULTIFICATION = "1.2.2"
|
||||
const val PACKETS_EVENTS = "2.9.5"
|
||||
const val ETERNALCODE_COMMONS = "1.3.2"
|
||||
const val MULTIFICATION = "1.2.4"
|
||||
const val PACKETS_EVENTS = "2.11.1"
|
||||
|
||||
const val ADVENTURE_PLATFORM_BUKKIT = "4.4.1"
|
||||
const val ADVENTURE_API = "4.24.0"
|
||||
const val ADVENTURE_API = "4.26.1"
|
||||
|
||||
const val LITE_COMMANDS = "3.10.5"
|
||||
const val OKAERI_CONFIGS_YAML_BUKKIT = "5.0.6"
|
||||
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 GIT_CHECK = "1.0.0"
|
||||
const val CAFFEINE = "3.2.3"
|
||||
|
||||
const val CAFFEINE = "3.2.2"
|
||||
const val WORLD_GUARD_BUKKIT = "7.0.8"
|
||||
|
||||
const val B_STATS_BUKKIT = "3.1.0"
|
||||
const val WORLD_GUARD_BUKKIT = "7.0.14"
|
||||
|
||||
const val PLACEHOLDER_API = "2.11.6"
|
||||
const val PLACEHOLDER_API = "2.11.7"
|
||||
const val LANDS_API = "7.23.1"
|
||||
const val PAPERLIB = "1.0.8"
|
||||
|
||||
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.8"
|
||||
const val LUCKPERMS = "5.5.17"
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = "com.eternalcode"
|
||||
version = "2.3.0-SNAPSHOT"
|
||||
version = "2.4.1"
|
||||
|
||||
tasks.compileJava {
|
||||
options.compilerArgs = listOf("-Xlint:deprecation", "-parameters")
|
||||
|
||||
@@ -4,7 +4,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = "com.eternalcode"
|
||||
version = "2.3.0-SNAPSHOT"
|
||||
version = "2.4.0"
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
|
||||
@@ -3,11 +3,12 @@ plugins {
|
||||
}
|
||||
|
||||
repositories {
|
||||
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://repo.eternalcode.pl/releases")
|
||||
maven("https://repo.eternalcode.pl/snapshots")
|
||||
maven("https://storehouse.okaeri.eu/repository/maven-public/")
|
||||
maven("https://repo.panda-lang.org/releases")
|
||||
maven("https://maven.enginehub.org/repo/")
|
||||
|
||||
+4
-1
@@ -2,6 +2,9 @@ package com.eternalcode.combat.fight.event;
|
||||
|
||||
public enum CancelTagReason {
|
||||
|
||||
TAGOUT
|
||||
TAGOUT,
|
||||
PERMISSION_BYPASS,
|
||||
ADMIN,
|
||||
CREATIVE_MODE,
|
||||
|
||||
}
|
||||
@@ -1,10 +1,96 @@
|
||||
import xyz.jpenilla.runpaper.task.RunServer
|
||||
import net.minecrell.pluginyml.bukkit.BukkitPluginDescription
|
||||
import io.papermc.hangarpublishplugin.model.Platforms
|
||||
|
||||
plugins {
|
||||
java
|
||||
id("com.gradleup.shadow") version "8.3.6"
|
||||
id("net.minecrell.plugin-yml.bukkit") version "0.6.0"
|
||||
`eternalcombat-java`
|
||||
`eternalcombat-repositories`
|
||||
|
||||
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", "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 {
|
||||
resolutionStrategy {
|
||||
eachDependency {
|
||||
if (requested.group == "com.google.code.gson" && requested.name == "gson") {
|
||||
useVersion("2.11.0")
|
||||
because("WorldGuard requires strictly gson 2.11.0")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -19,25 +105,45 @@ dependencies {
|
||||
) { // Import WorldGuard but without its bundled WorldEdit.
|
||||
exclude(group = "com.sk89q.worldedit")
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
compileOnly("com.github.angeschossen:LandsAPI:7.15.20")
|
||||
|
||||
// EternalCode Commons (split modules)
|
||||
implementation("com.eternalcode:eternalcode-commons-shared:+")
|
||||
implementation("com.eternalcode:eternalcode-commons-bukkit:+")
|
||||
implementation("com.eternalcode:eternalcode-commons-adventure:+")
|
||||
// litecommands
|
||||
implementation("dev.rollczi:litecommands-bukkit:${Versions.LITE_COMMANDS}")
|
||||
|
||||
// Other libs
|
||||
implementation("net.kyori:adventure-api:4.17.0")
|
||||
implementation("net.kyori:adventure-text-minimessage:4.17.0")
|
||||
implementation("net.kyori:adventure-platform-bukkit:4.3.3")
|
||||
implementation("dev.rollczi:litecommands-bukkit:3.10.5")
|
||||
implementation("com.github.ben-manes.caffeine:caffeine:3.1.8")
|
||||
implementation("org.bstats:bstats-bukkit:3.0.2")
|
||||
implementation("io.papermc:paperlib:1.0.8")
|
||||
// Okaeri configs
|
||||
implementation("eu.okaeri:okaeri-configs-serdes-commons:${Versions.OKAERI_CONFIGS_SERDES_COMMONS}")
|
||||
implementation("eu.okaeri:okaeri-configs-serdes-bukkit:${Versions.OKAERI_CONFIGS_SERDES_BUKKIT}")
|
||||
|
||||
implementation("com.eternalcode:multification-bukkit:1.2.2")
|
||||
implementation("com.eternalcode:multification-okaeri:1.1.4")
|
||||
implementation("com.eternalcode:gitcheck:1.0.0")
|
||||
// caffeine
|
||||
implementation("com.github.ben-manes.caffeine:caffeine:${Versions.CAFFEINE}")
|
||||
|
||||
implementation("com.eternalcode:eternalcode-commons-adventure:${Versions.ETERNALCODE_COMMONS}")
|
||||
implementation("com.eternalcode:eternalcode-commons-bukkit:${Versions.ETERNALCODE_COMMONS}")
|
||||
implementation("com.eternalcode:eternalcode-commons-shared:${Versions.ETERNALCODE_COMMONS}")
|
||||
implementation("com.eternalcode:eternalcode-commons-updater:${Versions.ETERNALCODE_COMMONS}")
|
||||
|
||||
// worldguard
|
||||
compileOnly("com.sk89q.worldguard:worldguard-bukkit:${Versions.WORLD_GUARD_BUKKIT}")
|
||||
|
||||
// PlaceholderAPI
|
||||
compileOnly("me.clip:placeholderapi:${Versions.PLACEHOLDER_API}")
|
||||
|
||||
// Lands
|
||||
compileOnly("com.github.angeschossen:LandsAPI:${Versions.LANDS_API}")
|
||||
|
||||
// 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}")
|
||||
|
||||
implementation("eu.okaeri:okaeri-configs-core:5.0.9")
|
||||
implementation("eu.okaeri:okaeri-configs-yaml-snakeyaml:5.0.9")
|
||||
@@ -46,8 +152,6 @@ dependencies {
|
||||
implementation("eu.okaeri:okaeri-configs-serdes-bukkit:5.0.9")
|
||||
}
|
||||
|
||||
java { toolchain { languageVersion.set(JavaLanguageVersion.of(17)) } }
|
||||
|
||||
bukkit {
|
||||
name = "EternalCombat"
|
||||
main = "com.eternalcode.combat.CombatPlugin"
|
||||
@@ -55,12 +159,33 @@ bukkit {
|
||||
apiVersion = "1.19"
|
||||
authors = listOf("EternalCodeTeam")
|
||||
prefix = "EternalCombat"
|
||||
softDepend = listOf("Lands")
|
||||
depend = listOf("PacketEvents-OG")
|
||||
name = "EternalCombat"
|
||||
load = BukkitPluginDescription.PluginLoadOrder.POSTWORLD
|
||||
softDepend = listOf(
|
||||
"Lands",
|
||||
"WorldGuard"
|
||||
)
|
||||
depend = listOf(
|
||||
"packetevents",
|
||||
)
|
||||
version = "${project.version}"
|
||||
|
||||
foliaSupported = false
|
||||
}
|
||||
|
||||
tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
|
||||
tasks {
|
||||
runServer {
|
||||
minecraftVersion("1.19.4")
|
||||
downloadPlugins.modrinth("WorldEdit", Versions.WORLDEDIT)
|
||||
downloadPlugins.modrinth("PacketEvents", "${Versions.PACKETEVENTS}+spigot")
|
||||
downloadPlugins.modrinth("WorldGuard", Versions.WORLDGUARD)
|
||||
downloadPlugins.modrinth("LuckPerms", "v${Versions.LUCKPERMS}-bukkit")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
archiveFileName.set("EternalCombat v${project.version}.jar")
|
||||
|
||||
exclude(
|
||||
"org/intellij/lang/annotations/**",
|
||||
"org/jetbrains/annotations/**",
|
||||
@@ -70,6 +195,7 @@ tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJ
|
||||
"org/checkerframework/**",
|
||||
"com/google/errorprone/**"
|
||||
)
|
||||
|
||||
val prefix = "com.eternalcode.combat.libs"
|
||||
listOf(
|
||||
"eu.okaeri",
|
||||
@@ -82,14 +208,8 @@ tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJ
|
||||
"com.github.benmanes.caffeine",
|
||||
"com.eternalcode.commons",
|
||||
"com.eternalcode.multification",
|
||||
"io.papermc"
|
||||
).forEach { relocate(it, "$prefix.$it") }
|
||||
}
|
||||
|
||||
tasks.named<RunServer>("runServer") {
|
||||
minecraftVersion("1.19.4")
|
||||
downloadPlugins {
|
||||
url("https://github.com/retrooper/packetevents/releases/download/v2.8.0/packetevents-spigot-2.8.0.jar")
|
||||
"io.papermc.lib"
|
||||
).forEach { pack ->
|
||||
relocate(pack, "$prefix.$pack")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@ import com.eternalcode.combat.border.animation.particle.ParticleController;
|
||||
import com.eternalcode.combat.bridge.BridgeService;
|
||||
import com.eternalcode.combat.crystalpvp.RespawnAnchorListener;
|
||||
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.drop.DropKeepInventoryService;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.fight.drop.DropService;
|
||||
@@ -49,17 +52,16 @@ import com.eternalcode.combat.updater.UpdaterNotificationController;
|
||||
import com.eternalcode.combat.updater.UpdaterService;
|
||||
import com.eternalcode.commons.adventure.AdventureLegacyColorPostProcessor;
|
||||
import com.eternalcode.commons.adventure.AdventureLegacyColorPreProcessor;
|
||||
import com.eternalcode.commons.bukkit.scheduler.BukkitSchedulerImpl;
|
||||
import com.eternalcode.commons.scheduler.Scheduler;
|
||||
import com.eternalcode.commons.bukkit.scheduler.MinecraftScheduler;
|
||||
import com.eternalcode.multification.notice.Notice;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import dev.rollczi.litecommands.LiteCommands;
|
||||
import dev.rollczi.litecommands.bukkit.LiteBukkitFactory;
|
||||
import dev.rollczi.litecommands.bukkit.LiteBukkitMessages;
|
||||
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;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
@@ -73,7 +75,6 @@ import java.util.stream.Stream;
|
||||
public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
|
||||
|
||||
private static final String FALLBACK_PREFIX = "eternalcombat";
|
||||
private static final int BSTATS_METRICS_ID = 17803;
|
||||
|
||||
private FightManager fightManager;
|
||||
private FightPearlService fightPearlService;
|
||||
@@ -99,10 +100,10 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
|
||||
ConfigService configService = new ConfigService();
|
||||
|
||||
EventManager eventManager = new EventManager(this);
|
||||
Scheduler scheduler = new BukkitSchedulerImpl(this);
|
||||
|
||||
PluginConfig pluginConfig = configService.create(PluginConfig.class, new File(dataFolder, "config.yml"));
|
||||
|
||||
MinecraftScheduler scheduler = CombatSchedulerAdapter.getAdaptiveScheduler(this);
|
||||
|
||||
this.fightManager = new FightManagerImpl(eventManager);
|
||||
this.fightPearlService = new FightPearlServiceImpl(pluginConfig.pearl);
|
||||
this.fightTagOutService = new FightTagOutServiceImpl();
|
||||
@@ -157,9 +158,7 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
|
||||
.build();
|
||||
|
||||
FightTask fightTask = new FightTask(server, pluginConfig, this.fightManager, noticeService);
|
||||
this.getServer().getScheduler().runTaskTimer(this, fightTask, 20L, 20L);
|
||||
|
||||
new Metrics(this, BSTATS_METRICS_ID);
|
||||
scheduler.timer(fightTask, Duration.ofSeconds(1), Duration.ofSeconds(1));
|
||||
|
||||
Stream.of(
|
||||
new PercentDropModifier(pluginConfig.drop),
|
||||
@@ -169,14 +168,17 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
|
||||
eventManager.subscribe(
|
||||
new FightTagController(this.fightManager, pluginConfig),
|
||||
new FightUnTagController(this.fightManager, pluginConfig, logoutService),
|
||||
new FightBypassAdminController(server, pluginConfig),
|
||||
new FightBypassPermissionController(server, pluginConfig),
|
||||
new FightBypassCreativeController(server, pluginConfig),
|
||||
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, this.getServer()),
|
||||
new FightEffectController(pluginConfig.effect, this.fightEffectService, this.fightManager, server),
|
||||
new FightTagOutController(this.fightTagOutService),
|
||||
new FightMessageController(this.fightManager, noticeService, pluginConfig, this.getServer()),
|
||||
new BorderTriggerController(borderService, () -> pluginConfig.border, fightManager, server),
|
||||
new FightMessageController(this.fightManager, noticeService, pluginConfig, server),
|
||||
new BorderTriggerController(borderService, () -> pluginConfig.border, fightManager, server, scheduler),
|
||||
new ParticleController(borderService, () -> pluginConfig.border.particle, scheduler, server),
|
||||
new BorderBlockController(borderService, () -> pluginConfig.border.block, scheduler, server),
|
||||
new EndCrystalListener(this, this.fightManager, pluginConfig),
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.eternalcode.combat;
|
||||
|
||||
import com.eternalcode.commons.bukkit.scheduler.BukkitSchedulerImpl;
|
||||
import com.eternalcode.commons.bukkit.scheduler.MinecraftScheduler;
|
||||
import java.util.logging.Logger;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public final class CombatSchedulerAdapter {
|
||||
|
||||
private CombatSchedulerAdapter() {
|
||||
throw new UnsupportedOperationException("This is an utility class and cannot be instantiated");
|
||||
}
|
||||
|
||||
public static MinecraftScheduler getAdaptiveScheduler(Plugin plugin) {
|
||||
Logger logger = plugin.getLogger();
|
||||
logger.info("» Detected Bukkit/Paper environment. Using BukkitScheduler.");
|
||||
return new BukkitSchedulerImpl(plugin);
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -14,7 +14,6 @@ import java.time.Duration;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
@Command(name = "combatlog", aliases = "combat")
|
||||
@Permission("eternalcombat.reload")
|
||||
public class EternalCombatReloadCommand {
|
||||
|
||||
private static final Notice RELOAD_MESSAGE = BukkitNotice.builder()
|
||||
@@ -31,6 +30,7 @@ public class EternalCombatReloadCommand {
|
||||
|
||||
@Async
|
||||
@Execute(name = "reload")
|
||||
@Permission("eternalcombat.reload")
|
||||
void execute(@Context CommandSender sender) {
|
||||
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||
this.configService.reload();
|
||||
|
||||
@@ -2,18 +2,24 @@ package com.eternalcode.combat.border;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public record BorderPoint(int x, int y, int z, @Nullable BorderPoint inclusive) {
|
||||
public record BorderPoint(int x, int y, int z, @Nullable BorderPoint innerPoint) {
|
||||
|
||||
public BorderPoint(int x, int y, int z) {
|
||||
this(x, y, z, null);
|
||||
}
|
||||
|
||||
public BorderPoint toInclusive() {
|
||||
if (inclusive == null) {
|
||||
/**
|
||||
* This point represents an adjusted coordinate that takes into account the block's volume (thickness)
|
||||
* and is used for logical placement and grouping, especially for assigning border blocks to the
|
||||
* correct chunk when they are on the very edge of a chunk boundary.
|
||||
* This ensures the block is considered to be on the "inner" side of the border for chunk-based logic.
|
||||
*/
|
||||
@Override
|
||||
public BorderPoint innerPoint() {
|
||||
if (this.innerPoint == null) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return inclusive;
|
||||
return this.innerPoint;
|
||||
}
|
||||
|
||||
}
|
||||
+11
-10
@@ -4,6 +4,7 @@ import com.eternalcode.combat.border.event.BorderHideAsyncEvent;
|
||||
import com.eternalcode.combat.border.event.BorderShowAsyncEvent;
|
||||
import com.eternalcode.combat.event.EventManager;
|
||||
import com.eternalcode.combat.region.RegionProvider;
|
||||
import com.eternalcode.commons.bukkit.scheduler.MinecraftScheduler;
|
||||
import com.eternalcode.commons.scheduler.Scheduler;
|
||||
import dev.rollczi.litecommands.shared.Lazy;
|
||||
import java.util.ArrayList;
|
||||
@@ -19,7 +20,7 @@ import org.bukkit.entity.Player;
|
||||
|
||||
public class BorderServiceImpl implements BorderService {
|
||||
|
||||
private final Scheduler scheduler;
|
||||
private final MinecraftScheduler scheduler;
|
||||
private final EventManager eventManager;
|
||||
|
||||
private final Supplier<BorderSettings> settings;
|
||||
@@ -27,7 +28,7 @@ public class BorderServiceImpl implements BorderService {
|
||||
private final BorderTriggerIndex borderIndexes;
|
||||
private final BorderActivePointsIndex activeBorderIndex = new BorderActivePointsIndex();
|
||||
|
||||
public BorderServiceImpl(Scheduler scheduler, Server server, RegionProvider provider, EventManager eventManager, Supplier<BorderSettings> settings) {
|
||||
public BorderServiceImpl(MinecraftScheduler scheduler, Server server, RegionProvider provider, EventManager eventManager, Supplier<BorderSettings> settings) {
|
||||
this.scheduler = scheduler;
|
||||
this.eventManager = eventManager;
|
||||
this.settings = settings;
|
||||
@@ -128,8 +129,8 @@ public class BorderServiceImpl implements BorderService {
|
||||
if (borderMax.y() <= realMaxY) { // Top wall
|
||||
for (int currentX = realMinX; currentX <= realMaxX; currentX++) {
|
||||
for (int currentZ = realMinZ; currentZ <= realMaxZ; currentZ++) {
|
||||
BorderPoint inclusive = new BorderPoint(Math.max(realMinX, currentX - 1), realMaxY - 1, Math.max(realMinZ, currentZ - 1));
|
||||
addPoint(points, currentX, realMaxY, currentZ, playerLocation, inclusive);
|
||||
BorderPoint innerPoint = new BorderPoint(Math.max(realMinX, currentX - 1), realMaxY - 1, Math.max(realMinZ, currentZ - 1));
|
||||
addPoint(points, currentX, realMaxY, currentZ, playerLocation, innerPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,8 +146,8 @@ public class BorderServiceImpl implements BorderService {
|
||||
if (borderMax.x() <= realMaxX) { // East wall (right)
|
||||
for (int currentY = realMinY; currentY <= realMaxY; currentY++) {
|
||||
for (int currentZ = realMinZ; currentZ <= realMaxZ; currentZ++) {
|
||||
BorderPoint inclusive = new BorderPoint(realMaxX - 1, Math.max(realMinY, currentY - 1), Math.max(realMinZ, currentZ - 1));
|
||||
addPoint(points, realMaxX, currentY, currentZ, playerLocation, inclusive);
|
||||
BorderPoint innerPoint = new BorderPoint(realMaxX - 1, Math.max(realMinY, currentY - 1), Math.max(realMinZ, currentZ - 1));
|
||||
addPoint(points, realMaxX, currentY, currentZ, playerLocation, innerPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,8 +163,8 @@ public class BorderServiceImpl implements BorderService {
|
||||
if (borderMax.z() <= realMaxZ) { // South wall (back)
|
||||
for (int currentX = realMinX; currentX <= realMaxX; currentX++) {
|
||||
for (int currentY = realMinY; currentY <= realMaxY; currentY++) {
|
||||
BorderPoint inclusive = new BorderPoint(Math.max(realMinX, currentX - 1), Math.max(realMinY, currentY - 1), realMaxZ - 1);
|
||||
addPoint(points, currentX, currentY, realMaxZ, playerLocation, inclusive);
|
||||
BorderPoint innerPoint = new BorderPoint(Math.max(realMinX, currentX - 1), Math.max(realMinY, currentY - 1), realMaxZ - 1);
|
||||
addPoint(points, currentX, currentY, realMaxZ, playerLocation, innerPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,9 +172,9 @@ public class BorderServiceImpl implements BorderService {
|
||||
return points;
|
||||
}
|
||||
|
||||
private void addPoint(List<BorderPoint> points, int x, int y, int z, Location playerLocation, BorderPoint inclusive) {
|
||||
private void addPoint(List<BorderPoint> points, int x, int y, int z, Location playerLocation, BorderPoint innerPoint) {
|
||||
if (isVisible(x, y, z, playerLocation)) {
|
||||
points.add(new BorderPoint(x, y, z, inclusive));
|
||||
points.add(new BorderPoint(x, y, z, innerPoint));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-3
@@ -3,6 +3,8 @@ package com.eternalcode.combat.border;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.fight.event.FightTagEvent;
|
||||
import com.eternalcode.combat.fight.event.FightUntagEvent;
|
||||
import com.eternalcode.commons.bukkit.scheduler.MinecraftScheduler;
|
||||
import java.time.Duration;
|
||||
import java.util.function.Supplier;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
@@ -15,16 +17,26 @@ import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
|
||||
public class BorderTriggerController implements Listener {
|
||||
|
||||
private static final long BORDER_WORK_AROUND_DELAY_MILLIS = 250;
|
||||
|
||||
private final BorderService borderService;
|
||||
private final Supplier<BorderSettings> border;
|
||||
private final FightManager fightManager;
|
||||
private final Server server;
|
||||
private final MinecraftScheduler scheduler;
|
||||
|
||||
public BorderTriggerController(BorderService borderService, Supplier<BorderSettings> border, FightManager fightManager, Server server) {
|
||||
public BorderTriggerController(
|
||||
BorderService borderService,
|
||||
Supplier<BorderSettings> border,
|
||||
FightManager fightManager,
|
||||
Server server,
|
||||
MinecraftScheduler scheduler
|
||||
) {
|
||||
this.borderService = borderService;
|
||||
this.border = border;
|
||||
this.fightManager = fightManager;
|
||||
this.server = server;
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
@@ -86,7 +98,11 @@ public class BorderTriggerController implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
borderService.clearBorder(player);
|
||||
// Due to race condition in PlayerMoveEvent and FightUntagEvent - border can be triggered after death and untag of player - solution delayed removal of border
|
||||
this.scheduler.runLater(() -> {
|
||||
if (!this.fightManager.isInCombat(player.getUniqueId())) {
|
||||
this.borderService.clearBorder(player);
|
||||
}
|
||||
}, Duration.ofMillis(BORDER_WORK_AROUND_DELAY_MILLIS));
|
||||
}
|
||||
|
||||
}
|
||||
+4
-3
@@ -2,6 +2,7 @@ package com.eternalcode.combat.border;
|
||||
|
||||
import com.eternalcode.combat.region.Region;
|
||||
import com.eternalcode.combat.region.RegionProvider;
|
||||
import com.eternalcode.commons.bukkit.scheduler.MinecraftScheduler;
|
||||
import com.eternalcode.commons.scheduler.Scheduler;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
@@ -17,13 +18,13 @@ import org.bukkit.World;
|
||||
class BorderTriggerIndex {
|
||||
|
||||
private final Server server;
|
||||
private final Scheduler scheduler;
|
||||
private final MinecraftScheduler scheduler;
|
||||
private final RegionProvider provider;
|
||||
private final Supplier<BorderSettings> settings;
|
||||
|
||||
private final Map<String, BorderTriggerIndexBucket> borderIndexes = new HashMap<>();
|
||||
|
||||
private BorderTriggerIndex(Server server, Scheduler scheduler, RegionProvider provider, Supplier<BorderSettings> settings) {
|
||||
private BorderTriggerIndex(Server server, MinecraftScheduler scheduler, RegionProvider provider, Supplier<BorderSettings> settings) {
|
||||
this.server = server;
|
||||
this.scheduler = scheduler;
|
||||
this.provider = provider;
|
||||
@@ -56,7 +57,7 @@ class BorderTriggerIndex {
|
||||
});
|
||||
}
|
||||
|
||||
static BorderTriggerIndex started(Server server, Scheduler scheduler, RegionProvider provider, Supplier<BorderSettings> settings) {
|
||||
static BorderTriggerIndex started(Server server, MinecraftScheduler scheduler, RegionProvider provider, Supplier<BorderSettings> settings) {
|
||||
BorderTriggerIndex index = new BorderTriggerIndex(server, scheduler, provider, settings);
|
||||
scheduler.timerAsync(() -> index.updateWorlds(), Duration.ZERO, settings.get().indexRefreshDelay());
|
||||
return index;
|
||||
|
||||
+102
-68
@@ -15,6 +15,7 @@ import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerMultiBlockChange;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerMultiBlockChange.EncodedBlock;
|
||||
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@@ -25,11 +26,12 @@ import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.bukkit.ChunkSnapshot;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
public class BorderBlockController implements Listener {
|
||||
|
||||
@@ -37,7 +39,7 @@ public class BorderBlockController implements Listener {
|
||||
public static final PlayerManager PLAYER_MANAGER = PACKET_EVENTS.getPlayerManager();
|
||||
public static final ClientVersion SERVER_VERSION = PACKET_EVENTS.getServerManager().getVersion().toClientVersion();
|
||||
|
||||
public static final int AIR_ID = WrappedBlockState.getDefaultState(SERVER_VERSION, StateTypes.AIR).getGlobalId();
|
||||
public static final WrappedBlockState AIR_ID = WrappedBlockState.getDefaultState(SERVER_VERSION, StateTypes.AIR);
|
||||
public static final int MINECRAFT_CHUNK_SHIFT = 4;
|
||||
|
||||
private final BorderService borderService;
|
||||
@@ -46,6 +48,7 @@ public class BorderBlockController implements Listener {
|
||||
|
||||
private final Set<UUID> playersToUpdate = ConcurrentHashMap.newKeySet();
|
||||
private final Map<UUID, Object> lockedPlayers = new ConcurrentHashMap<>();
|
||||
private final Map<UUID, Map<BorderPoint, WrappedBlockState>> originalBlocks = new ConcurrentHashMap<>();
|
||||
private final ChunkCache chunkCache;
|
||||
|
||||
public BorderBlockController(BorderService borderService, Supplier<BlockSettings> settings, Scheduler scheduler, Server server) {
|
||||
@@ -59,37 +62,52 @@ public class BorderBlockController implements Listener {
|
||||
|
||||
@EventHandler
|
||||
void onBorderShowAsyncEvent(BorderShowAsyncEvent event) {
|
||||
if (!settings.get().enabled) {
|
||||
if (!this.settings.get().enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
Set<BorderPoint> borderPoints = this.getPointsWithoutAir(player, event.getPoints());
|
||||
UUID playerId = player.getUniqueId();
|
||||
|
||||
event.setPoints(borderPoints);
|
||||
this.showBlocks(player, borderPoints);
|
||||
this.playersToUpdate.add(player.getUniqueId());
|
||||
synchronized (this.getLock(playerId)) {
|
||||
Set<BorderPoint> borderPoints = this.savePassablePoints(player, event.getPoints());
|
||||
|
||||
event.setPoints(borderPoints);
|
||||
this.showBorder(player, borderPoints);
|
||||
this.playersToUpdate.add(playerId);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onBorderHideAsyncEvent(BorderHideAsyncEvent event) {
|
||||
if (!settings.get().enabled) {
|
||||
if (!this.settings.get().enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object lock = lockedPlayers.computeIfAbsent(event.getPlayer().getUniqueId(), k -> new Object());
|
||||
synchronized (lock) {
|
||||
this.hideBlocks(event.getPlayer(), event.getPoints());
|
||||
UUID playerId = event.getPlayer().getUniqueId();
|
||||
|
||||
synchronized (this.getLock(playerId)) {
|
||||
this.hideBorder(event.getPlayer(), event.getPoints());
|
||||
|
||||
Set<BorderPoint> border = this.borderService.getActiveBorder(event.getPlayer());
|
||||
if (border.isEmpty()) {
|
||||
this.playersToUpdate.remove(event.getPlayer().getUniqueId());
|
||||
this.playersToUpdate.remove(playerId);
|
||||
this.originalBlocks.remove(playerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
void onPlayerQuit(PlayerQuitEvent event) {
|
||||
UUID playerId = event.getPlayer().getUniqueId();
|
||||
|
||||
this.playersToUpdate.remove(playerId);
|
||||
this.originalBlocks.remove(playerId);
|
||||
this.lockedPlayers.remove(playerId);
|
||||
}
|
||||
|
||||
private void updatePlayers() {
|
||||
if (!settings.get().enabled) {
|
||||
if (!this.settings.get().enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -105,93 +123,109 @@ public class BorderBlockController implements Listener {
|
||||
}
|
||||
|
||||
private void updatePlayer(UUID uuid, Player player) {
|
||||
Object lock = lockedPlayers.computeIfAbsent(uuid, k -> new Object());
|
||||
synchronized (lock) {
|
||||
synchronized (this.getLock(uuid)) {
|
||||
Set<BorderPoint> border = this.borderService.getActiveBorder(player);
|
||||
|
||||
if (border.isEmpty()) {
|
||||
this.playersToUpdate.remove(uuid);
|
||||
this.originalBlocks.remove(uuid);
|
||||
return;
|
||||
}
|
||||
|
||||
this.showBlocks(player, border);
|
||||
Set<BorderPoint> passablePoints = this.savePassablePoints(player, border);
|
||||
this.showBorder(player, passablePoints);
|
||||
}
|
||||
}
|
||||
|
||||
private void showBlocks(Player player, Collection<BorderPoint> blocks) {
|
||||
this.splitByChunks(blocks).entrySet().stream()
|
||||
.map(chunkBlocks -> toMultiBlockChangePacket(chunkBlocks))
|
||||
.forEach(change -> PLAYER_MANAGER.sendPacket(player, change));
|
||||
private void showBorder(Player player, Collection<BorderPoint> blocks) {
|
||||
this.groupByChunkPacket(blocks).forEach((chunkPos, chunkPoints) -> {
|
||||
EncodedBlock[] encodedBlocks = chunkPoints.stream()
|
||||
.map(point -> toBorderBlock(point))
|
||||
.toArray(EncodedBlock[]::new);
|
||||
|
||||
PLAYER_MANAGER.sendPacket(player, new WrapperPlayServerMultiBlockChange(chunkPos, true, encodedBlocks));
|
||||
});
|
||||
}
|
||||
|
||||
private WrapperPlayServerMultiBlockChange toMultiBlockChangePacket(Entry<Vector3i, Set<BorderPoint>> chunkBlocks) {
|
||||
EncodedBlock[] encodedBlocks = chunkBlocks.getValue().stream()
|
||||
.map(borderPoint -> this.toEncodedBlock(borderPoint))
|
||||
.toArray(value -> new EncodedBlock[value]);
|
||||
private void hideBorder(Player player, Collection<BorderPoint> blocks) {
|
||||
UUID playerId = player.getUniqueId();
|
||||
Map<BorderPoint, WrappedBlockState> savedBlocks = this.originalBlocks.get(playerId);
|
||||
|
||||
return new WrapperPlayServerMultiBlockChange(chunkBlocks.getKey(), true, encodedBlocks);
|
||||
this.groupByChunkPacket(blocks).forEach((chunkPosition, chunkPoints) -> {
|
||||
EncodedBlock[] originalBlocks = chunkPoints.stream()
|
||||
.map(point -> this.toOriginalBlock(point, savedBlocks))
|
||||
.toArray(EncodedBlock[]::new);
|
||||
|
||||
PLAYER_MANAGER.sendPacket(player, new WrapperPlayServerMultiBlockChange(chunkPosition, true, originalBlocks));
|
||||
});
|
||||
|
||||
if (savedBlocks != null) {
|
||||
blocks.forEach(key -> savedBlocks.remove(key));
|
||||
}
|
||||
}
|
||||
|
||||
private void hideBlocks(Player player, Collection<BorderPoint> blocks) {
|
||||
this.splitByChunks(blocks).entrySet().stream()
|
||||
.map(chunkBlocks -> toMultiAirChangePacket(chunkBlocks))
|
||||
.forEach(change -> PLAYER_MANAGER.sendPacket(player, change));
|
||||
}
|
||||
private Set<BorderPoint> savePassablePoints(Player player, Collection<BorderPoint> points) {
|
||||
UUID playerId = player.getUniqueId();
|
||||
Map<BorderPoint, WrappedBlockState> savedBlocks = this.originalBlocks.computeIfAbsent(playerId, key -> new ConcurrentHashMap<>());
|
||||
|
||||
private WrapperPlayServerMultiBlockChange toMultiAirChangePacket(Entry<Vector3i, Set<BorderPoint>> chunkBlocks) {
|
||||
EncodedBlock[] encodedBlocks = chunkBlocks.getValue().stream()
|
||||
.map(point -> new EncodedBlock(AIR_ID, point.x(), point.y(), point.z()))
|
||||
.toArray(value -> new EncodedBlock[value]);
|
||||
|
||||
return new WrapperPlayServerMultiBlockChange(chunkBlocks.getKey(), true, encodedBlocks);
|
||||
}
|
||||
|
||||
private Set<BorderPoint> getPointsWithoutAir(Player player, Collection<BorderPoint> blocks) {
|
||||
Map<ChunkLocation, Set<BorderPoint>> chunksToProcess = blocks.stream()
|
||||
.map(borderPoint -> borderPoint.toInclusive())
|
||||
.collect(Collectors.groupingBy(
|
||||
inclusive -> new ChunkLocation(inclusive.x() >> MINECRAFT_CHUNK_SHIFT, inclusive.z() >> MINECRAFT_CHUNK_SHIFT),
|
||||
Collectors.toSet()
|
||||
));
|
||||
|
||||
return chunksToProcess.entrySet().stream()
|
||||
.flatMap(entry -> getPointsWithoutAirOnChunk(player, entry))
|
||||
return this.groupByChunk(points).entrySet().stream()
|
||||
.flatMap(entry -> this.savePassableBlock(player, entry, savedBlocks))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private Stream<BorderPoint> getPointsWithoutAirOnChunk(Player player, Entry<ChunkLocation, Set<BorderPoint>> entry) {
|
||||
ChunkSnapshot snapshot = this.chunkCache.loadSnapshot(player, entry.getKey());
|
||||
private Stream<BorderPoint> savePassableBlock(Player player, Entry<ChunkLocation, Set<BorderPoint>> entry, Map<BorderPoint, WrappedBlockState> savedBlocks) {
|
||||
ChunkSnapshot snapshot = this.chunkCache.loadSnapshot(player, entry.getKey());
|
||||
|
||||
if (snapshot == null) {
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
return entry.getValue().stream()
|
||||
.filter(point -> isAir(entry.getKey(), point, snapshot));
|
||||
ChunkLocation chunk = entry.getKey();
|
||||
return entry.getValue().stream().filter(point -> this.saveBlockIfPassable(point, chunk, snapshot, savedBlocks));
|
||||
}
|
||||
|
||||
private static boolean isAir(ChunkLocation location, BorderPoint point, ChunkSnapshot chunk) {
|
||||
int xInsideChunk = point.x() - (location.x() << MINECRAFT_CHUNK_SHIFT);
|
||||
int zInsideChunk = point.z() - (location.z() << MINECRAFT_CHUNK_SHIFT);
|
||||
Material material = chunk.getBlockType(xInsideChunk, point.y(), zInsideChunk);
|
||||
private boolean saveBlockIfPassable(BorderPoint point, ChunkLocation chunk, ChunkSnapshot snapshot, Map<BorderPoint, WrappedBlockState> savedBlocks) {
|
||||
int localX = point.x() - (chunk.x() << MINECRAFT_CHUNK_SHIFT);
|
||||
int localZ = point.z() - (chunk.z() << MINECRAFT_CHUNK_SHIFT);
|
||||
|
||||
return material.isAir();
|
||||
BlockData blockData = snapshot.getBlockData(localX, point.y(), localZ);
|
||||
if (blockData.getMaterial().isSolid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
savedBlocks.put(point, SpigotConversionUtil.fromBukkitBlockData(blockData));
|
||||
return true;
|
||||
}
|
||||
|
||||
private Map<Vector3i, Set<BorderPoint>> splitByChunks(Collection<BorderPoint> blocks) {
|
||||
return blocks.stream().collect(Collectors.groupingBy(
|
||||
block -> new Vector3i(
|
||||
block.x() >> MINECRAFT_CHUNK_SHIFT,
|
||||
block.y() >> MINECRAFT_CHUNK_SHIFT,
|
||||
block.z() >> MINECRAFT_CHUNK_SHIFT
|
||||
),
|
||||
private EncodedBlock toBorderBlock(BorderPoint point) {
|
||||
StateType type = this.settings.get().type.getStateType(point);
|
||||
int blockId = WrappedBlockState.getDefaultState(SERVER_VERSION, type).getGlobalId();
|
||||
|
||||
return new EncodedBlock(blockId, point.x(), point.y(), point.z());
|
||||
}
|
||||
|
||||
private EncodedBlock toOriginalBlock(BorderPoint point, Map<BorderPoint, WrappedBlockState> savedBlocks) {
|
||||
WrappedBlockState blockId = savedBlocks != null ? savedBlocks.getOrDefault(point, AIR_ID) : AIR_ID;
|
||||
|
||||
return new EncodedBlock(blockId, point.x(), point.y(), point.z());
|
||||
}
|
||||
|
||||
private Map<ChunkLocation, Set<BorderPoint>> groupByChunk(Collection<BorderPoint> points) {
|
||||
return points.stream()
|
||||
.map(borderPoint -> borderPoint.innerPoint())
|
||||
.collect(Collectors.groupingBy(point -> new ChunkLocation(point.x() >> MINECRAFT_CHUNK_SHIFT, point.z() >> MINECRAFT_CHUNK_SHIFT),
|
||||
Collectors.toSet()
|
||||
));
|
||||
}
|
||||
|
||||
private EncodedBlock toEncodedBlock(BorderPoint point) {
|
||||
StateType type = settings.get().type.getStateType(point);
|
||||
WrappedBlockState state = WrappedBlockState.getDefaultState(SERVER_VERSION, type);
|
||||
return new EncodedBlock(state.getGlobalId(), point.x(), point.y(), point.z());
|
||||
private Map<Vector3i, Set<BorderPoint>> groupByChunkPacket(Collection<BorderPoint> points) {
|
||||
return points.stream().collect(Collectors.groupingBy(
|
||||
point -> new Vector3i(point.x() >> MINECRAFT_CHUNK_SHIFT, point.y() >> MINECRAFT_CHUNK_SHIFT, point.z() >> MINECRAFT_CHUNK_SHIFT),
|
||||
Collectors.toSet()
|
||||
));
|
||||
}
|
||||
|
||||
private Object getLock(UUID uuid) {
|
||||
return this.lockedPlayers.computeIfAbsent(uuid, k -> new Object());
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ public class BridgeService {
|
||||
|
||||
initialize(
|
||||
"PlaceholderAPI",
|
||||
() -> new FightTagPlaceholder(this.fightManager, server, this.plugin).register(),
|
||||
() -> new FightTagPlaceholder(this.config, this.fightManager, server, this.plugin).register(),
|
||||
() -> this.logger.warning("PlaceholderAPI not found; skipping placeholders.")
|
||||
);
|
||||
}
|
||||
|
||||
+75
-53
@@ -1,5 +1,7 @@
|
||||
package com.eternalcode.combat.bridge.placeholder;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PlaceholderSettings;
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.fight.FightTag;
|
||||
import com.eternalcode.combat.util.DurationUtil;
|
||||
@@ -14,23 +16,93 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class FightTagPlaceholder extends PlaceholderExpansion {
|
||||
|
||||
private static final String IDENTIFIER = "eternalcombat";
|
||||
|
||||
private final PlaceholderSettings placeholderSettings;
|
||||
private final FightManager fightManager;
|
||||
private final Server server;
|
||||
private final Plugin plugin;
|
||||
private static final String IDENTIFIER = "eternalcombat";
|
||||
|
||||
public FightTagPlaceholder(FightManager fightManager, Server server, Plugin plugin) {
|
||||
public FightTagPlaceholder(PluginConfig pluginConfig, FightManager fightManager, Server server, Plugin plugin) {
|
||||
this.placeholderSettings = pluginConfig.placeholders;
|
||||
this.fightManager = fightManager;
|
||||
this.server = server;
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String onRequest(OfflinePlayer player, String identifier) {
|
||||
return switch (identifier) {
|
||||
case "remaining_millis" -> this.handleRemainingMillis(player);
|
||||
case "remaining_seconds" -> this.handleRemainingSeconds(player);
|
||||
case "opponent" -> this.handleOpponent(player);
|
||||
case "opponent_health" -> this.handleOpponentHealth(player);
|
||||
case "isInCombat" -> this.handleIsInCombat(player);
|
||||
case "isInCombat_formatted" -> this.handleIsInCombatFormatted(player);
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private String handleRemainingMillis(OfflinePlayer player) {
|
||||
return this.getFightTag(player)
|
||||
.map(tag -> DurationParser.TIME_UNITS.format(tag.getRemainingDuration()))
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
private String handleRemainingSeconds(OfflinePlayer player) {
|
||||
return this.getFightTag(player)
|
||||
.map(tag -> DurationUtil.format(tag.getRemainingDuration()))
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
private String handleOpponent(OfflinePlayer player) {
|
||||
return this.getTagger(player)
|
||||
.map(Player::getName)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
private String handleOpponentHealth(OfflinePlayer player) {
|
||||
return this.getTagger(player)
|
||||
.map(tagger -> String.format("%.2f", tagger.getHealth()))
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
private String handleIsInCombat(OfflinePlayer player) {
|
||||
return String.valueOf(this.isPlayerInCombat(player));
|
||||
}
|
||||
|
||||
private String handleIsInCombatFormatted(OfflinePlayer player) {
|
||||
return this.isPlayerInCombat(player)
|
||||
? this.placeholderSettings.isInCombatFormattedTrue
|
||||
: this.placeholderSettings.isInCombatFormattedFalse;
|
||||
}
|
||||
|
||||
private boolean isPlayerInCombat(OfflinePlayer player) {
|
||||
Player onlinePlayer = player.getPlayer();
|
||||
return onlinePlayer != null && this.fightManager.isInCombat(onlinePlayer.getUniqueId());
|
||||
}
|
||||
|
||||
private @NotNull Optional<Player> getTagger(OfflinePlayer player) {
|
||||
return this.getFightTag(player)
|
||||
.map(FightTag::getTagger)
|
||||
.map(this.server::getPlayer);
|
||||
}
|
||||
|
||||
private Optional<FightTag> getFightTag(OfflinePlayer player) {
|
||||
Player onlinePlayer = player.getPlayer();
|
||||
|
||||
if (onlinePlayer == null || !this.fightManager.isInCombat(onlinePlayer.getUniqueId())) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(this.fightManager.getTag(onlinePlayer.getUniqueId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRegister() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull String getIdentifier() {
|
||||
return IDENTIFIER;
|
||||
@@ -45,54 +117,4 @@ public class FightTagPlaceholder extends PlaceholderExpansion {
|
||||
public @NotNull String getVersion() {
|
||||
return this.plugin.getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String onRequest(OfflinePlayer player, String identifier) {
|
||||
if (identifier.equals("remaining_seconds")) {
|
||||
return this.getFightTag(player)
|
||||
.map(fightTagInter -> DurationUtil.format(fightTagInter.getRemainingDuration()))
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
if (identifier.equals("remaining_millis")) {
|
||||
return this.getFightTag(player)
|
||||
.map(fightTag -> DurationParser.TIME_UNITS.format(fightTag.getRemainingDuration()))
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
if (identifier.equals("opponent")) {
|
||||
return this.getTagger(player)
|
||||
.map(tagger -> tagger.getName())
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
if (identifier.equals("opponent_health")) {
|
||||
return this.getTagger(player)
|
||||
.map(tagger -> String.format("%.2f", tagger.getHealth()))
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private @NotNull Optional<Player> getTagger(OfflinePlayer player) {
|
||||
return this.getFightTag(player)
|
||||
.map(fightTagInter -> fightTagInter.getTagger())
|
||||
.map(taggerId -> this.server.getPlayer(taggerId));
|
||||
}
|
||||
|
||||
private Optional<FightTag> getFightTag(OfflinePlayer player) {
|
||||
Player onlinePlayer = player.getPlayer();
|
||||
|
||||
if (onlinePlayer != null) {
|
||||
if (!this.fightManager.isInCombat(onlinePlayer.getUniqueId())) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(this.fightManager.getTag(onlinePlayer.getUniqueId()));
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.eternalcode.combat.config.implementation;
|
||||
|
||||
import eu.okaeri.configs.OkaeriConfig;
|
||||
import eu.okaeri.configs.annotation.Comment;
|
||||
|
||||
public class PlaceholderSettings extends OkaeriConfig {
|
||||
|
||||
@Comment("Text returned by %eternalcombat_isInCombat_formatted% placeholder when the player is in combat")
|
||||
public String isInCombatFormattedTrue = "In Combat";
|
||||
|
||||
@Comment("Text returned by %eternalcombat_isInCombat_formatted% placeholder when the player is out of combat")
|
||||
public String isInCombatFormattedFalse = "Not In Combat";
|
||||
|
||||
}
|
||||
+7
@@ -105,6 +105,13 @@ public class PluginConfig extends OkaeriConfig {
|
||||
})
|
||||
public CombatSettings combat = new CombatSettings();
|
||||
|
||||
@Comment({
|
||||
" ",
|
||||
"# Settings related to placeholders used in the plugin.",
|
||||
"# Configure default values returned by placeholders"
|
||||
})
|
||||
public PlaceholderSettings placeholders = new PlaceholderSettings();
|
||||
|
||||
@Comment({
|
||||
" ",
|
||||
"# Customize the messages displayed by the plugin.",
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.eternalcode.combat.fight.controller;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.event.CancelTagReason;
|
||||
import com.eternalcode.combat.fight.event.FightTagEvent;
|
||||
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;
|
||||
|
||||
public class FightBypassAdminController implements Listener {
|
||||
|
||||
private final Server server;
|
||||
private final PluginConfig config;
|
||||
|
||||
public FightBypassAdminController(Server server, PluginConfig config) {
|
||||
this.server = server;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
void onFightTagEvent(FightTagEvent event) {
|
||||
UUID uniqueId = event.getPlayer();
|
||||
|
||||
Player player = this.server.getPlayer(uniqueId);
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.config.admin.excludeAdminsFromCombat && player.isOp()) {
|
||||
event.setCancelReason(CancelTagReason.ADMIN);
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.eternalcode.combat.fight.controller;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.event.CancelTagReason;
|
||||
import com.eternalcode.combat.fight.event.FightTagEvent;
|
||||
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.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
public class FightBypassCreativeController implements Listener {
|
||||
|
||||
private final Server server;
|
||||
private final PluginConfig config;
|
||||
|
||||
public FightBypassCreativeController(Server server, PluginConfig config) {
|
||||
this.server = server;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
void onFightTagEvent(FightTagEvent event) {
|
||||
UUID uniqueId = event.getPlayer();
|
||||
|
||||
Player player = this.server.getPlayer(uniqueId);
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.config.admin.excludeCreativePlayersFromCombat && player.getGameMode() == GameMode.CREATIVE) {
|
||||
event.setCancelReason(CancelTagReason.CREATIVE_MODE);
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.eternalcode.combat.fight.controller;
|
||||
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.event.CancelTagReason;
|
||||
import com.eternalcode.combat.fight.event.FightTagEvent;
|
||||
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;
|
||||
|
||||
public class FightBypassPermissionController implements Listener {
|
||||
|
||||
private static final String BYPASS_PERMISSION = "eternalcombat.bypass";
|
||||
|
||||
private final Server server;
|
||||
private final PluginConfig config;
|
||||
|
||||
public FightBypassPermissionController(Server server, PluginConfig config) {
|
||||
this.server = server;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
void onFightTagEvent(FightTagEvent event) {
|
||||
UUID uniqueId = event.getPlayer();
|
||||
|
||||
Player player = this.server.getPlayer(uniqueId);
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.hasPermission(BYPASS_PERMISSION) && this.config.admin.excludeAdminsFromCombat) {
|
||||
event.setCancelReason(CancelTagReason.PERMISSION_BYPASS);
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
-30
@@ -4,7 +4,6 @@ import com.eternalcode.combat.WhitelistBlacklistMode;
|
||||
import com.eternalcode.combat.config.implementation.PluginConfig;
|
||||
import com.eternalcode.combat.fight.FightManager;
|
||||
import com.eternalcode.combat.fight.event.CauseOfTag;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
@@ -56,14 +55,6 @@ public class FightTagController implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.cannotBeTagged(attacker)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.cannotBeTagged(attackedPlayerByPerson)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.config.combat.disableFlying) {
|
||||
if (attackedPlayerByPerson.isFlying()) {
|
||||
attackedPlayerByPerson.setFlying(false);
|
||||
@@ -99,15 +90,6 @@ public class FightTagController implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.cannotBeTagged(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasBypass = player.hasPermission("eternalcombat.bypass");
|
||||
if (hasBypass) {
|
||||
return;
|
||||
}
|
||||
|
||||
Duration combatTime = this.config.settings.combatTimerDuration;
|
||||
UUID uuid = player.getUniqueId();
|
||||
|
||||
@@ -145,18 +127,6 @@ public class FightTagController implements Listener {
|
||||
return this.config.settings.ignoredWorlds.contains(worldName);
|
||||
}
|
||||
|
||||
private boolean cannotBeTagged(Player player) {
|
||||
if (this.config.admin.excludeAdminsFromCombat && player.hasPermission("eternalcombat.bypass")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.config.admin.excludeAdminsFromCombat && player.isOp()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.config.admin.excludeCreativePlayersFromCombat && player.getGameMode() == GameMode.CREATIVE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+17
-14
@@ -4,7 +4,8 @@ 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.scheduler.Scheduler;
|
||||
import com.eternalcode.commons.bukkit.scheduler.MinecraftScheduler;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -12,18 +13,18 @@ import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public final class KnockbackService {
|
||||
|
||||
private final PluginConfig config;
|
||||
private final Scheduler scheduler;
|
||||
private final MinecraftScheduler scheduler;
|
||||
private final RegionProvider regionProvider;
|
||||
|
||||
private final Map<UUID, Region> insideRegion = new HashMap<>();
|
||||
|
||||
public KnockbackService(PluginConfig config, Scheduler scheduler, RegionProvider regionProvider) {
|
||||
public KnockbackService(PluginConfig config, MinecraftScheduler scheduler, RegionProvider regionProvider) {
|
||||
this.config = config;
|
||||
this.scheduler = scheduler;
|
||||
this.regionProvider = regionProvider;
|
||||
@@ -39,17 +40,20 @@ public final class KnockbackService {
|
||||
}
|
||||
|
||||
insideRegion.put(player.getUniqueId(), region);
|
||||
scheduler.runLater(() -> {
|
||||
insideRegion.remove(player.getUniqueId());
|
||||
Location playerLocation = player.getLocation();
|
||||
if (!region.contains(playerLocation) && !regionProvider.isInRegion(playerLocation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Location location = generate(playerLocation, Point2D.from(region.getMin()), Point2D.from(region.getMax()));
|
||||
scheduler.runLater(
|
||||
player.getLocation(), () -> {
|
||||
insideRegion.remove(player.getUniqueId());
|
||||
Location playerLocation = player.getLocation();
|
||||
if (!region.contains(playerLocation) && !regionProvider.isInRegion(playerLocation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
player.teleport(location, PlayerTeleportEvent.TeleportCause.PLUGIN);
|
||||
}, this.config.knockback.forceDelay);
|
||||
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) {
|
||||
@@ -73,5 +77,4 @@ public final class KnockbackService {
|
||||
|
||||
player.setVelocity(knockbackVector.multiply(configuredVector));
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -85,7 +85,7 @@ public class WorldGuardRegionProvider implements RegionProvider {
|
||||
@Nullable
|
||||
private ProtectedRegion highestPriorityRegion(ApplicableRegionSet applicableRegions) {
|
||||
return applicableRegions.getRegions().stream()
|
||||
.min(Comparator.comparingInt(ProtectedRegion::getPriority))
|
||||
.max(Comparator.comparingInt(ProtectedRegion::getPriority))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
|
||||
+12
-16
@@ -1,6 +1,7 @@
|
||||
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;
|
||||
@@ -9,12 +10,9 @@ import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class UpdaterNotificationController implements Listener {
|
||||
|
||||
private static final String NEW_VERSION_AVAILABLE = "<b><gradient:#8a1212:#fc6b03>EternalCombat:</gradient></b> <color:#fce303>New version of EternalCombat is available, please update!";
|
||||
private static final String RECEIVE_UPDATES_PERMISSION = "eternalcombat.receiveupdates";
|
||||
|
||||
private final UpdaterService updaterService;
|
||||
private final PluginConfig pluginConfig;
|
||||
@@ -33,23 +31,21 @@ public class UpdaterNotificationController implements Listener {
|
||||
Player player = event.getPlayer();
|
||||
Audience audience = this.audienceProvider.player(player.getUniqueId());
|
||||
|
||||
if (!player.hasPermission(RECEIVE_UPDATES_PERMISSION) || !this.pluginConfig.settings.notifyAboutUpdates) {
|
||||
if (!shouldNotify(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
CompletableFuture<Boolean> upToDate = this.updaterService.isUpToDate();
|
||||
this.updaterService.checkForUpdate()
|
||||
.thenAccept(result -> {
|
||||
if (result.isUpdateAvailable()) {
|
||||
audience.sendMessage(this.miniMessage.deserialize(NEW_VERSION_AVAILABLE));
|
||||
}
|
||||
})
|
||||
.exceptionally(FutureHandler::handleException);
|
||||
}
|
||||
|
||||
upToDate.whenComplete((isUpToDate, throwable) -> {
|
||||
if (throwable != null) {
|
||||
throwable.printStackTrace();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isUpToDate) {
|
||||
audience.sendMessage(this.miniMessage.deserialize(NEW_VERSION_AVAILABLE));
|
||||
}
|
||||
});
|
||||
private boolean shouldNotify(Player player) {
|
||||
return player.hasPermission("eternalcombat.receiveupdates") && this.pluginConfig.settings.notifyAboutUpdates;
|
||||
}
|
||||
|
||||
}
|
||||
+17
-19
@@ -1,35 +1,33 @@
|
||||
package com.eternalcode.combat.updater;
|
||||
|
||||
import com.eternalcode.gitcheck.GitCheck;
|
||||
import com.eternalcode.gitcheck.GitCheckResult;
|
||||
import com.eternalcode.gitcheck.git.GitRepository;
|
||||
import com.eternalcode.gitcheck.git.GitTag;
|
||||
import dev.rollczi.litecommands.shared.Lazy;
|
||||
import com.eternalcode.commons.updater.UpdateResult;
|
||||
import com.eternalcode.commons.updater.Version;
|
||||
import com.eternalcode.commons.updater.impl.ModrinthUpdateChecker;
|
||||
import com.github.benmanes.caffeine.cache.AsyncLoadingCache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class UpdaterService {
|
||||
|
||||
private static final GitRepository GIT_REPOSITORY = GitRepository.of("EternalCodeTeam", "EternalCombat");
|
||||
private static final String MODRINTH_PROJECT_ID = "EternalCombat";
|
||||
private static final String CACHE_KEY = "modrinth-update";
|
||||
|
||||
private final GitCheck gitCheck = new GitCheck();
|
||||
private final Lazy<GitCheckResult> gitCheckResult;
|
||||
private final AsyncLoadingCache<String, UpdateResult> updateCache;
|
||||
|
||||
public UpdaterService(PluginDescriptionFile descriptionFile) {
|
||||
this.gitCheckResult = new Lazy<>(() -> {
|
||||
String version = descriptionFile.getVersion();
|
||||
Version currentVersion = new Version(descriptionFile.getVersion());
|
||||
ModrinthUpdateChecker updateChecker = new ModrinthUpdateChecker();
|
||||
|
||||
return this.gitCheck.checkRelease(GIT_REPOSITORY, GitTag.of("v" + version));
|
||||
});
|
||||
this.updateCache = Caffeine.newBuilder()
|
||||
.expireAfterWrite(Duration.ofHours(1))
|
||||
.buildAsync(key -> updateChecker.check(MODRINTH_PROJECT_ID, currentVersion));
|
||||
}
|
||||
|
||||
public CompletableFuture<Boolean> isUpToDate() {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
GitCheckResult result = this.gitCheckResult.get();
|
||||
|
||||
return result.isUpToDate();
|
||||
});
|
||||
CompletableFuture<UpdateResult> checkForUpdate() {
|
||||
return this.updateCache.get(CACHE_KEY);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+5
-3
@@ -1,5 +1,7 @@
|
||||
org.gradle.configuration-cache=false
|
||||
org.gradle.caching=true
|
||||
org.gradle.parallel=true
|
||||
org.gradle.vfs.watch=false
|
||||
org.gradle.caching=true
|
||||
org.gradle.configuration-cache=true
|
||||
org.gradle.configuration-cache.parallel=true
|
||||
|
||||
# Platforms
|
||||
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
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -114,7 +114,6 @@ case "$( uname )" in #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH="\\\"\\\""
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@@ -172,7 +171,6 @@ fi
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
@@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
|
||||
Vendored
+1
-2
@@ -70,11 +70,10 @@ goto fail
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
||||
Reference in new issue
Block a user