Compare commits

..

128 Commits

Author SHA1 Message Date
Auxilor
525cc019ea Updated kotlin gradle plugin 2022-02-03 18:53:19 +00:00
Auxilor
04f2d15783 Fixed missing compileKotlin options 2022-02-03 18:46:36 +00:00
Auxilor
f988b591a4 Updated kotlin 2022-02-03 18:42:53 +00:00
Auxilor
9ebfb124c8 Refactored build logic 2022-02-03 18:42:01 +00:00
Auxilor
b9ab263f67 Updated CONTRIBUTING.md 2022-02-03 17:54:44 +00:00
Auxilor
bb5f68283b Updated empty (default) EcoPlugin constructor 2022-02-03 17:51:54 +00:00
Auxilor
9bbf1cfe36 Added EcoPlugin#mutateProps 2022-02-03 17:49:26 +00:00
Auxilor
19bb5f608c Updated more javadoc 2022-02-03 17:46:31 +00:00
Auxilor
a1c70d2081 Corrected PluginProps javadoc 2022-02-03 17:43:40 +00:00
Auxilor
979ddf0ff0 Safety checks to FastItemStack 2022-02-03 17:41:45 +00:00
Auxilor
232a63c00d Cleaned up FillerMask 2022-02-03 17:22:46 +00:00
Auxilor
e65cf9be2c Added extra methods to Items 2022-02-03 17:17:01 +00:00
Auxilor
fbf56037d4 Deprecated MaskMaterials in favour of MaskItems 2022-02-03 16:54:52 +00:00
Auxilor
aa0c4ee7fa Refactored props name 2022-02-03 16:08:18 +00:00
Auxilor
5f3375bf87 Added props validation 2022-02-03 15:11:15 +00:00
Auxilor
11dc6d0e67 Allowed custom props parameter 2022-02-03 15:06:35 +00:00
Auxilor
9cccbd10ba Removed need to reflectively instantiate props 2022-02-03 15:02:45 +00:00
Auxilor
1f0ad48480 Updated props javadoc 2022-02-03 14:58:12 +00:00
Auxilor
93322dcfa5 Updated props javadoc 2022-02-03 14:56:29 +00:00
Auxilor
e3b630fcb7 Improved props system 2022-02-03 14:54:43 +00:00
Auxilor
8690b75f4c Added namespacedKeyOf 2022-02-03 14:19:59 +00:00
Auxilor
6de792f308 Added more durability utils 2022-02-03 14:17:41 +00:00
Auxilor
e59037635e Removed debug from eco.yml 2022-02-03 13:52:48 +00:00
Auxilor
b9d50e261d Fixed missing javadoc 2022-02-03 13:44:15 +00:00
Auxilor
15173c8369 Finally added eco.yml 2022-02-03 13:38:14 +00:00
Auxilor
4ee0645a4e Codestyle 2022-02-03 12:57:29 +00:00
Auxilor
96bd53c089 Codestyle 2022-02-03 12:36:49 +00:00
Auxilor
e658bf3fa8 Removed redundant suppression 2022-02-03 12:36:14 +00:00
Auxilor
988836b5b9 Deprecated UnsupportedVersionException in favour of UnsupportedVersionError 2022-02-03 12:32:46 +00:00
Auxilor
5688f41b8b Fixed deprecation 2022-02-03 12:27:47 +00:00
Auxilor
4eaa6ab75c Fixed build issue 2022-02-03 12:25:39 +00:00
Auxilor
b29363cdf6 Fixed javadoc 2022-02-03 12:22:05 +00:00
Auxilor
c8648a92f5 Resolved PlayerUtils ambiguity in kotlin 2022-02-03 12:10:29 +00:00
Auxilor
0a59b6a208 ProxyFactory error changes 2022-02-03 12:06:00 +00:00
Auxilor
4e18a0ab78 Updated proxy errors 2022-02-03 12:05:22 +00:00
Auxilor
d49405f839 Updated create2DList method signature 2022-02-03 11:47:26 +00:00
Auxilor
e10566da66 Deprecated TeamUtils#getMaterialColorTeam 2022-02-03 11:45:56 +00:00
Auxilor
0c64cd98e0 Updated to 6.24.0 2022-02-03 11:43:47 +00:00
Auxilor
231af30c61 Deprecated + Marked requirement system for removal 2022-02-03 11:41:58 +00:00
Auxilor
9b5cc1fd9c Added more kotlin utilities 2022-02-03 11:23:07 +00:00
Auxilor
7628c0bbfd Renamed FastItemStack methods 2022-02-03 11:17:29 +00:00
Auxilor
0beedc6b07 Updated kotlin to use kotlin API 2022-02-03 11:09:36 +00:00
Auxilor
f3c69f1c15 Added NumberUtils extensions 2022-02-03 11:08:20 +00:00
Auxilor
a148f667e5 Added kotlin builder for commands and PlayerUtils#runExempted 2022-02-03 11:07:04 +00:00
Auxilor
b2370b4b6e Player only commands now can have non-player only subcommands 2022-02-03 10:41:24 +00:00
Auxilor
525bd5264a Removed checkstyle suppressions 2022-02-03 10:34:43 +00:00
Auxilor
54c27a0379 More CI changes 2022-02-03 10:30:22 +00:00
Auxilor
989dda0a4f Updated CI workflows 2022-02-03 10:25:38 +00:00
Auxilor
1f2bb3341e Suppression 2022-02-02 16:54:09 +00:00
Auxilor
65221bdddf Deprecated SlotModifier, replaced with SlotUpdater 2022-02-02 16:52:52 +00:00
Auxilor
b386f2df1b Updated CONTRIBUTING.md 2022-02-02 16:38:05 +00:00
Auxilor
969329486d Reverted publication changes 2022-02-02 16:00:01 +00:00
Auxilor
aab2e8237c Gave up trying to have separate java and kotlin modules 2022-02-02 15:57:45 +00:00
Auxilor
30457c29a1 Gave up trying to have separate java and kotlin modules 2022-02-02 15:57:37 +00:00
Auxilor
9ad480ecf0 Shadow publication attempt 1 2022-02-02 15:50:43 +00:00
Auxilor
b0d3256d1b Fixed conflicting jvm names 2022-02-02 14:23:51 +00:00
Auxilor
4ff9d82cc1 Added kotlin builders for GUIs 2022-02-02 13:21:28 +00:00
Auxilor
f9178e248b Updated paperweight userdev 2022-02-02 12:47:56 +00:00
Auxilor
cc8a799438 Added log-full-extension-errors 2022-02-02 12:46:49 +00:00
Auxilor
90b81f56df Codestyle 2022-02-02 12:43:55 +00:00
Auxilor
1240c14c14 Added kotlin extensions 2022-02-02 12:42:38 +00:00
Auxilor
ed46900f2f Re-added NMS Modules after build checks 2022-02-02 12:20:33 +00:00
Auxilor
dade3d7fbb Fixed build.gradle in eco-api 2022-02-02 12:16:39 +00:00
Auxilor
df141875d3 Updated CI workflows 2022-02-02 12:15:34 +00:00
Auxilor
50b07de5d1 Updated CI workflows 2022-02-02 12:13:58 +00:00
Auxilor
e2a033c24f Dev changes 2022-02-02 12:13:36 +00:00
Auxilor
3fa574105f Hopefully resolved circular dependencies 2022-02-02 11:40:39 +00:00
Auxilor
a64386f980 Hopefully resolved circular dependencies 2022-02-02 11:40:03 +00:00
Auxilor
4c5a0f9887 Even more buildscript changes 2022-02-02 11:31:21 +00:00
Auxilor
cbd43f5757 More buildscript changes 2022-02-02 11:24:33 +00:00
Auxilor
01f1425557 buildscript changes 2022-02-02 11:24:12 +00:00
Auxilor
25e8cc0837 Refactored API, added kotlin extensions 2022-02-02 11:22:19 +00:00
Auxilor
7ff3eeef06 Updated to 6.22.3 2022-02-01 19:09:24 +00:00
Auxilor
58faf6de23 Fixed more server profile issues 2022-02-01 19:09:10 +00:00
Auxilor
7f42cbe32e Updated to 6.22.2 2022-02-01 18:55:18 +00:00
Auxilor
ae12ab17fe Fixed server profile 2022-02-01 18:55:07 +00:00
Auxilor
9949ed4f5f Updated to 6.22.1 2022-02-01 18:16:47 +00:00
Auxilor
e3f81a51e8 Revert "Fixed WorldGuard antigrief integration"
This reverts commit feebbd8ec7.
2022-02-01 18:16:27 +00:00
Auxilor
a06d782dea Cleaned up StringUtils 2022-02-01 14:12:03 +00:00
Auxilor
7e60ee63ea Merge branch '0ft3n_master' into develop 2022-02-01 14:04:50 +00:00
Auxilor
e349f47e66 Swapped out guava cache for caffeine 2022-02-01 14:04:00 +00:00
Auxilor
f710a69455 Changed cache expiry times 2022-02-01 13:49:35 +00:00
Auxilor
20b06be1f2 Changed item cache off to guava 2022-02-01 13:24:36 +00:00
Auxilor
9992820580 Items changes 2022-02-01 13:17:52 +00:00
0ft3n
feebbd8ec7 Fixed WorldGuard antigrief integration 2022-02-01 15:26:40 +03:00
Auxilor
5302aa07a5 Un-did thing? 2022-02-01 11:19:23 +00:00
Auxilor
d124c5b274 Fixed build issues 2022-02-01 11:08:08 +00:00
Auxilor
f188919197 Fixed wrong suppression 2022-02-01 11:04:24 +00:00
Auxilor
388268e906 Minor changes 2022-02-01 11:03:02 +00:00
Auxilor
6367867d2b Suppressed warnings 2022-02-01 11:01:36 +00:00
Auxilor
291357e235 Updated to 6.22.0 2022-02-01 10:55:13 +00:00
Auxilor
07178b0645 Added cache to string formats 2022-02-01 10:54:13 +00:00
Auxilor
70ef99e875 Added guava caches to performance-sensitive components 2022-02-01 10:44:19 +00:00
Auxilor
885a7835ea Fixed CrashClaim integration not being registered 2022-02-01 10:09:41 +00:00
Auxilor
94e9b47f02 Renaming 2022-02-01 10:08:21 +00:00
Auxilor
e8f4bdd4aa Added toString methods on profile impl 2022-02-01 10:07:25 +00:00
Auxilor
c01e409904 Added ServerProfile, internal annotations 2022-02-01 10:06:39 +00:00
Auxilor
f1cf82160e Rewrote custom recipe listener in kotlin 2022-02-01 09:46:59 +00:00
0ft3n
d1c15f8699 Merge branch 'Auxilor:master' into master 2022-01-29 20:41:22 +03:00
_OfTeN_
be6e7b1f46 Added RPGHorses Antigrief integration
Fixed CustoMCrafting compatibility

Updated CustomCrafting Items lookup integration

Added a warning for empty recipes
2022-01-29 00:25:13 +03:00
Auxilor
b78fc2fb66 Suppressed warning 2022-01-28 09:30:57 +00:00
Auxilor
23a297b8e3 Updated to 6.21.1 2022-01-28 09:15:39 +00:00
Auxilor
4e99ca51f0 PR Codestyle 2022-01-28 09:15:16 +00:00
NicoNekoDev
47c93a6dbe Fix strange imports 2022-01-28 01:16:28 +02:00
NicoNekoDev
da7f47d1ba Fix getCustomItem lookup system for better performance 2022-01-28 01:14:55 +02:00
_OfTeN_
144ea0dd10 Added silent arg parser for entities 2022-01-27 16:51:39 +03:00
Auxilor
732aaa3bf1 Fixed NamespacedKeyUtils.fromString 2022-01-27 13:23:25 +00:00
Auxilor
a38387be33 Fixed more stupidity 2022-01-27 13:16:42 +00:00
Auxilor
582f9b08f3 Fixed stupidity 2022-01-27 13:15:19 +00:00
Auxilor
638367cbb2 Switched objenesis instantiator 2022-01-27 13:08:59 +00:00
Auxilor
ec35e7d779 Fixed lateinit issues 2022-01-27 13:04:33 +00:00
Auxilor
1cc2a585d6 NamespacedKey changes 2022-01-27 12:51:22 +00:00
Auxilor
aa553b96d6 Updated to 6.21.0 2022-01-27 12:41:53 +00:00
Auxilor
feb7ecee48 Added fast NamespacedKey creation 2022-01-27 12:41:18 +00:00
Auxilor
c0be6a12ff Changed behaviour to not be the same as enum behaviour 2022-01-26 12:42:05 +00:00
Auxilor
1dc6b651a0 Switched PersistentDataKeyType to not be an enum 2022-01-26 12:40:15 +00:00
Auxilor
3c26c02642 Added issue template 2022-01-26 11:19:02 +00:00
Auxilor
343508f099 Updated to 6.20.4 2022-01-20 09:44:08 +00:00
Auxilor
76dc4948bc Fixed playerless placeholders 2022-01-20 09:43:53 +00:00
Auxilor
8fa209a981 Switched from shallow to deep packet cloning for async 2022-01-18 09:19:14 +00:00
Auxilor
b3a0634ad0 Updated to 6.20.3 2022-01-18 09:18:36 +00:00
Auxilor
97d7acc0a9 Tweaked async display 2022-01-18 09:18:25 +00:00
Auxilor
ebac75b0ee Updated to 6.20.2 2022-01-18 08:41:04 +00:00
Auxilor
02d0fa85b5 Updated plugin.yml 2022-01-18 08:40:53 +00:00
Auxilor
168915868c Added support for CustomCrafting and ExecutableItems 2022-01-18 08:40:38 +00:00
Auxilor
d62d598fd6 Merge branch '0ft3n_master' into develop
# Conflicts:
#	eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt
2022-01-18 08:38:53 +00:00
0ft3n
06561c5387 Removed unneeded event call 2022-01-18 02:00:10 +03:00
often
c0547a7c34 Readded and fixed CustomItems support, added ExecutableItems support 2022-01-02 13:19:35 +03:00
125 changed files with 2752 additions and 754 deletions

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Auxilor Community Discord
url: https://discord.gg/ZcwpSsE/
about: Join the Auxilor discord to get help from support staff and the general community!
- name: The most common issues people have
url: https://github.com/Auxilor/eco/issues/78
about: Check the list of known common issues to see if your issue has already been solved

31
.github/ISSUE_TEMPLATE/report-a-bug.md vendored Normal file
View File

@@ -0,0 +1,31 @@
---
name: Report a Bug
about: Report an issue with the plugin
title: ''
labels: bug
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.
**Server Information (please complete the following information):**
- Version: (output of `/ver` command)
- Version of plugin and eco (`/ver eco`, `/ver <plugin>`)
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,20 @@
---
name: Request a Feature
about: Suggest an idea for this plugin
title: ''
labels: enhancement
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.

15
.github/workflows/checkstyle.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
name: Check PR Codestyle
on: [ pull_request ]
jobs:
checkstyle:
name: Checkstyle
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: dbelyaev/action-checkstyle@v0.5.1
with:
github_token: ${{ secrets.github_token }}
reporter: github-pr-review
level: warning
checkstyle_config: ../../config/checkstyle/checkstyle.xml

View File

@@ -1,6 +1,6 @@
name: Java CI
on: [push]
on: [ push, pull_request ]
jobs:
build:

42
.github/workflows/test-publish.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: Publish API (Dev)
on: [ push, pull_request ]
jobs:
publish-release:
runs-on: ubuntu-latest
steps:
- name: Checkout latest code
uses: actions/checkout@v2
- name: Set outputs
id: vars
run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: 17
- name: Setup build cache
uses: actions/cache@v2.1.6
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Publish artifact
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# The GITHUB_REF tag comes in the format 'refs/tags/xxx'.
# So if we split on '/' and take the 3rd value, we can get the release name.
run: |
NEW_VERSION=$(echo "${GITHUB_REF}" | cut -d "/" -f3)
echo "New version: ${{ steps.vars.outputs.sha_short }}"
echo "Github username: ${GITHUB_ACTOR}"
./gradlew -Pversion=dev-${{ steps.vars.outputs.sha_short }} publish

View File

@@ -1,24 +1,38 @@
# How to contribute to eco
## Codestyle
1. The eco checkstyle is in /config/checkstyle.xml
- The pull request must not have any checkstyle issues.
- Every method and field must have a javadoc attached.
2. Use JetBrains annotations
- Every parameter should be annotated with @NotNull or @Nullable
- Use @NotNull over lombok @NonNull
3. Imports
- No group (*) imports.
- No static imports.
4. Kotlin
- Kotlin should be the only language used in the backend, java should be the only language used in the frontend.
- Kotlin API extensions should only be for creating extension functions and extra niceties that aren't possible in java.
Do not write API components in kotlin.
- Kotlin code should never be called directly from the frontend Java API. Kotlin API extensions should always rely on
java, not the other way round.
## Dependency Injection
- eco uses Dependency Injection
- Any calls to Eco#getHandler#getEcoPlugin are code smells and should never be used unless **absolutely necessary**.
- NamespacedKeys, FixedMetadataValues, Runnables, and Schedules should be managed using AbstractEcoPlugin through DI.
- Any DI class should extend PluginDependent where possible. If the class extends another, then you **must** store the plugin instance in a private final variable called **plugin** with a private or protected getter.
- Any DI class should extend PluginDependent where possible. If the class extends another, then you **must** store the
plugin instance in a private final variable called **plugin** with a private or protected getter.
## Other
- All drops **must** be sent through a DropQueue - calls to World#dropItem will get your PR rejected.
- eco is built with java 17.

View File

@@ -1,8 +1,19 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
}
}
plugins {
id("java-library")
id("com.github.johnrengelman.shadow") version "7.1.0"
id("maven-publish")
id("java")
kotlin("jvm") version "1.6.10"
}
dependencies {
@@ -20,6 +31,7 @@ allprojects {
apply(plugin = "java-library")
apply(plugin = "maven-publish")
apply(plugin = "com.github.johnrengelman.shadow")
apply(plugin = "kotlin")
repositories {
mavenCentral()
@@ -67,19 +79,27 @@ allprojects {
// Crunch
maven("https://redempt.dev")
// LibsDisguises
maven("https://repo.md-5.net/content/groups/public/")
}
dependencies {
compileOnly(kotlin("stdlib", version = "1.6.10"))
compileOnly("org.jetbrains:annotations:23.0.0")
// Test
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
// Adventure
compileOnly("net.kyori:adventure-api:4.9.3")
compileOnly("net.kyori:adventure-text-serializer-gson:4.9.3")
compileOnly("net.kyori:adventure-text-serializer-legacy:4.9.3")
// Other
compileOnly("com.google.guava:guava:31.0.1-jre")
compileOnly("com.github.ben-manes.caffeine:caffeine:3.0.5")
}
tasks.withType<JavaCompile> {
@@ -94,14 +114,20 @@ allprojects {
exclude(group = "org.spongepowered", module = "configurate-hocon")
exclude(group = "com.darkblade12", module = "particleeffect")
exclude(group = "com.github.cryptomorin", module = "XSeries")
exclude(group = "org.apache.commons", module = "commons-lang3")
}
tasks {
compileKotlin {
kotlinOptions {
jvmTarget = "17"
}
targetCompatibility = "17"
sourceCompatibility = "17"
}
shadowJar {
relocate("org.bstats", "com.willfp.eco.shaded.bstats")
relocate("net.kyori.adventure.text.minimessage", "com.willfp.eco.shaded.minimessage")
relocate("redempt.crunch", "com.willfp.eco.shaded.crunch")
}
compileJava {

View File

@@ -32,10 +32,6 @@
-->
<module name="Checker">
<module name="SuppressionFilter">
<property name="file" value="config/checkstyle/suppression.xml"/>
</module>
<!--
If you set the basedir property below, then all reported file
names will be relative to the specified directory. See

View File

@@ -1,24 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Puppy Crawl//DTD Suppressions 1.1//EN"
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions>
<!-- Internals don't need javadoc. -->
<suppress files="[\\/]internal[\\/]" checks="MissingJavadocMethod"/>
<suppress files="[\\/]internal[\\/]" checks="JavadocVariable"/>
<suppress files="[\\/]eco[\\/]spigot[\\/]" checks="MissingJavadocMethod"/>
<suppress files="[\\/]eco[\\/]spigot[\\/]" checks="JavadocVariable"/>
<suppress files="[\\/]eco[\\/]proxy[\\/]" checks="MissingJavadocMethod"/>
<suppress files="[\\/]eco[\\/]proxy[\\/]" checks="JavadocVariable"/>
<!-- Modified version of library -->
<suppress files="ArmorEquipEvent.java" checks="JavadocVariable"/>
<suppress files="ArmorEquipEvent.java" checks="MissingJavadocMethod"/>
<suppress files="ArmorEquipEvent.java" checks="JavadocStyle"/>
<suppress files="ArmorListener.java" checks="JavadocVariable"/>
<suppress files="ArmorListener.java" checks="MissingJavadocMethod"/>
<suppress files="ArmorType.java" checks="JavadocVariable"/>
<suppress files="ArmorType.java" checks="MissingJavadocMethod"/>
</suppressions>

View File

@@ -1,10 +1,3 @@
plugins {
id 'com.github.johnrengelman.shadow'
}
group 'com.willfp'
version rootProject.version
dependencies {
// Adventure
compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0'
@@ -15,13 +8,10 @@ dependencies {
compileOnly 'org.apache.maven:maven-artifact:3.8.1'
compileOnly 'com.comphenix.protocol:ProtocolLib:4.6.1-SNAPSHOT'
compileOnly 'com.google.code.gson:gson:2.8.8'
compileOnly 'org.apache.commons:commons-lang3:3.0'
}
java {
withJavadocJar()
}
group 'com.willfp'
version rootProject.version
build.dependsOn publishToMavenLocal

View File

@@ -4,6 +4,12 @@ import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Holds the instance of the eco handler for bridging between the frontend
* and backend.
@@ -52,6 +58,24 @@ public final class Eco {
return handler;
}
/**
* Eco Handler components are internals, so if a class is marked as a handler component,
* then it should be treated the same as if it was marked with {@link ApiStatus.Internal}.
* <p>
* If a class is marked with {@link HandlerComponent}, <strong>Do not reference it in
* your code!</strong> It can and will contain breaking changes between minor versions and
* even patches, and you will create compatibility issues by using them.
* <p>
* Handler components should also be marked with {@link ApiStatus.Internal} in order to
* cause compiler / IDE warnings.
*/
@Documented
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE})
public @interface HandlerComponent {
}
private Eco() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}

View File

@@ -152,10 +152,14 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
private final ProxyFactory proxyFactory;
/**
* Create a new plugin without a specified color, proxy support, polymart, or bStats.
* Create a new plugin.
* <p>
* Will read from eco.yml (like plugin.yml) to fetch values that would otherwise be passed
* into the constructor. If no eco.yml is present, the plugin will load without extension
* support, without proxy support, with no update-checker or bStats, and with the color white.
*/
protected EcoPlugin() {
this("&f");
this((PluginProps) null);
}
/**
@@ -236,6 +240,23 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
@NotNull final String proxyPackage,
@NotNull final String color,
final boolean supportingExtensions) {
this(
PluginProps.createSimple(
resourceId,
bStatsId,
proxyPackage,
color,
supportingExtensions
)
);
}
/**
* Create a new plugin.
*
* @param pluginProps The props. If left null, it will read from eco.yml.
*/
protected EcoPlugin(@Nullable final PluginProps pluginProps) {
/*
The handler must be initialized before any plugin's constructors
are called, as the constructors call Eco#getHandler().
@@ -253,15 +274,15 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
a standalone handler class, but then there would be an interface
left in the API that doesn't really help anything.
The other alternative would be do use reflection to get a 'createHandler'
method that only exists in EcoSpigotPlugin - but that feels really dirty
The other alternative would be to use reflection to get a 'createHandler'
method that only exists in EcoSpigotPlugin - but that feels filthy,
and I'd rather only use reflection where necessary.
*/
if (Eco.getHandler() == null && this instanceof Handler) {
/*
This code is only ever called by EcoSpigotPlugin (EcoHandler)
as it's the first plugin to load and it is a handler.
as it's the first plugin to load, and it is a handler.
Any other plugins will never call this code as the handler
will have already been initialized.
@@ -272,11 +293,16 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
assert Eco.getHandler() != null;
this.resourceId = resourceId;
this.bStatsId = bStatsId;
this.proxyPackage = proxyPackage;
this.color = color;
this.supportingExtensions = supportingExtensions;
PluginProps generatedProps = Eco.getHandler().getProps(pluginProps, this.getClass());
generatedProps.validate();
PluginProps props = this.mutateProps(generatedProps);
props.validate();
this.resourceId = props.getResourceId();
this.bStatsId = props.getBStatsId();
this.proxyPackage = props.getProxyPackage();
this.color = props.getColor();
this.supportingExtensions = props.isSupportingExtensions();
this.scheduler = Eco.getHandler().createScheduler(this);
this.eventManager = Eco.getHandler().createEventManager(this);
@@ -296,8 +322,8 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
/*
The minimum eco version check was moved here because it's very common
to add a lot of code in the constructor of plugins; meaning that the plugin
can throw errors without it being obvious to the user that the reason is
because they have an outdated version of eco installed.
can throw errors without it being obvious to the user that the reason is that
they have an outdated version of eco installed.
*/
DefaultArtifactVersion runningVersion = new DefaultArtifactVersion(Eco.getHandler().getEcoPlugin().getDescription().getVersion());
@@ -534,6 +560,21 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
}
/**
* Mutate the plugin props.
* <p>
* Useful for eco-based plugin libraries to enforce certain properties, such as
* forcing extensions to be enabled.
* <p>
* Props are validated both before and after calling this method.
*
* @param props The props.
* @return The mutated props.
*/
protected PluginProps mutateProps(@NotNull final PluginProps props) {
return props;
}
/**
* The plugin-specific integrations to be tested and loaded.
*
@@ -635,7 +676,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
* @return The proxy.
*/
public final <T> T getProxy(@NotNull final Class<T> proxyClass) {
Validate.notNull(proxyFactory, "Plugin does not support proxy!");
Validate.notNull(proxyFactory, "Plugin does not support proxies!");
return proxyFactory.getProxy(proxyClass);
}

View File

@@ -2,7 +2,7 @@ package com.willfp.eco.core;
import com.willfp.eco.core.config.updating.ConfigHandler;
import com.willfp.eco.core.config.wrapper.ConfigFactory;
import com.willfp.eco.core.data.PlayerProfileHandler;
import com.willfp.eco.core.data.ProfileHandler;
import com.willfp.eco.core.data.keys.KeyRegistry;
import com.willfp.eco.core.drops.DropQueueFactory;
import com.willfp.eco.core.events.EventManager;
@@ -15,10 +15,10 @@ import com.willfp.eco.core.gui.GUIFactory;
import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration;
import com.willfp.eco.core.proxy.Cleaner;
import com.willfp.eco.core.proxy.ProxyFactory;
import com.willfp.eco.core.requirement.RequirementFactory;
import com.willfp.eco.core.scheduling.Scheduler;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
@@ -32,6 +32,7 @@ import java.util.logging.Logger;
* @see Eco#getHandler()
*/
@ApiStatus.Internal
@SuppressWarnings("removal")
public interface Handler {
/**
* Create a scheduler.
@@ -209,7 +210,8 @@ public interface Handler {
* @return The factory.
*/
@NotNull
RequirementFactory getRequirementFactory();
@Deprecated(forRemoval = true)
com.willfp.eco.core.requirement.RequirementFactory getRequirementFactory();
/**
* Get Adventure audiences.
@@ -233,7 +235,7 @@ public interface Handler {
* @return The handler.
*/
@NotNull
PlayerProfileHandler getPlayerProfileHandler();
ProfileHandler getProfileHandler();
/**
* Create dummy entity - never spawned, exists purely in code.
@@ -243,4 +245,30 @@ public interface Handler {
*/
@NotNull
Entity createDummyEntity(@NotNull Location location);
/**
* Create a {@link NamespacedKey} quickly
* <p>
* Bypasses the constructor, allowing for the creation of invalid keys,
* therefore this is considered unsafe and should only be called after
* the key has been confirmed to be valid.
*
* @param namespace The namespace.
* @param key The key.
* @return The key.
*/
@NotNull
NamespacedKey createNamespacedKey(@NotNull String namespace,
@NotNull String key);
/**
* Return or get props for a plugin.
*
* @param existing The existing constructor props.
* @param plugin The plugin.
* @return The props.
*/
@NotNull
PluginProps getProps(@Nullable PluginProps existing,
@NotNull Class<? extends EcoPlugin> plugin);
}

View File

@@ -0,0 +1,275 @@
package com.willfp.eco.core;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
/**
* Plugin props are the arguments related to the plugin that are required on start-up.
* <p>
* This class is complex in how it works intentionally. This is done so that fields can be
* added to the props without breaking API backwards compatibility. Thus, there is no public
* constructor and no way to instantiate props without creating a parser.
*/
public final class PluginProps {
/**
* All registered parsers.
*/
private static final Map<Class<?>, PropsParser<?>> REGISTERED_PARSERS = new HashMap<>();
/**
* The polymart resource ID.
*/
@Nullable
private Integer resourceId;
/**
* The bStats ID.
*/
@Nullable
private Integer bStatsId;
/**
* The proxy package.
*/
@Nullable
private String proxyPackage;
/**
* The color.
*/
@Nullable
private String color;
/**
* If extensions are supported.
*/
@Nullable
private Boolean supportingExtensions;
/**
* Create new blank props.
*/
private PluginProps() {
}
/**
* Get resource ID.
*
* @return The resource ID.
*/
public int getResourceId() {
assert resourceId != null;
return resourceId;
}
/**
* Set resource ID.
*
* @param resourceId The resource ID.
*/
public void setResourceId(final int resourceId) {
this.resourceId = resourceId;
}
/**
* Get bStats ID.
*
* @return The bStats ID.
*/
public int getBStatsId() {
assert bStatsId != null;
return bStatsId;
}
/**
* Set bStats ID.
*
* @param bStatsId The bStats ID.
*/
public void setBStatsId(final int bStatsId) {
this.bStatsId = bStatsId;
}
/**
* Get the proxy package.
*
* @return The package.
*/
@NotNull
public String getProxyPackage() {
assert proxyPackage != null;
return proxyPackage;
}
/**
* Set the proxy package.
*
* @param proxyPackage The proxy package.
*/
public void setProxyPackage(@NotNull final String proxyPackage) {
this.proxyPackage = proxyPackage;
}
/**
* Get color.
*
* @return The color.
*/
@NotNull
public String getColor() {
assert color != null;
return color;
}
/**
* Set the color.
*
* @param color The color.
*/
public void setColor(@NotNull final String color) {
this.color = color;
}
/**
* Get if extensions are supported.
*
* @return If supported.
*/
public boolean isSupportingExtensions() {
assert supportingExtensions != null;
return supportingExtensions;
}
/**
* Set if extensions are supported.
*
* @param supportingExtensions If supported.
*/
public void setSupportingExtensions(final boolean supportingExtensions) {
this.supportingExtensions = supportingExtensions;
}
/**
* Ensure that all required props have been set.
*/
public void validate() {
if (
supportingExtensions == null
|| proxyPackage == null
|| color == null
|| bStatsId == null
|| resourceId == null
) {
throw new IllegalStateException("Missing required props!");
}
}
/**
* Parse props from source.
*
* @param source The source.
* @param sourceClass The source class.
* @param <T> The source type.
* @return The props.
*/
public static <T> PluginProps parse(@NotNull final T source,
@NotNull final Class<? extends T> sourceClass) {
for (Map.Entry<Class<?>, PropsParser<?>> entry : REGISTERED_PARSERS.entrySet()) {
Class<?> clazz = entry.getKey();
if (clazz.equals(sourceClass)) {
@SuppressWarnings("unchecked")
PropsParser<T> parser = (PropsParser<T>) entry.getValue();
return parser.parseFrom(source);
}
}
throw new IllegalArgumentException("No parser exists for class " + sourceClass);
}
/**
* Register a parser for a type.
*
* @param clazz The class.
* @param parser The parser.
* @param <T> The source type.
*/
public static <T> void registerParser(@NotNull final Class<T> clazz,
@NotNull final PropsParser<T> parser) {
REGISTERED_PARSERS.put(clazz, parser);
}
/**
* Get if there is a registered parser for a class.
*
* @param clazz The class.
* @return If there is a parser registered.
*/
public static boolean hasParserFor(@NotNull final Class<?> clazz) {
for (Class<?> test : REGISTERED_PARSERS.keySet()) {
if (test.equals(clazz)) {
return true;
}
}
return false;
}
/**
* Create new props from known values.
*
* Marked as internal as this method will break whenever the properties themselves
* are updated (e.g. if a new property is added) - so to prevent any potential
* backwards-compatibility bugs, this method cannot be invoked outside eco itself.
*
* @param resourceId The ID of the plugin on polymart.
* @param bStatsId The ID of the plugin on bStats.
* @param proxyPackage The package where proxies can be found.
* @param color The primary color of the plugin.
* @param supportsExtensions If the plugin should attempt to look for extensions.
* @return The props.
*/
@ApiStatus.Internal
static PluginProps createSimple(final int resourceId,
final int bStatsId,
@NotNull final String proxyPackage,
@NotNull final String color,
final boolean supportsExtensions) {
PluginProps props = new PluginProps();
props.setResourceId(resourceId);
props.setBStatsId(bStatsId);
props.setProxyPackage(proxyPackage);
props.setColor(color);
props.setSupportingExtensions(supportsExtensions);
return props;
}
/**
* Parse arguments into props for a plugin.
*
* @param <T> The type of source.
*/
public interface PropsParser<T> {
/**
* Parse props from a given source.
*
* @param source The source.
* @return The props.
*/
PluginProps parseFrom(@NotNull T source);
/**
* Get a new, blank props instance.
*
* @return Blank props.
*/
default PluginProps getBlankProps() {
return new PluginProps();
}
}
}

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.command;
import com.willfp.eco.core.EcoPlugin;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
@@ -66,6 +67,13 @@ public interface CommandBase {
return new ArrayList<>();
}
/**
* Get the plugin.
*
* @return The plugin.
*/
EcoPlugin getPlugin();
/**
* Get the handler.
*

View File

@@ -1,7 +1,6 @@
package com.willfp.eco.core.command.impl;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.command.CommandBase;
import com.willfp.eco.core.command.CommandHandler;
import com.willfp.eco.core.command.TabCompleteHandler;
@@ -25,7 +24,12 @@ import java.util.stream.Collectors;
* layer, hence why it's a package-private class.
*/
@SuppressWarnings({"DeprecatedIsStillUsed"})
abstract class HandledCommand extends PluginDependent<EcoPlugin> implements CommandBase {
abstract class HandledCommand implements CommandBase {
/**
* The plugin.
*/
private final EcoPlugin plugin;
/**
* The name of the command.
*/
@@ -78,7 +82,7 @@ abstract class HandledCommand extends PluginDependent<EcoPlugin> implements Comm
@NotNull final String name,
@NotNull final String permission,
final boolean playersOnly) {
super(plugin);
this.plugin = plugin;
this.name = name;
this.permission = permission;
this.playersOnly = playersOnly;
@@ -98,6 +102,16 @@ abstract class HandledCommand extends PluginDependent<EcoPlugin> implements Comm
return this;
}
/**
* Get the plugin.
*
* @return The plugin.
*/
@Override
public EcoPlugin getPlugin() {
return this.plugin;
}
/**
* Handle the command.
*
@@ -124,6 +138,11 @@ abstract class HandledCommand extends PluginDependent<EcoPlugin> implements Comm
}
}
if (this.isPlayersOnly() && !(sender instanceof Player)) {
sender.sendMessage(this.getPlugin().getLangYml().getMessage("not-player"));
return;
}
if (this.getHandler() != null) {
this.getHandler().onExecute(sender, Arrays.asList(args));
} else {
@@ -193,11 +212,6 @@ abstract class HandledCommand extends PluginDependent<EcoPlugin> implements Comm
public static boolean canExecute(@NotNull final CommandSender sender,
@NotNull final CommandBase command,
@NotNull final EcoPlugin plugin) {
if (command.isPlayersOnly() && !(sender instanceof Player)) {
sender.sendMessage(plugin.getLangYml().getMessage("not-player"));
return false;
}
if (!sender.hasPermission(command.getPermission()) && sender instanceof Player) {
sender.sendMessage(plugin.getLangYml().getNoPermission());
return false;

View File

@@ -5,7 +5,10 @@ import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.core.config.wrapper.ConfigWrapper;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
/**
@@ -21,6 +24,15 @@ public class TransientConfig extends ConfigWrapper<Config> {
super(Eco.getHandler().getConfigFactory().createConfig(config));
}
/**
* @param stream The InputStream.
*/
public TransientConfig(@Nullable final InputStream stream) {
super(stream != null ? Eco.getHandler().getConfigFactory().createConfig(YamlConfiguration.loadConfiguration(
new InputStreamReader(stream)
)) : new TransientConfig());
}
/**
* Create a new empty transient config.
*

View File

@@ -235,7 +235,7 @@ public interface Config extends Cloneable {
*/
@NotNull
default String getString(@NotNull String path) {
return getString(path, false);
return getString(path, false, StringUtils.FormatOption.WITHOUT_PLACEHOLDERS);
}
/**

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.config.wrapper;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.interfaces.Config;
@@ -14,6 +15,7 @@ import java.util.Map;
* Internal component to create backend config implementations.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface ConfigFactory {
/**
* Updatable config.

View File

@@ -1,7 +1,6 @@
package com.willfp.eco.core.data;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
@@ -12,26 +11,7 @@ import java.util.UUID;
* <p>
* Profiles save automatically, so there is no need to save after changes.
*/
public interface PlayerProfile {
/**
* Write a key to a player's persistent data.
*
* @param key The key.
* @param value The value.
* @param <T> The type of the key.
*/
<T> void write(@NotNull PersistentDataKey<T> key,
@NotNull T value);
/**
* Read a key from a player's persistent data.
*
* @param key The key.
* @param <T> The type of the key.
* @return The value, or the default value if not found.
*/
<T> @NotNull T read(@NotNull PersistentDataKey<T> key);
public interface PlayerProfile extends Profile {
/**
* Load a player profile.
*
@@ -51,6 +31,6 @@ public interface PlayerProfile {
*/
@NotNull
static PlayerProfile load(@NotNull final UUID uuid) {
return Eco.getHandler().getPlayerProfileHandler().load(uuid);
return Eco.getHandler().getProfileHandler().load(uuid);
}
}

View File

@@ -0,0 +1,30 @@
package com.willfp.eco.core.data;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import org.jetbrains.annotations.NotNull;
/**
* Persistent data storage interface.
* <p>
* Profiles save automatically, so there is no need to save after changes.
*/
public interface Profile {
/**
* Write a key to persistent data.
*
* @param key The key.
* @param value The value.
* @param <T> The type of the key.
*/
<T> void write(@NotNull PersistentDataKey<T> key,
@NotNull T value);
/**
* Read a key from persistent data.
*
* @param key The key.
* @param <T> The type of the key.
* @return The value, or the default value if not found.
*/
<T> @NotNull T read(@NotNull PersistentDataKey<T> key);
}

View File

@@ -1,15 +1,19 @@
package com.willfp.eco.core.data;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
import java.util.UUID;
/**
* API to handle player profiles.
* API to handle profiles.
*/
public interface PlayerProfileHandler {
@ApiStatus.Internal
@Eco.HandlerComponent
public interface ProfileHandler {
/**
* Load a player profile.
*
@@ -18,6 +22,13 @@ public interface PlayerProfileHandler {
*/
PlayerProfile load(@NotNull UUID uuid);
/**
* Load the server profile.
*
* @return The profile.
*/
ServerProfile loadServerProfile();
/**
* Unload a player profile from memory.
* <p>
@@ -37,7 +48,7 @@ public interface PlayerProfileHandler {
*/
@Deprecated
default void savePlayer(@NotNull UUID uuid) {
this.saveKeysForPlayer(uuid, PersistentDataKey.values());
this.saveKeysFor(uuid, PersistentDataKey.values());
}
/**
@@ -48,8 +59,8 @@ public interface PlayerProfileHandler {
* @param uuid The uuid.
* @param keys The keys.
*/
void saveKeysForPlayer(@NotNull UUID uuid,
@NotNull Set<PersistentDataKey<?>> keys);
void saveKeysFor(@NotNull UUID uuid,
@NotNull Set<PersistentDataKey<?>> keys);
/**
* Save all player data.

View File

@@ -0,0 +1,21 @@
package com.willfp.eco.core.data;
import com.willfp.eco.core.Eco;
import org.jetbrains.annotations.NotNull;
/**
* Persistent data storage interface for servers.
* <p>
* Profiles save automatically, so there is no need to save after changes.
*/
public interface ServerProfile extends Profile {
/**
* Load the server profile.
*
* @return The profile.
*/
@NotNull
static ServerProfile load() {
return Eco.getHandler().getProfileHandler().loadServerProfile();
}
}

View File

@@ -25,7 +25,7 @@ public class PersistentDataKey<T> {
/**
* The persistent data key type.
*/
private final PersistentDataKeyType type;
private final PersistentDataKeyType<T> type;
/**
* Create a new Persistent Data Key.
@@ -35,7 +35,7 @@ public class PersistentDataKey<T> {
* @param defaultValue The default value.
*/
public PersistentDataKey(@NotNull final NamespacedKey key,
@NotNull final PersistentDataKeyType type,
@NotNull final PersistentDataKeyType<T> type,
@NotNull final T defaultValue) {
this.key = key;
this.defaultValue = defaultValue;
@@ -76,7 +76,7 @@ public class PersistentDataKey<T> {
*
* @return The key type.
*/
public PersistentDataKeyType getType() {
public PersistentDataKeyType<T> getType() {
return this.type;
}

View File

@@ -1,26 +1,108 @@
package com.willfp.eco.core.data.keys;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* All storable data key types.
*
* @param <T> The type.
*/
public enum PersistentDataKeyType {
public final class PersistentDataKeyType<T> {
/**
* The registered key types.
*/
private static final List<PersistentDataKeyType<?>> VALUES = new ArrayList<>();
/**
* String.
*/
STRING,
public static final PersistentDataKeyType<String> STRING = new PersistentDataKeyType<>(String.class, "STRING");
/**
* Boolean.
*/
BOOLEAN,
public static final PersistentDataKeyType<Boolean> BOOLEAN = new PersistentDataKeyType<>(Boolean.class, "BOOLEAN");
/**
* Integer.
* Int.
*/
INT,
public static final PersistentDataKeyType<Integer> INT = new PersistentDataKeyType<>(Integer.class, "INT");
/**
* Double.
*/
DOUBLE
public static final PersistentDataKeyType<Double> DOUBLE = new PersistentDataKeyType<>(Double.class, "DOUBLE");
/**
* The class of the type.
*/
private final Class<T> typeClass;
/**
* The name of the key type.
*/
private final String name;
/**
* Get the class of the type.
*
* @return The class.
*/
public Class<T> getTypeClass() {
return typeClass;
}
/**
* Get the name of the key type.
*
* @return The name.
*/
public String name() {
return name;
}
/**
* Create new PersistentDataKeyType.
*
* @param typeClass The type class.
* @param name The name.
*/
private PersistentDataKeyType(@NotNull final Class<T> typeClass,
@NotNull final String name) {
VALUES.add(this);
this.typeClass = typeClass;
this.name = name;
}
/**
* Get all registered {@link PersistentDataKeyType}s.
*
* @return The registered types.
*/
@NotNull
public static PersistentDataKeyType<?>[] values() {
return VALUES.toArray(new PersistentDataKeyType[0]);
}
/**
* Get a key type from a name.
*
* @param name The name.
* @return The type, or null if not found.
*/
@Nullable
public static PersistentDataKeyType<?> valueOf(@NotNull final String name) {
for (PersistentDataKeyType<?> type : VALUES) {
if (type.name.equalsIgnoreCase(name)) {
return type;
}
}
return null;
}
}

View File

@@ -1,13 +1,17 @@
package com.willfp.eco.core.display;
import com.willfp.eco.core.Eco;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Interface for display implementations.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface DisplayHandler {
/**
* Register display module.

View File

@@ -1,11 +1,15 @@
package com.willfp.eco.core.drops;
import com.willfp.eco.core.Eco;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* Internal component to create backend DropQueue implementations.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface DropQueueFactory {
/**
* Create a DropQueue.

View File

@@ -1,7 +1,9 @@
package com.willfp.eco.core.drops;
import com.willfp.eco.core.Eco;
import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
@@ -9,6 +11,8 @@ import java.util.Collection;
/**
* Internal interface for backend DropQueue implementations.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface InternalDropQueue {
/**
* Add item to queue.

View File

@@ -22,8 +22,30 @@ public interface FastItemStack {
*
* @param checkStored If stored NBT should also be checked.
* @return A map of all enchantments.
* @deprecated Poorly named method. Use getEnchants instead.
*/
Map<Enchantment, Integer> getEnchantmentsOnItem(boolean checkStored);
@Deprecated(since = "6.24.0")
default Map<Enchantment, Integer> getEnchantmentsOnItem(boolean checkStored) {
return getEnchants(checkStored);
}
/**
* Get all enchantments on an item.
* Does not account for stored enchants.
*
* @return A map of all enchantments.
*/
default Map<Enchantment, Integer> getEnchants() {
return getEnchants(false);
}
/**
* Get all enchantments on an item.
*
* @param checkStored If stored enchantments should be accounted for.
* @return A map of all enchantments.
*/
Map<Enchantment, Integer> getEnchants(boolean checkStored);
/**
* Get the level of an enchantment on an item.

View File

@@ -1,15 +1,19 @@
package com.willfp.eco.core.gui;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.gui.menu.MenuBuilder;
import com.willfp.eco.core.gui.slot.SlotBuilder;
import com.willfp.eco.core.gui.slot.functional.SlotProvider;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* Internal component used by {@link com.willfp.eco.core.gui.menu.Menu#builder(int)}
* and {@link com.willfp.eco.core.gui.slot.Slot#builder(ItemStack)}.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface GUIFactory {
/**
* Create slot builder.

View File

@@ -1,6 +1,8 @@
package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.items.builder.ItemStackBuilder;
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
import com.willfp.eco.core.recipe.parts.MaterialTestableItem;
import com.willfp.eco.util.ListUtils;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
@@ -38,7 +40,7 @@ public class FillerMask {
*/
public FillerMask(@NotNull final Material material,
@NotNull final String... pattern) {
this(new MaskMaterials(material), pattern);
this(new MaskItems(new MaterialTestableItem(material)), pattern);
}
/**
@@ -46,17 +48,33 @@ public class FillerMask {
*
* @param materials The mask materials.
* @param pattern The pattern.
* @deprecated Use {@link MaskItems} instead.
*/
@Deprecated(since = "6.24.0")
public FillerMask(@NotNull final MaskMaterials materials,
@NotNull final String... pattern) {
if (Arrays.stream(materials.materials()).anyMatch(material -> material == Material.AIR)) {
throw new IllegalArgumentException("Materials cannot be air!");
this(
materials.toMaskItems(),
pattern
);
}
/**
* Create a new filler mask.
*
* @param items The mask items.
* @param pattern The pattern.
*/
public FillerMask(@NotNull final MaskItems items,
@NotNull final String... pattern) {
if (Arrays.stream(items.items()).anyMatch(item -> item instanceof EmptyTestableItem)) {
throw new IllegalArgumentException("Items cannot be empty!");
}
mask = ListUtils.create2DList(6, 9);
for (int i = 0; i < materials.materials().length; i++) {
ItemStack itemStack = new ItemStackBuilder(materials.materials()[i])
for (int i = 0; i < items.items().length; i++) {
ItemStack itemStack = new ItemStackBuilder(items.items()[i])
.setDisplayName("&r")
.build();

View File

@@ -0,0 +1,45 @@
package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.items.Items;
import com.willfp.eco.core.items.TestableItem;
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
import com.willfp.eco.core.recipe.parts.MaterialTestableItem;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* Mask materials store a set of items which can be accessed by
* a filler mask.
*
* @param items The items.
*/
public record MaskItems(@NotNull TestableItem... items) {
/**
* Create MaskItems from a list of item names.
*
* @param names The names.
* @return The mask items.
*/
public static MaskItems fromItemNames(@NotNull final Iterable<String> names) {
List<TestableItem> items = new ArrayList<>();
for (String name : names) {
TestableItem item = Items.lookup(name);
if (item instanceof EmptyTestableItem) {
continue;
}
items.add(item);
}
if (items.isEmpty()) {
return new MaskItems(new MaterialTestableItem(Material.BLACK_STAINED_GLASS_PANE));
}
return new MaskItems(items.toArray(new TestableItem[0]));
}
}

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.items.Items;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
@@ -8,7 +9,16 @@ import org.jetbrains.annotations.NotNull;
* a filler mask.
*
* @param materials The materials.
* @deprecated Use {@link MaskItems} instead.
*/
@Deprecated(since = "6.24.0")
public record MaskMaterials(@NotNull Material... materials) {
/**
* Convert MaskMaterials to MaskItems.
*
* @return The MaskItems.
*/
public MaskItems toMaskItems() {
return new MaskItems(Items.fromMaterials(this.materials()));
}
}

View File

@@ -2,6 +2,7 @@ package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.gui.slot.functional.SlotHandler;
import com.willfp.eco.core.gui.slot.functional.SlotModifier;
import com.willfp.eco.core.gui.slot.functional.SlotUpdater;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull;
@@ -106,8 +107,23 @@ public interface SlotBuilder {
*
* @param modifier The modifier.
* @return The builder.
* @deprecated Use {@link SlotBuilder#setUpdater(SlotUpdater)} instead.
*/
SlotBuilder setModifier(@NotNull SlotModifier modifier);
@Deprecated
default SlotBuilder setModifier(@NotNull SlotModifier modifier) {
return setUpdater((player, menu, previous) -> {
modifier.modify(player, menu, previous);
return previous;
});
}
/**
* Set the ItemStack updater.
*
* @param updater The updater.
* @return The builder.
*/
SlotBuilder setUpdater(@NotNull SlotUpdater updater);
/**
* Set slot to be a captive slot.

View File

@@ -7,8 +7,11 @@ import org.jetbrains.annotations.NotNull;
/**
* Interface to run on slot modify.
*
* @deprecated Use {@link SlotUpdater} instead.
*/
@FunctionalInterface
@Deprecated
public interface SlotModifier {
/**
* Performs this operation on the given arguments.

View File

@@ -0,0 +1,24 @@
package com.willfp.eco.core.gui.slot.functional;
import com.willfp.eco.core.gui.menu.Menu;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Interface to run on slot update.
*/
@FunctionalInterface
public interface SlotUpdater {
/**
* Performs this operation on the given arguments.
*
* @param player The player.
* @param menu The menu.
* @param previous The previous ItemStack.
* @return The new ItemStack.
*/
ItemStack update(@NotNull Player player,
@NotNull Menu menu,
@NotNull ItemStack previous);
}

View File

@@ -6,6 +6,7 @@ import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Function;
/**
@@ -141,4 +142,21 @@ public class PlaceholderEntry {
public void register() {
PlaceholderManager.registerPlaceholder(this);
}
@Override
public boolean equals(@Nullable final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof PlaceholderEntry entry)) {
return false;
}
return Objects.equals(this.getIdentifier(), entry.getIdentifier())
&& Objects.equals(this.getPlugin(), entry.getPlugin());
}
@Override
public int hashCode() {
return Objects.hash(this.getIdentifier(), this.getPlugin());
}
}

View File

@@ -1,5 +1,7 @@
package com.willfp.eco.core.integrations.placeholder;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin;
import org.bukkit.entity.Player;
@@ -12,6 +14,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* Class to handle placeholder integrations.
@@ -27,10 +30,17 @@ public final class PlaceholderManager {
*/
private static final Set<PlaceholderIntegration> REGISTERED_INTEGRATIONS = new HashSet<>();
/**
* Placeholder Cache.
*/
private static final LoadingCache<EntryWithPlayer, String> PLACEHOLDER_CACHE = Caffeine.newBuilder()
.expireAfterWrite(50, TimeUnit.MILLISECONDS)
.build(key -> key.entry.getResult(key.player));
/**
* Register a new placeholder integration.
*
* @param integration The {@link PlaceholderIntegration} to register.
* @param integration The {@link com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration} to register.
*/
public static void addIntegration(@NotNull final PlaceholderIntegration integration) {
integration.registerIntegration();
@@ -40,7 +50,7 @@ public final class PlaceholderManager {
/**
* Register a placeholder.
*
* @param expansion The {@link PlaceholderEntry} to register.
* @param expansion The {@link com.willfp.eco.core.integrations.placeholder.PlaceholderEntry} to register.
*/
public static void registerPlaceholder(@NotNull final PlaceholderEntry expansion) {
EcoPlugin plugin = expansion.getPlugin() == null ? Eco.getHandler().getEcoPlugin() : expansion.getPlugin();
@@ -75,7 +85,7 @@ public final class PlaceholderManager {
public static String getResult(@Nullable final Player player,
@NotNull final String identifier,
@Nullable final EcoPlugin plugin) {
EcoPlugin owner = player == null ? Eco.getHandler().getEcoPlugin() : plugin;
EcoPlugin owner = plugin == null ? Eco.getHandler().getEcoPlugin() : plugin;
PlaceholderEntry entry = REGISTERED_PLACEHOLDERS.getOrDefault(owner, new HashMap<>()).get(identifier.toLowerCase());
if (entry == null && plugin != null) {
@@ -94,7 +104,7 @@ public final class PlaceholderManager {
return "";
}
return entry.getResult(player);
return PLACEHOLDER_CACHE.get(new EntryWithPlayer(entry, player));
}
/**
@@ -128,6 +138,11 @@ public final class PlaceholderManager {
return found;
}
private static record EntryWithPlayer(@NotNull PlaceholderEntry entry,
@Nullable Player player) {
}
private PlaceholderManager() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}

View File

@@ -0,0 +1,103 @@
package com.willfp.eco.core.items;
import com.willfp.eco.core.fast.FastItemStack;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* An item and its {@link com.willfp.eco.core.fast.FastItemStack} hash.
*/
public final class HashedItem {
/**
* The item.
*/
private final ItemStack item;
/**
* The hash.
*/
private final int hash;
/**
* Create new hashed item.
*
* @param item The item.
* @param hash The hash.
*/
private HashedItem(@NotNull final ItemStack item,
final int hash) {
this.item = item;
this.hash = hash;
}
/**
* Get the item.
*
* @return The ItemStack.
*/
public ItemStack getItem() {
return this.item;
}
/**
* Get the hash.
*
* @return The hash.
*/
public int getHash() {
return this.hash;
}
/**
* Kotlin destructuring support.
*
* @return The ItemStack.
*/
public ItemStack component1() {
return this.getItem();
}
/**
* Kotlin destructuring support.
*
* @return The hash.
*/
public int component2() {
return this.getHash();
}
@Override
public int hashCode() {
return this.hash;
}
@Override
public boolean equals(@Nullable final Object other) {
if (!(other instanceof HashedItem o)) {
return false;
}
return o.hash == this.hash;
}
/**
* Hashed item from an item.
*
* @param item The item.
* @return The hashed item.
*/
public static HashedItem of(@NotNull final ItemStack item) {
return new HashedItem(item, FastItemStack.wrap(item).hashCode());
}
/**
* Hashed item from a fast item stack.
*
* @param item The item.
* @return The hashed item.
*/
public static HashedItem of(@NotNull final FastItemStack item) {
return new HashedItem(item.unwrap(), item.hashCode());
}
}

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.core.items;
import com.willfp.eco.core.fast.FastItemStack;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.willfp.eco.core.items.args.LookupArgParser;
import com.willfp.eco.core.items.provider.ItemProvider;
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
@@ -14,16 +15,18 @@ import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -37,9 +40,23 @@ public final class Items {
private static final Map<NamespacedKey, TestableItem> REGISTRY = new ConcurrentHashMap<>();
/**
* Cached custom item lookups, using {@link FastItemStack#hashCode()}.
* Cached custom item lookups, using {@link HashedItem}.
*/
private static final Map<Integer, TestableItem> CACHE = new ConcurrentHashMap<>();
private static final LoadingCache<HashedItem, Optional<TestableItem>> CACHE = Caffeine.newBuilder()
.expireAfterAccess(5, TimeUnit.MINUTES)
.build(
key -> {
TestableItem match = null;
for (TestableItem item : REGISTRY.values()) {
if (item.matches(key.getItem())) {
match = item;
break;
}
}
return Optional.ofNullable(match);
}
);
/**
* All item providers.
@@ -201,7 +218,7 @@ public final class Items {
}
}
// Marked as redundant but i am covering all bases here
// Marked as redundant but I am covering all bases here
if (item == null || item instanceof EmptyTestableItem) {
return new EmptyTestableItem();
}
@@ -294,30 +311,7 @@ public final class Items {
*/
@Nullable
public static CustomItem getCustomItem(@NotNull final ItemStack itemStack) {
int hash = FastItemStack.wrap(itemStack).hashCode();
TestableItem cached = CACHE.get(hash);
if (cached != null) {
return getOrWrap(cached);
} else {
CACHE.remove(hash);
}
TestableItem match = null;
for (TestableItem item : REGISTRY.values()) {
if (item.matches(itemStack)) {
match = item;
break;
}
}
if (match == null) {
return null;
}
CACHE.put(hash, match);
return getOrWrap(match);
return CACHE.get(HashedItem.of(itemStack)).map(Items::getOrWrap).orElse(null);
}
/**
@@ -352,11 +346,32 @@ public final class Items {
}
/**
* Clear the lookup cache.
* Convert an array of materials to an array of testable items.
*
* @param materials The materials.
* @return An array of functionally identical testable items.
*/
@ApiStatus.Internal
public static void clearCache() {
CACHE.clear();
@NotNull
public static TestableItem[] fromMaterials(@NotNull final Material... materials) {
return Arrays.stream(materials)
.map(MaterialTestableItem::new)
.toArray(MaterialTestableItem[]::new);
}
/**
* Convert a collection of materials into a collection of testable items.
*
* @param materials The materials.
* @return A collection of functionally identical testable items.
*/
@NotNull
public static Collection<TestableItem> fromMaterials(@NotNull final Iterable<Material> materials) {
List<TestableItem> items = new ArrayList<>();
for (Material material : materials) {
items.add(new MaterialTestableItem(material));
}
return items;
}
private Items() {

View File

@@ -5,12 +5,25 @@ import org.jetbrains.annotations.NotNull;
/**
* Generic error with proxy loading.
*/
public class ProxyError extends RuntimeException {
public class ProxyError extends Error {
/**
* Thrown if there is an error getting a proxy.
*
* @param message The message to send.
* @param cause The cause.
*/
public ProxyError(@NotNull final String message,
@NotNull final Throwable cause) {
super(message, cause);
}
/**
* Thrown if there is an error getting a proxy.
*
* @param message The message to send.
* @deprecated Proxy Errors should include a cause.
*/
@Deprecated
public ProxyError(@NotNull final String message) {
super(message);
}

View File

@@ -0,0 +1,15 @@
package com.willfp.eco.core.proxy.exceptions;
import com.willfp.eco.core.proxy.ProxyConstants;
/**
* Server running an unsupported version.
*/
public class UnsupportedVersionError extends Error {
/**
* Thrown if the server is running an unsupported version.
*/
public UnsupportedVersionError() {
super("You're running an unsupported server version: " + ProxyConstants.NMS_VERSION);
}
}

View File

@@ -1,17 +1,30 @@
package com.willfp.eco.core.proxy.exceptions;
import com.willfp.eco.core.proxy.ProxyConstants;
import org.jetbrains.annotations.NotNull;
/**
* Error if the server is running an unsupported version.
*
* @deprecated Poorly named, exception when it's actually an error, contains doubly nested errors.
*/
@Deprecated(since = "6.24.0", forRemoval = true)
public class UnsupportedVersionException extends ProxyError {
/**
* Thrown if the server is running an unsupported NMS version.
*
* @param message The message to send.
* @deprecated Use the default constructor.
*/
@Deprecated(since = "6.24.0")
public UnsupportedVersionException(@NotNull final String message) {
super(message);
}
/**
* Thrown if the server is running an unsupported NMS version.
*/
public UnsupportedVersionException() {
super("You're running an unsupported server version: " + ProxyConstants.NMS_VERSION, new IllegalStateException());
}
}

View File

@@ -6,6 +6,8 @@ import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.items.Items;
import com.willfp.eco.core.recipe.recipes.CraftingRecipe;
import com.willfp.eco.core.recipe.recipes.ShapedCraftingRecipe;
import com.willfp.eco.util.NamespacedKeyUtils;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
@@ -16,7 +18,6 @@ import java.util.List;
/**
* Utility class to manage and register crafting recipes.
*/
@SuppressWarnings("deprecation")
public final class Recipes {
/**
* Registry of all recipes.
@@ -58,7 +59,10 @@ public final class Recipes {
}
if (key.getKey().contains("_displayed")) {
NamespacedKey otherKey = new NamespacedKey(key.getNamespace(), key.getKey().replace("_displayed", ""));
NamespacedKey otherKey = NamespacedKeyUtils.create(
key.getNamespace(),
key.getKey().replace("_displayed", "")
);
return RECIPES.get(otherKey);
}
@@ -92,6 +96,7 @@ public final class Recipes {
* @param permission The permission.
* @return The recipe.
*/
@Nullable
public static CraftingRecipe createAndRegisterRecipe(@NotNull final EcoPlugin plugin,
@NotNull final String key,
@NotNull final ItemStack output,
@@ -105,6 +110,12 @@ public final class Recipes {
builder.setRecipePart(i, Items.lookup(recipeStrings.get(i)));
}
if (builder.isAir()) {
Bukkit.getLogger().warning("RECIPE ERROR! " + plugin.getName() + ":" + key + " consists only");
Bukkit.getLogger().warning("of air or invalid items! Please change that or disable this recipe.");
return null;
}
ShapedCraftingRecipe recipe = builder.build();
recipe.register();

View File

@@ -287,6 +287,20 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
return this;
}
/**
* Check if recipe parts are all air.
*
* @return If recipe parts are all air.
*/
public boolean isAir() {
for (TestableItem recipePart : this.recipeParts) {
if (recipePart != null && !(recipePart instanceof EmptyTestableItem)) {
return false;
}
}
return true;
}
/**
* Build the recipe.
*

View File

@@ -7,7 +7,11 @@ import java.util.List;
/**
* A requirement is a defined goal that a player must meet.
*
* @deprecated No typing, weak definitions, and not an API component. Shouldn't be in eco.
*/
@Deprecated(since = "6.24.0", forRemoval = true)
@SuppressWarnings("DeprecatedIsStillUsed")
public abstract class Requirement {
/**
* Create a new requirement.

View File

@@ -1,10 +1,18 @@
package com.willfp.eco.core.requirement;
import com.willfp.eco.core.Eco;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* Interface for internal requirement factory implementations.
*
* @deprecated See {@link Requirement}.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
@Deprecated(since = "6.24.0", forRemoval = true)
@SuppressWarnings({"removal", "DeprecatedIsStillUsed"})
public interface RequirementFactory {
/**
* Create a requirement.

View File

@@ -5,7 +5,11 @@ import org.jetbrains.annotations.NotNull;
/**
* Contains methods and fields pertaining to requirements.
*
* @deprecated See {@link Requirement}.
*/
@Deprecated(since = "6.24.0", forRemoval = true)
@SuppressWarnings("removal")
public final class Requirements {
/**
* Requires a player to have a permission.

View File

@@ -26,11 +26,26 @@ public final class DurabilityUtils {
* @param item The item to damage.
* @param damage The amount of damage to deal.
* @param slot The slot in the inventory of the item.
* @deprecated The slot is not required.
*/
@Deprecated(since = "6.24.0")
public static void damageItem(@NotNull final Player player,
@NotNull final ItemStack item,
final int damage,
final int slot) {
damageItem(player, item, damage);
}
/**
* Damage an item in a player's inventory.
*
* @param player The player.
* @param item The item to damage.
* @param damage The amount of damage to deal.
*/
public static void damageItem(@NotNull final Player player,
@NotNull final ItemStack item,
final int damage) {
if (item.getItemMeta() == null) {
return;
}
@@ -61,7 +76,7 @@ public final class DurabilityUtils {
item.setItemMeta((ItemMeta) meta);
PlayerItemBreakEvent event = new PlayerItemBreakEvent(player, item);
Bukkit.getPluginManager().callEvent(event);
player.getInventory().clear(slot);
item.setType(Material.AIR);
player.playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, SoundCategory.BLOCKS, 1, 1);
} else {
item.setItemMeta((ItemMeta) meta);
@@ -69,6 +84,44 @@ public final class DurabilityUtils {
}
}
/**
* Damage an item.
*
* @param item The item to damage.
* @param damage The amount of damage to deal.
*/
public static void damageItem(@NotNull final ItemStack item,
final int damage) {
if (item.getItemMeta() == null) {
return;
}
if (item.getItemMeta().isUnbreakable()) {
return;
}
if (!(item.getItemMeta() instanceof Damageable)) {
return;
}
// Special edge case
if (item.getType() == Material.CARVED_PUMPKIN || item.getType() == Material.PLAYER_HEAD) {
return;
}
Damageable meta = (Damageable) item.getItemMeta();
meta.setDamage(meta.getDamage() + damage);
if (meta.getDamage() >= item.getType().getMaxDurability()) {
meta.setDamage(item.getType().getMaxDurability());
item.setItemMeta((ItemMeta) meta);
item.setType(Material.AIR);
} else {
item.setItemMeta((ItemMeta) meta);
}
}
/**
* Damage an item in a player's inventory without breaking it.
*

View File

@@ -1,7 +1,9 @@
package com.willfp.eco.util;
import com.willfp.eco.core.Eco;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
@@ -17,7 +19,7 @@ public final class NamespacedKeyUtils {
*/
@NotNull
public static NamespacedKey createEcoKey(@NotNull final String string) {
return Objects.requireNonNull(NamespacedKey.fromString("eco:" + string));
return NamespacedKeyUtils.create("eco", string);
}
/**
@@ -30,7 +32,45 @@ public final class NamespacedKeyUtils {
@NotNull
public static NamespacedKey create(@NotNull final String namespace,
@NotNull final String key) {
return Objects.requireNonNull(NamespacedKey.fromString(namespace + ":" + key));
return Eco.getHandler().createNamespacedKey(
namespace,
key
);
}
/**
* Create a NamespacedKey from a string.
* <p>
* Preferred over {@link NamespacedKey#fromString(String)} for performance reasons.
*
* @param string The string.
* @return The key.
*/
@NotNull
public static NamespacedKey fromString(@NotNull final String string) {
return Objects.requireNonNull(NamespacedKeyUtils.fromStringOrNull(string));
}
/**
* Create a NamespacedKey from a string.
* <p>
* Preferred over {@link NamespacedKey#fromString(String)} for performance reasons.
*
* @param string The string.
* @return The key, or null if not a key.
*/
@Nullable
public static NamespacedKey fromStringOrNull(@NotNull final String string) {
int index = string.indexOf(":");
if (index < 0) {
return null;
}
return NamespacedKeyUtils.create(
string.substring(0, index),
string.substring(index + 1)
);
}
private NamespacedKeyUtils() {

View File

@@ -5,6 +5,7 @@ import com.willfp.eco.core.Prerequisite;
import com.willfp.eco.core.data.PlayerProfile;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import com.willfp.eco.core.data.keys.PersistentDataKeyType;
import com.willfp.eco.core.integrations.anticheat.AnticheatManager;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.OfflinePlayer;
@@ -12,6 +13,8 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
/**
* Utilities / API methods for players.
*/
@@ -107,6 +110,38 @@ public final class PlayerUtils {
profile.write(PLAYER_NAME_KEY, player.getDisplayName());
}
/**
* Run something with the player exempted.
*
* @param player The player.
* @param action The action.
*/
public static void runExempted(@NotNull final Player player,
@NotNull final Consumer<Player> action) {
try {
AnticheatManager.exemptPlayer(player);
action.accept(player);
} finally {
AnticheatManager.unexemptPlayer(player);
}
}
/**
* Run something with the player exempted.
*
* @param player The player.
* @param action The action.
*/
public static void runExempted(@NotNull final Player player,
@NotNull final Runnable action) {
try {
AnticheatManager.exemptPlayer(player);
action.run();
} finally {
AnticheatManager.unexemptPlayer(player);
}
}
private PlayerUtils() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}

View File

@@ -1,5 +1,7 @@
package com.willfp.eco.util;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonSyntaxException;
@@ -20,6 +22,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -66,6 +69,42 @@ public final class StringUtils {
.emitLegacyHoverEvent()
.build();
/**
* String format cache.
*/
private static final LoadingCache<String, String> STRING_FORMAT_CACHE = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.build(StringUtils::processFormatting);
/**
* Json -> Legacy Cache.
*/
private static final LoadingCache<String, String> JSON_TO_LEGACY = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.build(
json -> {
try {
Component component = GSON_COMPONENT_SERIALIZER.deserialize(json);
return LEGACY_COMPONENT_SERIALIZER.serialize(component);
} catch (JsonSyntaxException e) {
return json;
}
}
);
/**
* Legacy -> Json Cache.
*/
private static final LoadingCache<String, String> LEGACY_TO_JSON = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.build(
legacy -> GSON_COMPONENT_SERIALIZER.serialize(
Component.empty().decoration(TextDecoration.ITALIC, false).append(
LEGACY_COMPONENT_SERIALIZER.deserialize(legacy)
)
)
);
/**
* Color map.
*/
@@ -272,6 +311,11 @@ public final class StringUtils {
if (option == FormatOption.WITH_PLACEHOLDERS) {
processedMessage = PlaceholderManager.translatePlaceholders(processedMessage, player);
}
return STRING_FORMAT_CACHE.get(processedMessage);
}
private static String processFormatting(@NotNull final String message) {
String processedMessage = message;
processedMessage = ChatColor.translateAlternateColorCodes('&', processedMessage);
processedMessage = translateGradients(processedMessage);
processedMessage = translateHexColorCodes(processedMessage);
@@ -423,11 +467,8 @@ public final class StringUtils {
if (legacy == null) {
processed = "";
}
return GSON_COMPONENT_SERIALIZER.serialize(
Component.empty().decoration(TextDecoration.ITALIC, false).append(
LEGACY_COMPONENT_SERIALIZER.deserialize(processed)
)
);
return LEGACY_TO_JSON.get(processed);
}
/**
@@ -442,12 +483,7 @@ public final class StringUtils {
return "";
}
try {
Component component = GSON_COMPONENT_SERIALIZER.deserialize(json);
return LEGACY_COMPONENT_SERIALIZER.serialize(component);
} catch (JsonSyntaxException e) {
return json;
}
return JSON_TO_LEGACY.get(json);
}
/**

View File

@@ -69,8 +69,10 @@ public final class TeamUtils {
*
* @param material The material to find the team from.
* @return The team.
* @deprecated Stupid method.
*/
@NotNull
@Deprecated(since = "6.24.0")
public static Team getMaterialColorTeam(@NotNull final Material material) {
return fromChatColor(MATERIAL_COLORS.getOrDefault(material, ChatColor.WHITE));
}

View File

@@ -0,0 +1,142 @@
@file:JvmName("CommandHelperExtensions")
package com.willfp.eco.core.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.CommandBase
import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.eco.core.command.impl.Subcommand
import org.bukkit.command.CommandSender
/**
* Helper class for creating commands with builders.
*
* @param plugin The plugin.
* @param name The command name.
* @param permission The permission.
* @param playersOnly If only players should run the command.
* @param executor The command executor.
* @param tabCompleter The tab completer.
*/
class BuiltPluginCommand internal constructor(
plugin: EcoPlugin,
name: String,
permission: String,
playersOnly: Boolean = false,
var executor: (CommandSender, List<String>) -> Unit,
var tabCompleter: (CommandSender, List<String>) -> List<String>,
) : PluginCommand(plugin, name, permission, playersOnly) {
override fun onExecute(sender: CommandSender, args: List<String>) =
executor(sender, args)
override fun tabComplete(sender: CommandSender, args: List<String>): List<String> =
tabCompleter(sender, args)
}
/**
* Helper class for creating commands with builders.
*
* @param plugin The plugin.
* @param name The command name.
* @param permission The permission.
* @param playersOnly If only players should run the command.
* @param executor The command executor.
* @param tabCompleter The tab completer.
*/
class BuiltSubcommand internal constructor(
plugin: EcoPlugin,
name: String,
permission: String,
playersOnly: Boolean = false,
var executor: (CommandSender, List<String>) -> Unit,
var tabCompleter: (CommandSender, List<String>) -> List<String>,
) : Subcommand(plugin, name, permission, playersOnly) {
internal constructor(
parent: CommandBase,
name: String,
executor: (CommandSender, List<String>) -> Unit,
tabCompleter: (CommandSender, List<String>) -> List<String>,
) : this(parent.plugin, name, parent.permission, parent.isPlayersOnly, executor, tabCompleter)
override fun onExecute(sender: CommandSender, args: List<String>) =
executor(sender, args)
override fun tabComplete(sender: CommandSender, args: List<String>): List<String> =
tabCompleter(sender, args)
}
/**
* Kotlin builder for commands.
*
* @param plugin The plugin.
* @param name The command name.
* @param permission The permission.
* @param playersOnly If only players should execute the command.
* @param init The builder.
*/
fun command(
plugin: EcoPlugin,
name: String,
permission: String,
playersOnly: Boolean = false,
init: BuiltPluginCommand.() -> Unit
): PluginCommand {
val command = BuiltPluginCommand(
plugin,
name,
permission,
playersOnly,
{ _, _ -> },
{ _, _ -> emptyList() }
)
init(command)
return command
}
/**
* Kotlin builder for commands.
*
* @param name The command name.
* @param permission The permission.
* @param playersOnly If only players should execute the command.
* @param init The builder.
*/
fun CommandBase.addSubcommand(
name: String,
permission: String,
playersOnly: Boolean = false,
init: BuiltSubcommand.() -> Unit
): Subcommand {
val command = BuiltSubcommand(
this.plugin,
name,
permission,
playersOnly,
{ _, _ -> },
{ _, _ -> emptyList() }
)
init(command)
return command
}
/**
* Kotlin builder for commands.
* Inherits plugin, permission, players only.
*
* @param name The command name.
* @param init The builder.
*/
fun CommandBase.addSubcommand(
name: String,
init: BuiltSubcommand.() -> Unit
): Subcommand {
val command = BuiltSubcommand(
this,
name,
{ _, _ -> },
{ _, _ -> emptyList() }
)
init(command)
return command
}

View File

@@ -0,0 +1,18 @@
@file:JvmName("ProfileExtensions")
package com.willfp.eco.core.data
import org.bukkit.OfflinePlayer
import org.bukkit.Server
/**
* @see PlayerProfile.load
*/
val OfflinePlayer.profile: PlayerProfile
get() = PlayerProfile.load(this)
/**
* @see ServerProfile.load
*/
val Server.profile: ServerProfile
get() = ServerProfile.load()

View File

@@ -0,0 +1,11 @@
@file:JvmName("FastItemStackExtensions")
package com.willfp.eco.core.fast
import org.bukkit.inventory.ItemStack
/**
* @see FastItemStack.wrap
*/
fun ItemStack.fast(): FastItemStack =
FastItemStack.wrap(this)

View File

@@ -0,0 +1,105 @@
@file:JvmName("GUIHelperExtensions")
package com.willfp.eco.core.gui
import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.menu.MenuBuilder
import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.core.gui.slot.SlotBuilder
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.inventory.ItemStack
/**
* @see SlotBuilder.onLeftClick
*/
fun SlotBuilder.onLeftClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onLeftClick { a, b, c -> action(a, b, c) }
/**
* @see SlotBuilder.onRightClick
*/
fun SlotBuilder.onRightClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onRightClick { a, b, c -> action(a, b, c) }
/**
* @see SlotBuilder.onShiftLeftClick
*/
fun SlotBuilder.onShiftLeftClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onShiftLeftClick { a, b, c -> action(a, b, c) }
/**
* @see SlotBuilder.onShiftRightClick
*/
fun SlotBuilder.onShiftRightClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onShiftRightClick { a, b, c -> action(a, b, c) }
/**
* @see SlotBuilder.onShiftRightClick
*/
fun SlotBuilder.onMiddleClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onMiddleClick { a, b, c -> action(a, b, c) }
/**
* @see SlotBuilder.setModifier
* @deprecated Use SlotUpdater instead.
*/
@Deprecated("Use SlotUpdater instead")
@Suppress("DEPRECATION")
fun SlotBuilder.setModifier(action: (Player, Menu, ItemStack) -> Unit): SlotBuilder =
this.setUpdater { a, b, c -> c.apply { action(a, b, c) } }
/**
* @see SlotBuilder.setUpdater
*/
fun SlotBuilder.setUpdater(action: (Player, Menu, ItemStack) -> ItemStack): SlotBuilder =
this.setUpdater { a, b, c -> action(a, b, c) }
/**
* Kotlin builder for slots.
*/
fun slot(
item: ItemStack,
init: SlotBuilder.() -> Unit
): Slot {
val builder = Slot.builder(item)
init(builder)
return builder.build()
}
/**
* Kotlin builder for slots.
*/
fun slot(
provider: (Player, Menu) -> ItemStack,
init: SlotBuilder.() -> Unit
): Slot {
val builder = Slot.builder { a, b -> provider(a, b) }
init(builder)
return builder.build()
}
/**
* @see MenuBuilder.onClose
*/
fun MenuBuilder.onClose(action: (InventoryCloseEvent, Menu) -> Unit): MenuBuilder =
this.onClose { a, b -> action(a, b) }
/**
* @see MenuBuilder.modify
*/
fun MenuBuilder.modify(modifier: (MenuBuilder) -> Unit): MenuBuilder =
this.modfiy { modifier(it) }
/**
* Kotlin builder for menus.
*/
fun menu(
rows: Int,
init: MenuBuilder.() -> Unit
): Menu {
val builder = Menu.builder(rows)
init(builder)
return builder.build()
}

View File

@@ -0,0 +1,12 @@
@file:JvmName("ArrowUtilsExtensions")
package com.willfp.eco.util
import org.bukkit.entity.Arrow
import org.bukkit.inventory.ItemStack
/**
* @see ArrowUtils.getBow
*/
val Arrow.bow: ItemStack?
get() = ArrowUtils.getBow(this)

View File

@@ -0,0 +1,11 @@
@file:JvmName("BlockUtilsExtensions")
package com.willfp.eco.util
import org.bukkit.block.Block
/**
* @see ArrowUtils.getBow
*/
val Block.isPlayerPlaced: Boolean
get() = BlockUtils.isPlayerPlaced(this)

View File

@@ -0,0 +1,18 @@
@file:JvmName("DurabilityUtilsExtensions")
package com.willfp.eco.util
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
/**
* @see DurabilityUtils.damageItem
*/
fun ItemStack.damage(damage: Int) =
DurabilityUtils.damageItem(this, damage)
/**
* @see DurabilityUtils.damageItem
*/
fun ItemStack.damage(damage: Int, player: Player) =
DurabilityUtils.damageItem(player, this, damage)

View File

@@ -0,0 +1,21 @@
@file:JvmName("ListUtilsExtensions")
package com.willfp.eco.util
/**
* @see ListUtils.listToFrequencyMap
*/
fun <T> List<T>.toFrequencyMap(): Map<T, Int> =
ListUtils.listToFrequencyMap(this)
/**
* @see ListUtils.containsIgnoreCase
*/
fun Iterable<String>.containsIgnoreCase(element: String): Boolean =
ListUtils.containsIgnoreCase(this, element)
/**
* @see ListUtils.create2DList
*/
fun <T> create2DList(rows: Int, columns: Int): MutableList<MutableList<T>> =
ListUtils.create2DList(rows, columns)

View File

@@ -0,0 +1,29 @@
@file:JvmName("NamespacedKeyUtilsExtensions")
package com.willfp.eco.util
import com.willfp.eco.core.EcoPlugin
/**
* @see NamespacedKeyUtils.fromString
*/
fun namespacedKeyOf(string: String) =
NamespacedKeyUtils.fromString(string)
/**
* @see NamespacedKeyUtils.fromString
*/
fun safeNamespacedKeyOf(string: String) =
NamespacedKeyUtils.fromStringOrNull(string)
/**
* @see NamespacedKeyUtils.create
*/
fun namespacedKeyOf(namespace: String, key: String) =
NamespacedKeyUtils.create(namespace, key)
/**
* @see EcoPlugin.namespacedKeyFactory
*/
fun namespacedKeyOf(plugin: EcoPlugin, key: String) =
plugin.namespacedKeyFactory.create(key)

View File

@@ -0,0 +1,9 @@
@file:JvmName("NumberUtilsExtensions")
package com.willfp.eco.util
/**
* @see NumberUtils.toNumeral
*/
fun Number.toNumeral(): String =
NumberUtils.toNumeral(this.toInt())

View File

@@ -0,0 +1,32 @@
@file:JvmName("PlayerUtilsExtensions")
package com.willfp.eco.util
import net.kyori.adventure.audience.Audience
import org.bukkit.OfflinePlayer
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
/**
* @see PlayerUtils.getSavedDisplayName
*/
val OfflinePlayer.savedDisplayName: String
get() = PlayerUtils.getSavedDisplayName(this)
/**
* @see PlayerUtils.getAudience
*/
fun Player.asAudience(): Audience =
PlayerUtils.getAudience(this)
/**
* @see PlayerUtils.getAudience
*/
fun CommandSender.asAudience(): Audience =
PlayerUtils.getAudience(this)
/**
* @see PlayerUtils.runExempted
*/
fun Player.runExempted(action: () -> Unit) =
PlayerUtils.runExempted(this, action)

View File

@@ -0,0 +1,11 @@
@file:JvmName("PotionUtilsExtensions")
package com.willfp.eco.util
import org.bukkit.potion.PotionData
/**
* @see PotionData.duration
*/
val PotionData.duration: Int
get() = PotionUtils.getDuration(this)

View File

@@ -0,0 +1,11 @@
@file:JvmName("ServerUtilsExtensions")
package com.willfp.eco.util
import org.bukkit.Server
/**
* @see ServerUtils.getTps
*/
val Server.tps: Double
get() = ServerUtils.getTps()

View File

@@ -0,0 +1,17 @@
@file:JvmName("SkullUtilsExtensions")
package com.willfp.eco.util
import org.bukkit.inventory.meta.SkullMeta
/**
* @see SkullUtils.getSkullTexture
* @see SkullUtils.setSkullTexture
*/
var SkullMeta.texture: String?
get() = SkullUtils.getSkullTexture(this)
set(value) {
if (value != null) {
SkullUtils.setSkullTexture(this, value)
}
}

View File

@@ -0,0 +1,42 @@
@file:JvmName("StringUtilsExtensions")
package com.willfp.eco.util
import net.kyori.adventure.text.Component
import org.bukkit.entity.Player
/**
* @see StringUtils.toComponent
*/
fun String.toComponent(): Component =
StringUtils.toComponent(this)
/**
* @see StringUtils.toLegacy
*/
fun Component.toLegacy(): String =
StringUtils.toLegacy(this)
/**
* @see StringUtils.format
*/
fun String.formatEco(
player: Player? = null,
formatPlaceholders: Boolean = false
) = StringUtils.format(
this,
player,
if (formatPlaceholders) StringUtils.FormatOption.WITH_PLACEHOLDERS else StringUtils.FormatOption.WITHOUT_PLACEHOLDERS
)
/**
* @see StringUtils.formatList
*/
fun List<String>.formatEco(
player: Player? = null,
formatPlaceholders: Boolean = false
): List<String> = StringUtils.formatList(
this,
player,
if (formatPlaceholders) StringUtils.FormatOption.WITH_PLACEHOLDERS else StringUtils.FormatOption.WITHOUT_PLACEHOLDERS
)

View File

@@ -0,0 +1,17 @@
@file:JvmName("VectorUtilsExtensions")
package com.willfp.eco.util
import org.bukkit.util.Vector
/**
* @see VectorUtils.isFinite
*/
val Vector.isFinite: Boolean
get() = VectorUtils.isFinite(this)
/**
* @see VectorUtils.simplifyVector
*/
fun Vector.simplify(): Vector =
VectorUtils.simplifyVector(this)

View File

@@ -1,29 +1,8 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0"
}
}
group 'com.willfp'
version rootProject.version
subprojects {
apply plugin: "kotlin"
dependencies {
compileOnly project(":eco-api")
compileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.6.0'
}
compileKotlin {
kotlinOptions {
jvmTarget = "17"
}
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_17
}
}
}

View File

@@ -7,5 +7,5 @@ dependencies {
compileOnly 'org.reflections:reflections:0.9.12'
compileOnly 'net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT'
compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0'
compileOnly 'com.google.guava:guava:31.0.1-jre'
compileOnly 'org.objenesis:objenesis:3.2'
}

View File

@@ -0,0 +1,35 @@
package com.willfp.eco.internal
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.PluginProps
import com.willfp.eco.core.config.TransientConfig
import com.willfp.eco.core.config.interfaces.Config
object EcoPropsParser : PluginProps.PropsParser<Config> {
override fun parseFrom(config: Config): PluginProps {
val resourceId = config.getIntOrNull("resource-id") ?: 0
val bStatsId = config.getIntOrNull("bstats-id") ?: 0
val proxyPackage = config.getStringOrNull("proxy-package") ?: ""
val color = config.getStringOrNull("color") ?: "&f"
val supportsExtensions = config.getBoolOrNull("supports-extensions") ?: false
return blankProps.apply {
this.resourceId = resourceId
this.bStatsId = bStatsId
this.proxyPackage = proxyPackage
this.color = color
this.isSupportingExtensions = supportsExtensions
}
}
fun parseForPlugin(plugin: Class<out EcoPlugin>): PluginProps {
if (!PluginProps.hasParserFor(Config::class.java)) {
PluginProps.registerParser(Config::class.java, this)
}
return PluginProps.parse(
TransientConfig(plugin.getResourceAsStream("/eco.yml")),
Config::class.java
)
}
}

View File

@@ -15,7 +15,7 @@ import com.willfp.eco.internal.config.yaml.EcoYamlConfigSection
import org.bukkit.configuration.file.YamlConfiguration
import java.io.StringReader
class EcoConfigFactory : ConfigFactory {
object EcoConfigFactory : ConfigFactory {
override fun createConfig(config: YamlConfiguration): Config {
return EcoYamlConfigSection(config)
}

View File

@@ -5,7 +5,7 @@ import com.willfp.eco.core.display.Display
import com.willfp.eco.core.display.DisplayHandler
import com.willfp.eco.core.display.DisplayModule
import com.willfp.eco.core.display.DisplayPriority
import com.willfp.eco.core.fast.FastItemStack
import com.willfp.eco.core.fast.fast
import org.bukkit.NamespacedKey
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
@@ -60,7 +60,7 @@ class EcoDisplayHandler(plugin: EcoPlugin) : DisplayHandler {
Display.unfinalize(itemStack)
}
val fast = FastItemStack.wrap(itemStack)
val fast = itemStack.fast()
val lore = fast.lore
if (lore.isNotEmpty() && lore.removeIf { line: String ->

View File

@@ -10,7 +10,6 @@ import org.bukkit.Material
import org.bukkit.entity.EntityType
import org.bukkit.entity.ExperienceOrb
import org.bukkit.entity.Player
import org.bukkit.event.player.PlayerExpChangeEvent
import org.bukkit.inventory.ItemStack
import org.bukkit.util.Vector
@@ -73,12 +72,10 @@ open class EcoDropQueue(val player: Player) : InternalDropQueue {
world.dropItem(location, drop!!).velocity = Vector()
}
if (xp > 0) {
val event = PlayerExpChangeEvent(player, xp)
Bukkit.getPluginManager().callEvent(event)
val orb =
world.spawnEntity(player.location.add(0.0, 0.2, 0.0), EntityType.EXPERIENCE_ORB) as ExperienceOrb
orb.velocity = Vector(0, 0, 0)
orb.experience = event.amount
orb.experience = xp
}
} else {
for (drop in items) {
@@ -94,4 +91,4 @@ open class EcoDropQueue(val player: Player) : InternalDropQueue {
init {
location = player.location
}
}
}

View File

@@ -0,0 +1,29 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
class EntityArgParserSilent : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var silent = false
for (arg in args) {
if (arg.equals("silent", true)) {
silent = true
}
}
if (!silent) {
return null
}
return EntityArgParseResult(
{
it.isSilent
},
{
it.isSilent = true
}
)
}
}

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.internal.extensions
import com.google.common.collect.ImmutableSet
import com.willfp.eco.core.Eco
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.config.TransientConfig
import com.willfp.eco.core.extensions.Extension
@@ -32,6 +33,9 @@ class EcoExtensionLoader(
runCatching { loadExtension(extensionJar) }.onFailure {
this.plugin.logger.warning(extensionJar.name + " caused an error!")
if (Eco.getHandler().ecoPlugin.configYml.getBool("log-full-extension-errors")) {
it.printStackTrace()
}
}
}
}

View File

@@ -2,10 +2,11 @@ package com.willfp.eco.internal.factory
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.factory.NamespacedKeyFactory
import com.willfp.eco.util.NamespacedKeyUtils
import org.bukkit.NamespacedKey
class EcoNamespacedKeyFactory(private val plugin: EcoPlugin) : NamespacedKeyFactory {
override fun create(key: String): NamespacedKey {
return NamespacedKey(plugin, key)
return NamespacedKeyUtils.create(plugin.name, key)
}
}

View File

@@ -0,0 +1,31 @@
package com.willfp.eco.internal.fast
import org.bukkit.NamespacedKey
import org.objenesis.ObjenesisStd
interface InternalNamespacedKeyFactory {
fun create(namespace: String, key: String): NamespacedKey
}
class FastInternalNamespacedKeyFactory : InternalNamespacedKeyFactory {
private val creator = ObjenesisStd().getInstantiatorOf(NamespacedKey::class.java)
private val namespaceField = NamespacedKey::class.java.getDeclaredField("namespace")
.apply { isAccessible = true }
private val keyField = NamespacedKey::class.java.getDeclaredField("key")
.apply { isAccessible = true }
override fun create(namespace: String, key: String): NamespacedKey {
val namespacedKey = creator.newInstance()
keyField.set(namespacedKey, key.lowercase())
namespaceField.set(namespacedKey, namespace.lowercase())
return namespacedKey
}
}
class SafeInternalNamespacedKeyFactory : InternalNamespacedKeyFactory {
override fun create(namespace: String, key: String): NamespacedKey {
@Suppress("DEPRECATION")
return NamespacedKey(namespace, key)
}
}

View File

@@ -12,7 +12,7 @@ class EcoCaptiveSlot(
allowMovingItem,
allowMovingItem,
allowMovingItem,
{ _, _, _ -> }
{ _, _, prev -> prev }
) {
override fun isCaptive(): Boolean {
return true

View File

@@ -9,5 +9,5 @@ class EcoFillerSlot(itemStack: ItemStack) : EcoSlot(
{ _, _, _ -> },
{ _, _, _ -> },
{ _, _, _ -> },
{ _, _, _ -> }
{ _, _, prev -> prev }
)

View File

@@ -3,8 +3,8 @@ package com.willfp.eco.internal.gui.slot
import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.core.gui.slot.functional.SlotHandler
import com.willfp.eco.core.gui.slot.functional.SlotModifier
import com.willfp.eco.core.gui.slot.functional.SlotProvider
import com.willfp.eco.core.gui.slot.functional.SlotUpdater
import com.willfp.eco.internal.gui.menu.MenuHandler
import org.bukkit.entity.Player
import org.bukkit.event.inventory.ClickType
@@ -18,7 +18,7 @@ open class EcoSlot(
private val onShiftLeftClick: SlotHandler,
private val onShiftRightClick: SlotHandler,
private val onMiddleClick: SlotHandler,
private val modifier: SlotModifier
private val updater: SlotUpdater
) : Slot {
fun handleInventoryClick(
@@ -38,8 +38,7 @@ open class EcoSlot(
override fun getItemStack(player: Player): ItemStack {
val menu = MenuHandler.getMenu(player.openInventory.topInventory)!!
val prev = provider.provide(player, menu)
modifier.modify(player, menu, prev)
return prev
return updater.update(player, menu, prev)
}
fun getItemStack(
@@ -47,8 +46,7 @@ open class EcoSlot(
menu: Menu
): ItemStack {
val prev = provider.provide(player, menu)
modifier.modify(player, menu, prev)
return prev
return updater.update(player, menu, prev)
}
override fun isCaptive(): Boolean {

View File

@@ -3,12 +3,12 @@ package com.willfp.eco.internal.gui.slot
import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.core.gui.slot.SlotBuilder
import com.willfp.eco.core.gui.slot.functional.SlotHandler
import com.willfp.eco.core.gui.slot.functional.SlotModifier
import com.willfp.eco.core.gui.slot.functional.SlotProvider
import com.willfp.eco.core.gui.slot.functional.SlotUpdater
class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder {
private var captive = false
private var modifier: SlotModifier = SlotModifier{ player, menu, _ -> provider.provide(player, menu)}
private var updater: SlotUpdater = SlotUpdater { player, menu, _ -> provider.provide(player, menu) }
private var onLeftClick =
SlotHandler { _, _, _ -> run { } }
@@ -51,8 +51,8 @@ class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder {
return this
}
override fun setModifier(modifier: SlotModifier): SlotBuilder {
this.modifier = modifier
override fun setUpdater(updater: SlotUpdater): SlotBuilder {
this.updater = updater
return this
}
@@ -60,7 +60,7 @@ class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder {
return if (captive) {
EcoCaptiveSlot(provider)
} else {
EcoSlot(provider, onLeftClick, onRightClick, onShiftLeftClick, onShiftRightClick, onMiddleClick, modifier)
EcoSlot(provider, onLeftClick, onRightClick, onShiftLeftClick, onShiftRightClick, onMiddleClick, updater)
}
}
}

View File

@@ -1,8 +1,8 @@
package com.willfp.eco.internal.items
import com.willfp.eco.core.fast.FastItemStack
import com.willfp.eco.core.fast.fast
import com.willfp.eco.core.items.args.LookupArgParser
import org.bukkit.NamespacedKey
import com.willfp.eco.util.NamespacedKeyUtils
import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.EnchantmentStorageMeta
@@ -20,7 +20,7 @@ class ArgParserEnchantment : LookupArgParser {
continue
}
val enchant = Enchantment.getByKey(NamespacedKey.minecraft(argSplit[0].lowercase()))
val enchant = Enchantment.getByKey(NamespacedKeyUtils.create("minecraft", argSplit[0]))
val level = argSplit[1].toIntOrNull()
if (enchant != null && level != null) {
@@ -41,7 +41,7 @@ class ArgParserEnchantment : LookupArgParser {
}
return Predicate {
val onItem = FastItemStack.wrap(it).getEnchantmentsOnItem(true)
val onItem = it.fast().getEnchants(true)
for ((enchant, level) in enchants) {
if ((onItem[enchant] ?: 0) < level) {

View File

@@ -4,7 +4,7 @@ import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.proxy.ProxyConstants
import com.willfp.eco.core.proxy.ProxyFactory
import com.willfp.eco.core.proxy.exceptions.ProxyError
import com.willfp.eco.core.proxy.exceptions.UnsupportedVersionException
import com.willfp.eco.core.proxy.exceptions.UnsupportedVersionError
import java.net.URLClassLoader
import java.util.IdentityHashMap
@@ -34,21 +34,26 @@ class EcoProxyFactory(
return proxy
}
} catch (e: Exception) {
throwError(e)
throw proxyErrorFrom(e)
}
throwError(IllegalArgumentException())
throw RuntimeException("Something went wrong.")
throw proxyErrorFrom(IllegalArgumentException("Class doesn't seem to be a proxy."))
}
private fun throwError(e: Exception?) {
e?.printStackTrace()
private fun proxyErrorFrom(e: Exception): Throwable {
plugin.logger.severe("Fatal error with proxies! This plugin can't load.")
if (!SUPPORTED_VERSIONS.contains(ProxyConstants.NMS_VERSION)) {
throw UnsupportedVersionException("You're running an unsupported server version: " + ProxyConstants.NMS_VERSION)
return if (!SUPPORTED_VERSIONS.contains(ProxyConstants.NMS_VERSION)) {
ProxyError(
"Could not initialize proxy.",
UnsupportedVersionError()
)
} else {
throw ProxyError("Error with proxies - here's a stacktrace. Only god can help you now.")
ProxyError(
"Could not initialize proxy. If you're seeing this error message"
+ ", something has gone badly wrong. This almost definitely isn't user error, blame the developer.",
e
)
}
}

View File

@@ -1,14 +1,17 @@
@file:Suppress("DEPRECATION")
package com.willfp.eco.internal.requirement
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
import com.willfp.eco.core.requirement.Requirement
import com.willfp.eco.core.requirement.RequirementFactory
import com.willfp.eco.internal.requirement.requirements.RequirementHasPermission
import com.willfp.eco.internal.requirement.requirements.RequirementPlaceholderEquals
import com.willfp.eco.internal.requirement.requirements.RequirementPlaceholderGreaterThan
import com.willfp.eco.internal.requirement.requirements.RequirementPlaceholderLessThan
import com.willfp.eco.internal.requirement.requirements.RequirementTrue
import org.bukkit.entity.Player
class EcoRequirementFactory: RequirementFactory {
@Deprecated(
"Requirement system is marked as for-removal from eco",
level = DeprecationLevel.WARNING
)
class EcoRequirementFactory : RequirementFactory {
override fun create(name: String): Requirement {
return when (name.lowercase()) {
"has-permission" -> RequirementHasPermission()
@@ -18,4 +21,93 @@ class EcoRequirementFactory: RequirementFactory {
else -> RequirementTrue()
}
}
}
}
@Deprecated(
"Requirement system is marked as for-removal from eco",
level = DeprecationLevel.WARNING
)
class RequirementHasPermission : Requirement() {
override fun doesPlayerMeet(
player: Player,
args: List<String>
): Boolean {
if (args.isEmpty()) {
return false
}
val permission = args[0]
return player.hasPermission(permission)
}
}
@Deprecated(
"Requirement system is marked as for-removal from eco",
level = DeprecationLevel.WARNING
)
class RequirementPlaceholderEquals : Requirement() {
override fun doesPlayerMeet(
player: Player,
args: List<String>
): Boolean {
if (args.size < 2) {
return false
}
val placeholder = args[0]
val equals = args[1]
return PlaceholderManager.translatePlaceholders(placeholder, player).equals(equals, ignoreCase = true)
}
}
@Deprecated(
"Requirement system is marked as for-removal from eco",
level = DeprecationLevel.WARNING
)
@SuppressWarnings("DEPRECATION")
class RequirementPlaceholderGreaterThan : Requirement() {
override fun doesPlayerMeet(
player: Player,
args: List<String>
): Boolean {
if (args.size < 2) {
return false
}
val placeholder = args[0]
val equals = args[1].toDoubleOrNull() ?: return false
return (PlaceholderManager.translatePlaceholders(placeholder, player).toDoubleOrNull() ?: 0.0) >= equals
}
}
@Deprecated(
"Requirement system is marked as for-removal from eco",
level = DeprecationLevel.WARNING
)
class RequirementPlaceholderLessThan : Requirement() {
override fun doesPlayerMeet(
player: Player,
args: List<String>
): Boolean {
if (args.size < 2) {
return false
}
val placeholder = args[0]
val equals = args[1].toDoubleOrNull() ?: return false
return (PlaceholderManager.translatePlaceholders(placeholder, player).toDoubleOrNull() ?: 0.0) < equals
}
}
@Deprecated(
"Requirement system is marked as for-removal from eco",
level = DeprecationLevel.WARNING
)
class RequirementTrue : Requirement() {
override fun doesPlayerMeet(
player: Player,
args: List<String>
): Boolean {
return true
}
}

View File

@@ -1,18 +0,0 @@
package com.willfp.eco.internal.requirement.requirements
import com.willfp.eco.core.requirement.Requirement
import org.bukkit.entity.Player
class RequirementHasPermission : Requirement() {
override fun doesPlayerMeet(
player: Player,
args: List<String>
): Boolean {
if (args.isEmpty()) {
return false
}
val permission = args[0]
return player.hasPermission(permission)
}
}

View File

@@ -1,20 +0,0 @@
package com.willfp.eco.internal.requirement.requirements
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
import com.willfp.eco.core.requirement.Requirement
import org.bukkit.entity.Player
class RequirementPlaceholderEquals : Requirement() {
override fun doesPlayerMeet(
player: Player,
args: List<String>
): Boolean {
if (args.size < 2) {
return false
}
val placeholder = args[0]
val equals = args[1]
return PlaceholderManager.translatePlaceholders(placeholder, player).equals(equals, ignoreCase = true)
}
}

View File

@@ -1,20 +0,0 @@
package com.willfp.eco.internal.requirement.requirements
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
import com.willfp.eco.core.requirement.Requirement
import org.bukkit.entity.Player
class RequirementPlaceholderGreaterThan : Requirement() {
override fun doesPlayerMeet(
player: Player,
args: List<String>
): Boolean {
if (args.size < 2) {
return false
}
val placeholder = args[0]
val equals = args[1].toDoubleOrNull() ?: return false
return (PlaceholderManager.translatePlaceholders(placeholder, player).toDoubleOrNull() ?: 0.0) >= equals
}
}

View File

@@ -1,20 +0,0 @@
package com.willfp.eco.internal.requirement.requirements
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
import com.willfp.eco.core.requirement.Requirement
import org.bukkit.entity.Player
class RequirementPlaceholderLessThan : Requirement() {
override fun doesPlayerMeet(
player: Player,
args: List<String>
): Boolean {
if (args.size < 2) {
return false
}
val placeholder = args[0]
val equals = args[1].toDoubleOrNull() ?: return false
return (PlaceholderManager.translatePlaceholders(placeholder, player).toDoubleOrNull() ?: 0.0) < equals
}
}

View File

@@ -1,13 +0,0 @@
package com.willfp.eco.internal.requirement.requirements
import com.willfp.eco.core.requirement.Requirement
import org.bukkit.entity.Player
class RequirementTrue : Requirement() {
override fun doesPlayerMeet(
player: Player,
args: List<String>
): Boolean {
return true
}
}

View File

@@ -8,7 +8,7 @@ import org.bukkit.inventory.MerchantRecipe
import java.lang.reflect.Field
class VillagerTrade : VillagerTradeProxy {
private var handle: Field
private val handle: Field = CraftMerchantRecipe::class.java.getDeclaredField("handle")
override fun displayTrade(
recipe: MerchantRecipe,
@@ -35,7 +35,6 @@ class VillagerTrade : VillagerTradeProxy {
}
init {
handle = CraftMerchantRecipe::class.java.getDeclaredField("handle")
handle.isAccessible = true
}
}

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.internal.spigot.proxy.v1_16_R3.fast
import com.willfp.eco.internal.fast.EcoFastItemStack
import com.willfp.eco.util.NamespacedKeyUtils
import com.willfp.eco.util.StringUtils
import net.minecraft.server.v1_16_R3.Item
import net.minecraft.server.v1_16_R3.ItemEnchantedBook
@@ -11,7 +12,6 @@ import net.minecraft.server.v1_16_R3.NBTTagList
import net.minecraft.server.v1_16_R3.NBTTagString
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_16_R3.util.CraftNamespacedKey
import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.ItemFlag
import kotlin.experimental.and
@@ -20,7 +20,7 @@ class NMSFastItemStack(itemStack: org.bukkit.inventory.ItemStack) : EcoFastItemS
itemStack.getNMSStack(), itemStack
) {
private var loreCache: List<String>? = null
override fun getEnchantmentsOnItem(checkStored: Boolean): Map<Enchantment, Int> {
override fun getEnchants(checkStored: Boolean): Map<Enchantment, Int> {
val enchantmentNBT = if (checkStored && handle.item === Items.ENCHANTED_BOOK) ItemEnchantedBook.d(
handle
) else handle.enchantments
@@ -29,7 +29,7 @@ class NMSFastItemStack(itemStack: org.bukkit.inventory.ItemStack) : EcoFastItemS
val compound = base as NBTTagCompound
val key = compound.getString("id")
val level: Int = ('\uffff'.code.toShort() and compound.getShort("lvl")).toInt()
val found = Enchantment.getByKey(CraftNamespacedKey.fromStringOrNull(key))
val found = Enchantment.getByKey(NamespacedKeyUtils.fromStringOrNull(key))
if (found != null) {
foundEnchantments[found] = level
}

View File

@@ -1,5 +1,5 @@
plugins {
id("io.papermc.paperweight.userdev") version "1.3.3"
id("io.papermc.paperweight.userdev") version "1.3.4"
}
group = "com.willfp"

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.internal.spigot.proxy.v1_17_R1.fast
import com.willfp.eco.internal.fast.EcoFastItemStack
import com.willfp.eco.util.NamespacedKeyUtils
import com.willfp.eco.util.StringUtils
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
@@ -11,7 +12,6 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_17_R1.util.CraftNamespacedKey
import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.ItemFlag
import kotlin.experimental.and
@@ -21,7 +21,7 @@ class NMSFastItemStack(itemStack: org.bukkit.inventory.ItemStack) : EcoFastItemS
) {
private var loreCache: List<String>? = null
override fun getEnchantmentsOnItem(checkStored: Boolean): Map<Enchantment, Int> {
override fun getEnchants(checkStored: Boolean): Map<Enchantment, Int> {
val enchantmentNBT =
if (checkStored && handle.item === Items.ENCHANTED_BOOK) EnchantedBookItem.getEnchantments(
handle
@@ -31,7 +31,7 @@ class NMSFastItemStack(itemStack: org.bukkit.inventory.ItemStack) : EcoFastItemS
val compound = base as CompoundTag
val key = compound.getString("id")
val level = ('\uffff'.code.toShort() and compound.getShort("lvl")).toInt()
val found = Enchantment.getByKey(CraftNamespacedKey.fromStringOrNull(key))
val found = Enchantment.getByKey(NamespacedKeyUtils.fromStringOrNull(key))
if (found != null) {
foundEnchantments[found] = level
}
@@ -176,6 +176,7 @@ class NMSFastItemStack(itemStack: org.bukkit.inventory.ItemStack) : EcoFastItemS
}
override fun hashCode(): Int {
@Suppress("KotlinDeprecation")
return handle.tag?.hashCode() ?: (0b00010101 * 31 + Item.getId(handle.item))
}

View File

@@ -1,5 +1,5 @@
plugins {
id("io.papermc.paperweight.userdev") version "1.3.3"
id("io.papermc.paperweight.userdev") version "1.3.4"
}
group = "com.willfp"

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1.fast
import com.willfp.eco.internal.fast.EcoFastItemStack
import com.willfp.eco.util.NamespacedKeyUtils
import com.willfp.eco.util.StringUtils
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
@@ -11,7 +12,6 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_18_R1.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_18_R1.util.CraftNamespacedKey
import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.ItemFlag
import kotlin.experimental.and
@@ -22,7 +22,7 @@ class NMSFastItemStack(itemStack: org.bukkit.inventory.ItemStack) : EcoFastItemS
) {
private var loreCache: List<String>? = null
override fun getEnchantmentsOnItem(checkStored: Boolean): Map<Enchantment, Int> {
override fun getEnchants(checkStored: Boolean): Map<Enchantment, Int> {
val enchantmentNBT =
if (checkStored && handle.getItem() === Items.ENCHANTED_BOOK) EnchantedBookItem.getEnchantments(
handle
@@ -32,7 +32,7 @@ class NMSFastItemStack(itemStack: org.bukkit.inventory.ItemStack) : EcoFastItemS
val compound = base as CompoundTag
val key = compound.getString("id")
val level = ('\uffff'.code.toShort() and compound.getShort("lvl")).toInt()
val found = Enchantment.getByKey(CraftNamespacedKey.fromStringOrNull(key))
val found = Enchantment.getByKey(NamespacedKeyUtils.fromStringOrNull(key))
if (found != null) {
foundEnchantments[found] = level
}

View File

@@ -26,6 +26,7 @@ dependencies {
compileOnly 'com.gmail.nossr50.mcMMO:mcMMO:2.1.202'
compileOnly 'me.clip:placeholderapi:2.10.10'
compileOnly 'com.github.oraxen:oraxen:bd81ace154'
compileOnly 'com.github.Ssomar-Developement:ExecutableItems:master-SNAPSHOT'
compileOnly 'com.github.brcdev-minecraft:shopgui-api:2.2.0'
compileOnly 'com.github.LoneDev6:API-ItemsAdder:2.4.7'
compileOnly 'com.arcaniax:HeadDatabase-API:1.3.0'
@@ -39,10 +40,9 @@ dependencies {
compileOnly 'com.bgsoftware:SuperiorSkyblockAPI:1.8.3'
compileOnly 'com.github.MilkBowl:VaultAPI:1.7'
compileOnly 'world.bentobox:bentobox:1.17.3-SNAPSHOT'
compileOnly 'com.google.guava:guava:31.0.1-jre'
compileOnly 'com.iridium:IridiumSkyblock:3.1.2'
compileOnly 'com.github.WhipDevelopment:CrashClaim:f9cd7d92eb'
compileOnly 'com.wolfyscript.wolfyutilities:wolfyutilities:1.7.8.1'
compileOnly 'com.wolfyscript.wolfyutilities:wolfyutilities:3.16.0.0'
compileOnly 'com.github.decentsoftware-eu:decentholograms:2.1.2'
compileOnly 'io.lumine.xikage:MythicMobs:4.9.1'
@@ -54,6 +54,9 @@ dependencies {
compileOnly 'com.github.sirblobman.combatlogx:api:11.0.0.0-SNAPSHOT'
compileOnly 'com.github.sirblobman.combatlogx.expansion:newbie-helper:11.0.0.0-SNAPSHOT'
// LibsDisguises
compileOnly 'LibsDisguises:LibsDisguises:10.0.26'
compileOnly fileTree(dir: '../../lib', include: ['*.jar'])
}

View File

@@ -1,339 +0,0 @@
package com.willfp.eco.internal.spigot.recipes;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.items.Items;
import com.willfp.eco.core.items.TestableItem;
import com.willfp.eco.core.recipe.Recipes;
import com.willfp.eco.core.recipe.parts.MaterialTestableItem;
import com.willfp.eco.core.recipe.parts.ModifiedTestableItem;
import com.willfp.eco.core.recipe.parts.TestableStack;
import com.willfp.eco.core.recipe.recipes.CraftingRecipe;
import com.willfp.eco.core.recipe.recipes.ShapedCraftingRecipe;
import org.bukkit.Keyed;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.event.inventory.PrepareItemCraftEvent;
import org.bukkit.event.player.PlayerRecipeDiscoverEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ShapedRecipe;
import org.jetbrains.annotations.NotNull;
public class ShapedRecipeListener extends PluginDependent<EcoPlugin> implements Listener {
public ShapedRecipeListener(@NotNull final EcoPlugin plugin) {
super(plugin);
}
private void allow(@NotNull final Event event,
@NotNull final CraftingRecipe recipe) {
if (event instanceof PrepareItemCraftEvent) {
((PrepareItemCraftEvent) event).getInventory().setResult(recipe.getOutput());
}
if (event instanceof CraftItemEvent) {
((CraftItemEvent) event).getInventory().setResult(recipe.getOutput());
}
}
private void deny(@NotNull final Event event) {
if (event instanceof PrepareItemCraftEvent) {
((PrepareItemCraftEvent) event).getInventory().setResult(new ItemStack(Material.AIR));
}
if (event instanceof CraftItemEvent) {
((CraftItemEvent) event).getInventory().setResult(new ItemStack(Material.AIR));
((CraftItemEvent) event).setResult(Event.Result.DENY);
((CraftItemEvent) event).setCancelled(true);
}
}
@EventHandler
public void complexRecipeListener(@NotNull final PrepareItemCraftEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe recipe)) {
return;
}
if (!EcoPlugin.getPluginNames().contains(recipe.getKey().getNamespace())) {
return;
}
if (!(event.getInventory().getViewers().get(0) instanceof Player player)) {
return;
}
ItemStack[] matrix = event.getInventory().getMatrix();
CraftingRecipe matched = Recipes.getMatch(matrix);
if (matched == null) {
deny(event);
return;
}
if (matched.test(matrix)) {
if (matched.getPermission() != null) {
if (player.hasPermission(matched.getPermission())) {
allow(event, matched);
} else {
deny(event);
}
} else {
allow(event, matched);
}
} else {
deny(event);
}
}
@EventHandler
public void complexRecipeListener(@NotNull final CraftItemEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe recipe)) {
return;
}
if (!EcoPlugin.getPluginNames().contains(recipe.getKey().getNamespace())) {
return;
}
if (!(event.getInventory().getViewers().get(0) instanceof Player player)) {
return;
}
ItemStack[] matrix = event.getInventory().getMatrix();
CraftingRecipe matched = Recipes.getMatch(matrix);
if (matched == null) {
deny(event);
return;
}
if (matched.test(matrix)) {
if (matched.getPermission() != null) {
if (player.hasPermission(matched.getPermission())) {
allow(event, matched);
} else {
deny(event);
}
} else {
allow(event, matched);
}
} else {
deny(event);
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void stackedRecipeListener(@NotNull final CraftItemEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe recipe)) {
return;
}
if (!EcoPlugin.getPluginNames().contains(recipe.getKey().getNamespace())) {
return;
}
ItemStack[] matrix = event.getInventory().getMatrix();
CraftingRecipe matched = Recipes.getMatch(matrix);
if (matched == null) {
return;
}
boolean isStackedRecipe = false;
int upperBound = 64;
for (int i = 0; i < 9; i++) {
ItemStack inMatrix = event.getInventory().getMatrix()[i];
TestableItem inRecipe = matched.getParts().get(i);
if (inRecipe instanceof TestableStack testableStack) {
int max = Math.floorDiv(inMatrix.getAmount(), testableStack.getAmount());
if (max < upperBound) {
upperBound = max;
}
isStackedRecipe = true;
} else if (inMatrix != null) {
int max = inMatrix.getAmount();
if (max < upperBound) {
upperBound = max;
}
}
}
if (!isStackedRecipe) {
return;
}
int toGivePerRecipe = event.getRecipe().getResult().getAmount();
int maxStackSize = event.getRecipe().getResult().getMaxStackSize();
while (toGivePerRecipe * upperBound > maxStackSize) {
upperBound--;
}
for (int i = 0; i < 9; i++) {
ItemStack inMatrix = event.getInventory().getMatrix()[i];
TestableItem inRecipe = matched.getParts().get(i);
if (inRecipe instanceof TestableStack testableStack) {
if (event.isShiftClick()) {
int amount = inMatrix.getAmount() + 1;
for (int j = 0; j < upperBound; j++) {
amount -= testableStack.getAmount();
}
inMatrix.setAmount(amount);
} else {
inMatrix.setAmount(inMatrix.getAmount() - (testableStack.getAmount() - 1));
}
}
}
int finalUpperBound = upperBound;
if (event.isShiftClick()) {
ItemStack result = event.getInventory().getResult();
if (result == null) {
return;
}
result.setAmount(result.getAmount() * finalUpperBound);
event.getInventory().setResult(result);
}
}
@EventHandler
public void preventUsingComplexPartInEcoRecipe(@NotNull final PrepareItemCraftEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe recipe)) {
return;
}
CraftingRecipe craftingRecipe = Recipes.getRecipe(recipe.getKey());
if (!(craftingRecipe instanceof ShapedCraftingRecipe shapedCraftingRecipe)) {
return;
}
for (int i = 0; i < 9; i++) {
ItemStack itemStack = event.getInventory().getMatrix()[i];
TestableItem part = shapedCraftingRecipe.getParts().get(i);
if (part instanceof MaterialTestableItem) {
if (Items.isCustomItem(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
return;
}
}
if (part instanceof ModifiedTestableItem modified) {
if (modified.getHandle() instanceof MaterialTestableItem) {
if (Items.isCustomItem(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
return;
}
}
}
if (part instanceof TestableStack modified) {
if (modified.getHandle() instanceof MaterialTestableItem) {
if (Items.isCustomItem(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
return;
}
}
}
}
}
@EventHandler
public void preventUsingComplexPartInEcoRecipe(@NotNull final CraftItemEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe recipe)) {
return;
}
CraftingRecipe craftingRecipe = Recipes.getRecipe(recipe.getKey());
if (!(craftingRecipe instanceof ShapedCraftingRecipe shapedCraftingRecipe)) {
return;
}
for (int i = 0; i < 9; i++) {
ItemStack itemStack = event.getInventory().getMatrix()[i];
TestableItem part = shapedCraftingRecipe.getParts().get(i);
if (part instanceof MaterialTestableItem) {
if (Items.isCustomItem(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
event.setResult(Event.Result.DENY);
event.setCancelled(true);
return;
}
}
if (part instanceof ModifiedTestableItem modified) {
if (modified.getHandle() instanceof MaterialTestableItem) {
if (Items.isCustomItem(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
event.setResult(Event.Result.DENY);
event.setCancelled(true);
return;
}
}
}
if (part instanceof TestableStack modified) {
if (modified.getHandle() instanceof MaterialTestableItem) {
if (Items.isCustomItem(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
return;
}
}
}
}
}
@EventHandler
public void preventUsingComplexPartInVanillaRecipe(@NotNull final PrepareItemCraftEvent event) {
if (!(event.getRecipe() instanceof Keyed recipe)) {
return;
}
if (EcoPlugin.getPluginNames().contains(recipe.getKey().getNamespace())) {
return;
}
for (ItemStack itemStack : event.getInventory().getMatrix()) {
if (Items.isCustomItem(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
return;
}
}
}
@EventHandler
public void preventUsingComplexPartInVanillaRecipe(@NotNull final CraftItemEvent event) {
if (!(event.getRecipe() instanceof Keyed recipe)) {
return;
}
if (EcoPlugin.getPluginNames().contains(recipe.getKey().getNamespace())) {
return;
}
for (ItemStack itemStack : event.getInventory().getMatrix()) {
if (Items.isCustomItem(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
event.setResult(Event.Result.DENY);
event.setCancelled(true);
return;
}
}
}
@EventHandler
public void preventLearningDisplayedRecipes(@NotNull final PlayerRecipeDiscoverEvent event) {
if (!EcoPlugin.getPluginNames().contains(event.getRecipe().getNamespace())) {
return;
}
if (event.getRecipe().getKey().contains("_displayed")) {
event.setCancelled(true);
}
}
}

Some files were not shown because too many files have changed in this diff Show More