Compare commits

..

140 Commits

Author SHA1 Message Date
Auxilor
13772002e8 Updated to 6.25.1 2022-02-17 17:03:16 +00:00
Auxilor
c9b84889e7 Fixed recursive caching bug 2022-02-17 17:03:10 +00:00
Auxilor
1513578266 Fixed recursive caching bug 2022-02-17 17:01:42 +00:00
Auxilor
89d6f2f867 Fixed initialization order 2022-02-17 12:53:54 +00:00
Auxilor
8e6d98c997 More MySQL Changes 2022-02-17 12:51:43 +00:00
Auxilor
5bc2cb31a4 Switched expiry from write to access (MySQL) 2022-02-17 12:47:59 +00:00
Auxilor
041575a103 Cached rows and columns with Caffeine 2022-02-17 12:47:32 +00:00
Auxilor
c88dac56b7 Added ability to manually categorize keys to improve performance 2022-02-17 12:21:26 +00:00
Auxilor
00da717f6d Changed key serialization 2022-02-17 11:49:26 +00:00
Auxilor
cc557378cc Preloaded known data keys 2022-02-16 18:16:09 +00:00
Auxilor
b5c49c79b8 Improvements to key saving 2022-02-16 18:13:04 +00:00
Auxilor
28018430e7 Categorized keys are now saved completely serialized 2022-02-16 18:01:41 +00:00
Auxilor
7b6c8d68a8 Key registration changes 2022-02-16 17:38:07 +00:00
Auxilor
ad3cb3a620 Fixed postInit 2022-02-16 16:48:40 +00:00
Auxilor
511a7e4830 Added optimisations to lazy column creation 2022-02-16 16:42:47 +00:00
Auxilor
5aeeafc041 MySQL Data Changes: Keys are now registered on first read/write 2022-02-16 16:32:38 +00:00
Auxilor
9a51fb8358 Updated to 6.25.0 2022-02-16 16:11:31 +00:00
Auxilor
eeefb9f40e Server persistence changes 2022-02-16 16:01:55 +00:00
Auxilor
aa1ce34cbc Updated to 6.24.4 2022-02-16 14:21:49 +00:00
Auxilor
47772c3ff7 Reverted Shaped Recipe changes 2022-02-16 14:21:03 +00:00
Auxilor
dfcac5d527 PR Changes 2022-02-14 13:28:37 +00:00
Auxilor
40f88f0b59 Revert "refactor(nms): Change checking if value is initialized to a lazy val"
This reverts commit 6361c0e8e9.
2022-02-14 13:28:25 +00:00
Auxilor
105355d967 Updated to 6.24.3 2022-02-14 13:15:55 +00:00
Will FP
3cddff22b8 Merge pull request #73
Bump com.github.johnrengelman.shadow from 7.1.0 to 7.1.2
2022-02-14 13:15:39 +00:00
Will FP
f8e930d29e Merge pull request #91
Update ShapedRecipeListener.kt
2022-02-14 13:15:28 +00:00
Will FP
9dbe088e66 Merge pull request #92
refactor(nms): Change checking if value is initialized to a lazy val
2022-02-14 13:15:17 +00:00
Racci
6361c0e8e9 refactor(nms): Change checking if value is initialized to a lazy val 2022-02-14 17:32:12 +11:00
casper
1135672241 Update ShapedRecipeListener.kt
| ShapedRecipeListener.kt Modified to change matrix at the end of the crafting to prevent duplication of items
2022-02-13 12:55:05 -05:00
Auxilor
80891e4a81 Fixed profile saveAll not working 2022-02-11 10:14:33 +00:00
Auxilor
3e0be3a629 Updated to 6.24.2 2022-02-09 15:20:30 +00:00
Auxilor
17819de2ea Fixed adult/baby parsers 2022-02-09 15:20:21 +00:00
Auxilor
209cdd6b0d Updated to 6.24.1 2022-02-05 17:05:29 +00:00
Auxilor
fbf6b2edd9 Added equipment arg parser 2022-02-05 17:05:18 +00:00
dependabot[bot]
8b9e8589a0 Bump com.github.johnrengelman.shadow from 7.1.0 to 7.1.2
Bumps com.github.johnrengelman.shadow from 7.1.0 to 7.1.2.

---
updated-dependencies:
- dependency-name: com.github.johnrengelman.shadow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-03 18:54:34 +00:00
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
128 changed files with 2973 additions and 865 deletions

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("com.github.johnrengelman.shadow") version "7.1.2"
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,7 +15,6 @@ 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;
@@ -33,6 +32,7 @@ import java.util.logging.Logger;
* @see Eco#getHandler()
*/
@ApiStatus.Internal
@SuppressWarnings("removal")
public interface Handler {
/**
* Create a scheduler.
@@ -210,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.
@@ -234,7 +235,7 @@ public interface Handler {
* @return The handler.
*/
@NotNull
PlayerProfileHandler getPlayerProfileHandler();
ProfileHandler getProfileHandler();
/**
* Create dummy entity - never spawned, exists purely in code.
@@ -259,4 +260,15 @@ public interface Handler {
@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

@@ -1,12 +1,18 @@
package com.willfp.eco.core.data.keys;
import com.willfp.eco.core.Eco;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
/**
* API to register persistent data keys.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface KeyRegistry {
/**
* Register a persistent data key to be stored.
@@ -21,4 +27,37 @@ public interface KeyRegistry {
* @return The keys.
*/
Set<PersistentDataKey<?>> getRegisteredKeys();
/**
* Mark key as category.
*
* @param key The key.
* @param category The category.
*/
void markKeyAs(@NotNull PersistentDataKey<?> key,
@NotNull KeyRegistry.KeyCategory category);
/**
* Get persistent data key from namespaced key.
*
* @param namespacedKey The key.
* @return The key, or null if not found.
*/
@Nullable
PersistentDataKey<?> getKeyFrom(@NotNull NamespacedKey namespacedKey);
/**
* Locations for key categorization.
*/
enum KeyCategory {
/**
* Player keys.
*/
PLAYER,
/**
* Server keys.
*/
SERVER
}
}

View File

@@ -3,7 +3,9 @@ package com.willfp.eco.core.data.keys;
import com.willfp.eco.core.Eco;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.Set;
/**
@@ -11,7 +13,7 @@ import java.util.Set;
*
* @param <T> The type of the data.
*/
public class PersistentDataKey<T> {
public final class PersistentDataKey<T> {
/**
* The key of the persistent data value.
*/
@@ -80,6 +82,32 @@ public class PersistentDataKey<T> {
return this.type;
}
/**
* Categorize key as a server key, will register new column to MySQL
* database immediately rather than waiting for auto-categorization.
* <p>
* This will improve performance.
*
* @return The key.
*/
public PersistentDataKey<T> server() {
Eco.getHandler().getKeyRegistry().markKeyAs(this, KeyRegistry.KeyCategory.SERVER);
return this;
}
/**
* Categorize key as a player key, will register new column to MySQL
* database immediately rather than waiting for auto-categorization.
* <p>
* This will improve performance.
*
* @return The key.
*/
public PersistentDataKey<T> player() {
Eco.getHandler().getKeyRegistry().markKeyAs(this, KeyRegistry.KeyCategory.PLAYER);
return this;
}
/**
* Get all persistent data keys.
*
@@ -88,4 +116,20 @@ public class PersistentDataKey<T> {
public static Set<PersistentDataKey<?>> values() {
return Eco.getHandler().getKeyRegistry().getRegisteredKeys();
}
@Override
public boolean equals(@Nullable final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof PersistentDataKey that)) {
return false;
}
return Objects.equals(this.getKey(), that.getKey());
}
@Override
public int hashCode() {
return Objects.hash(this.getKey());
}
}

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();
@@ -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

@@ -7,6 +7,7 @@ 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;
@@ -17,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.
@@ -96,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,
@@ -109,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

@@ -3,6 +3,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;
/**
* Utilities / API methods for {@link NamespacedKey}s.
@@ -45,8 +48,25 @@ public final class NamespacedKeyUtils {
*/
@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)

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,6 +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

View File

@@ -2,7 +2,7 @@ package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.entity.Animals
import org.bukkit.entity.Ageable
class EntityArgParserAdult : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
@@ -20,14 +20,14 @@ class EntityArgParserAdult : EntityArgParser {
return EntityArgParseResult(
{
if (it !is Animals) {
if (it !is Ageable) {
return@EntityArgParseResult false
}
it.isAdult
},
{
(it as? Animals)?.setAdult()
(it as? Ageable)?.setAdult()
}
)
}

View File

@@ -2,7 +2,7 @@ package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.entity.Animals
import org.bukkit.entity.Ageable
class EntityArgParserBaby : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
@@ -20,14 +20,14 @@ class EntityArgParserBaby : EntityArgParser {
return EntityArgParseResult(
{
if (it !is Animals) {
if (it !is Ageable) {
return@EntityArgParseResult false
}
!it.isAdult
},
{
(it as? Animals)?.setBaby()
(it as? Ageable)?.setBaby()
}
)
}

View File

@@ -0,0 +1,62 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.TestableItem
import org.bukkit.entity.LivingEntity
import org.bukkit.inventory.EquipmentSlot
class EntityArgParserEquipment : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
val equipment = mutableMapOf<EquipmentSlot, TestableItem>()
for (arg in args) {
val argSplit = arg.split(":")
for (slot in EquipmentSlot.values()) {
if (!argSplit[0].equals(slot.name, ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
equipment[slot] = Items.lookup(argSplit[1])
}
}
if (equipment.isEmpty()) {
return null
}
return EntityArgParseResult(
{
if (it !is LivingEntity) {
return@EntityArgParseResult false
}
val entityEquipment = it.equipment ?: return@EntityArgParseResult false
for ((slot, item) in equipment) {
if (!item.matches(entityEquipment.getItem(slot))) {
return@EntityArgParseResult false
}
}
return@EntityArgParseResult true
},
{
if (it !is LivingEntity) {
return@EntityArgParseResult
}
val entityEquipment = it.equipment ?: return@EntityArgParseResult
for ((slot, item) in equipment) {
entityEquipment.setItem(slot, item.item, false)
}
}
)
}
}

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

@@ -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,6 +1,6 @@
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 com.willfp.eco.util.NamespacedKeyUtils
import org.bukkit.enchantments.Enchantment
@@ -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

@@ -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(NamespacedKeyUtils.fromString(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

@@ -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(NamespacedKeyUtils.fromString(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

@@ -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(NamespacedKeyUtils.fromString(key))
val found = Enchantment.getByKey(NamespacedKeyUtils.fromStringOrNull(key))
if (found != null) {
foundEnchantments[found] = level
}

View File

@@ -40,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'
@@ -55,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);
}
}
}

View File

@@ -2,9 +2,11 @@ package com.willfp.eco.internal.spigot
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.Handler
import com.willfp.eco.core.PluginProps
import com.willfp.eco.core.fast.FastItemStack
import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration
import com.willfp.eco.internal.EcoCleaner
import com.willfp.eco.internal.EcoPropsParser
import com.willfp.eco.internal.Plugins
import com.willfp.eco.internal.config.EcoConfigFactory
import com.willfp.eco.internal.config.updating.EcoConfigHandler
@@ -21,12 +23,10 @@ import com.willfp.eco.internal.gui.EcoGUIFactory
import com.willfp.eco.internal.integrations.PlaceholderIntegrationPAPI
import com.willfp.eco.internal.logging.EcoLogger
import com.willfp.eco.internal.proxy.EcoProxyFactory
import com.willfp.eco.internal.requirement.EcoRequirementFactory
import com.willfp.eco.internal.scheduling.EcoScheduler
import com.willfp.eco.internal.spigot.data.DataYml
import com.willfp.eco.internal.spigot.data.EcoKeyRegistry
import com.willfp.eco.internal.spigot.data.EcoPlayerProfileHandler
import com.willfp.eco.internal.spigot.data.storage.MySQLDataHandler
import com.willfp.eco.internal.spigot.data.storage.YamlDataHandler
import com.willfp.eco.internal.spigot.data.EcoProfileHandler
import com.willfp.eco.internal.spigot.integrations.bstats.MetricHandler
import com.willfp.eco.internal.spigot.proxy.DummyEntityProxy
import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
@@ -39,14 +39,17 @@ import java.util.logging.Logger
@Suppress("UNUSED")
class EcoHandler : EcoSpigotPlugin(), Handler {
override val dataYml = DataYml(this)
private val cleaner = EcoCleaner()
private val requirementFactory = EcoRequirementFactory()
@Suppress("DEPRECATION")
private val requirementFactory = com.willfp.eco.internal.requirement.EcoRequirementFactory()
private var adventure: BukkitAudiences? = null
private val keyRegistry = EcoKeyRegistry(this)
private val playerProfileHandler = EcoPlayerProfileHandler(
if (this.configYml.getBool("mysql.enabled"))
MySQLDataHandler(this) else YamlDataHandler(this)
)
private val keyRegistry = EcoKeyRegistry()
private val playerProfileHandler = EcoProfileHandler(this.configYml.getBool("mysql.enabled"), this)
@Suppress("RedundantNullableReturnType")
private val keyFactory: InternalNamespacedKeyFactory? =
if (this.configYml.getBool("use-safer-namespacedkey-creation"))
SafeInternalNamespacedKeyFactory() else FastInternalNamespacedKeyFactory()
@@ -92,7 +95,7 @@ class EcoHandler : EcoSpigotPlugin(), Handler {
}
override fun getConfigFactory(): EcoConfigFactory {
return EcoConfigFactory()
return EcoConfigFactory
}
override fun getDropQueueFactory(): EcoDropQueueFactory {
@@ -131,7 +134,8 @@ class EcoHandler : EcoSpigotPlugin(), Handler {
MetricHandler.createMetrics(plugin)
}
override fun getRequirementFactory(): EcoRequirementFactory {
@Suppress("DEPRECATION")
override fun getRequirementFactory(): com.willfp.eco.internal.requirement.EcoRequirementFactory {
return requirementFactory
}
@@ -143,7 +147,7 @@ class EcoHandler : EcoSpigotPlugin(), Handler {
return keyRegistry
}
override fun getPlayerProfileHandler(): EcoPlayerProfileHandler {
override fun getProfileHandler(): EcoProfileHandler {
return playerProfileHandler
}
@@ -159,4 +163,8 @@ class EcoHandler : EcoSpigotPlugin(), Handler {
@Suppress("DEPRECATION")
return keyFactory?.create(namespace, key) ?: NamespacedKey(namespace, key)
}
override fun getProps(existing: PluginProps?, plugin: Class<out EcoPlugin>): PluginProps {
return existing ?: EcoPropsParser.parseForPlugin(plugin)
}
}

View File

@@ -24,6 +24,7 @@ import com.willfp.eco.internal.entities.EntityArgParserAttackDamage
import com.willfp.eco.internal.entities.EntityArgParserAttackSpeed
import com.willfp.eco.internal.entities.EntityArgParserBaby
import com.willfp.eco.internal.entities.EntityArgParserCharged
import com.willfp.eco.internal.entities.EntityArgParserEquipment
import com.willfp.eco.internal.entities.EntityArgParserExplosionRadius
import com.willfp.eco.internal.entities.EntityArgParserFlySpeed
import com.willfp.eco.internal.entities.EntityArgParserFollowRange
@@ -33,6 +34,7 @@ import com.willfp.eco.internal.entities.EntityArgParserKnockback
import com.willfp.eco.internal.entities.EntityArgParserKnockbackResistance
import com.willfp.eco.internal.entities.EntityArgParserName
import com.willfp.eco.internal.entities.EntityArgParserNoAI
import com.willfp.eco.internal.entities.EntityArgParserSilent
import com.willfp.eco.internal.entities.EntityArgParserSize
import com.willfp.eco.internal.entities.EntityArgParserSpawnReinforcements
import com.willfp.eco.internal.entities.EntityArgParserSpeed
@@ -45,6 +47,8 @@ import com.willfp.eco.internal.items.ArgParserTexture
import com.willfp.eco.internal.items.ArgParserUnbreakable
import com.willfp.eco.internal.spigot.arrows.ArrowDataListener
import com.willfp.eco.internal.spigot.data.DataListener
import com.willfp.eco.internal.spigot.data.DataYml
import com.willfp.eco.internal.spigot.data.EcoProfileHandler
import com.willfp.eco.internal.spigot.data.PlayerBlockListener
import com.willfp.eco.internal.spigot.data.storage.ProfileSaver
import com.willfp.eco.internal.spigot.display.PacketAutoRecipe
@@ -74,12 +78,14 @@ import com.willfp.eco.internal.spigot.integrations.anticheat.AnticheatVulcan
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefBentoBox
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogXV10
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogXV11
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCrashClaim
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefDeluxeCombat
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefFactionsUUID
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefGriefPrevention
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefIridiumSkyblock
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefKingdoms
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefLands
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefRPGHorses
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefSuperiorSkyblock2
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefTowny
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefWorldGuard
@@ -89,6 +95,7 @@ import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsExecut
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsHeadDatabase
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsItemsAdder
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsOraxen
import com.willfp.eco.internal.spigot.integrations.customrecipes.CustomRecipeCustomCrafting
import com.willfp.eco.internal.spigot.integrations.economy.EconomyVault
import com.willfp.eco.internal.spigot.integrations.hologram.HologramCMI
import com.willfp.eco.internal.spigot.integrations.hologram.HologramDecentHolograms
@@ -102,6 +109,9 @@ import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
import com.willfp.eco.internal.spigot.proxy.SkullProxy
import com.willfp.eco.internal.spigot.proxy.TPSProxy
import com.willfp.eco.internal.spigot.recipes.ShapedRecipeListener
import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInComplex
import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInEco
import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInVanilla
import com.willfp.eco.util.BlockUtils
import com.willfp.eco.util.NumberUtils
import com.willfp.eco.util.ServerUtils
@@ -113,12 +123,9 @@ import org.bukkit.Material
import org.bukkit.event.Listener
import org.bukkit.inventory.ItemStack
abstract class EcoSpigotPlugin : EcoPlugin(
773,
10043,
"com.willfp.eco.internal.spigot.proxy",
"&a"
) {
abstract class EcoSpigotPlugin : EcoPlugin() {
abstract val dataYml: DataYml
init {
Items.registerArgParser(ArgParserEnchantment())
Items.registerArgParser(ArgParserColor())
@@ -145,6 +152,12 @@ abstract class EcoSpigotPlugin : EcoPlugin(
Entities.registerArgParser(EntityArgParserAdult())
Entities.registerArgParser(EntityArgParserCharged())
Entities.registerArgParser(EntityArgParserExplosionRadius())
Entities.registerArgParser(EntityArgParserSilent())
Entities.registerArgParser(EntityArgParserEquipment())
ShapedRecipeListener.registerListener(ComplexInComplex())
ShapedRecipeListener.registerListener(ComplexInEco())
ShapedRecipeListener.registerListener(ComplexInVanilla())
val skullProxy = getProxy(SkullProxy::class.java)
SkullUtils.initialize(
@@ -174,16 +187,17 @@ abstract class EcoSpigotPlugin : EcoPlugin(
(Eco.getHandler() as EcoHandler).setAdventure(BukkitAudiences.create(this))
}
this.logger.info("Ignore messages about deprecated events!")
// Init FIS
this.getProxy(FastItemStackFactoryProxy::class.java).create(ItemStack(Material.AIR)).unwrap()
// Preload categorized persistent data keys
(Eco.getHandler().profileHandler as EcoProfileHandler).initialize()
}
override fun handleDisable() {
this.logger.info("Saving player data...")
val start = System.currentTimeMillis()
Eco.getHandler().playerProfileHandler.save()
Eco.getHandler().profileHandler.save()
this.logger.info("Saved player data! Took ${System.currentTimeMillis() - start}ms")
Eco.getHandler().adventure?.close()
}
@@ -192,11 +206,6 @@ abstract class EcoSpigotPlugin : EcoPlugin(
CollatedRunnable(this)
DropManager.update(this)
ProfileSaver(this)
this.scheduler.runTimer(
{ Items.clearCache() },
this.configYml.getInt("item-cache-ttl").toLong(),
this.configYml.getInt("item-cache-ttl").toLong()
)
this.scheduler.runTimer(
{ clearFrames() },
this.configYml.getInt("display-frame-ttl").toLong(),
@@ -223,7 +232,8 @@ abstract class EcoSpigotPlugin : EcoPlugin(
IntegrationLoader("Towny") { AntigriefManager.register(AntigriefTowny()) },
IntegrationLoader("Lands") { AntigriefManager.register(AntigriefLands(this)) },
IntegrationLoader("Kingdoms") { AntigriefManager.register(AntigriefKingdoms()) },
//IntegrationLoader("CrashClaim") { AntigriefManager.register(AntigriefCrashClaim()) },
IntegrationLoader("RPGHorses") { AntigriefManager.register(AntigriefRPGHorses()) },
IntegrationLoader("CrashClaim") { AntigriefManager.register(AntigriefCrashClaim()) },
IntegrationLoader("CombatLogX") {
val pluginManager = Bukkit.getPluginManager()
val combatLogXPlugin = pluginManager.getPlugin("CombatLogX") ?: return@IntegrationLoader
@@ -252,7 +262,11 @@ abstract class EcoSpigotPlugin : EcoPlugin(
IntegrationLoader("ItemsAdder") { CustomItemsManager.register(CustomItemsItemsAdder()) },
IntegrationLoader("HeadDatabase") { CustomItemsManager.register(CustomItemsHeadDatabase(this)) },
IntegrationLoader("ExecutableItems") { CustomItemsManager.register(CustomItemsExecutableItems()) },
IntegrationLoader("CustomCrafting") { CustomItemsManager.register(CustomItemsCustomCrafting()) },
IntegrationLoader("CustomCrafting") {
CustomItemsManager.register(CustomItemsCustomCrafting()); ShapedRecipeListener.registerValidator(
CustomRecipeCustomCrafting()
)
},
// Shop
IntegrationLoader("ShopGUIPlus") { ShopManager.register(ShopShopGuiPlus()) },
@@ -302,7 +316,7 @@ abstract class EcoSpigotPlugin : EcoPlugin(
NaturalExpGainListeners(),
ArmorListener(),
EntityDeathByEntityListeners(this),
ShapedRecipeListener(this),
ShapedRecipeListener(),
GUIListener(this),
ArrowDataListener(this),
ArmorChangeEventListeners(this),

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