mirror of
https://github.com/alexcrea/CustomAnvil.git
synced 2026-06-24 00:26:16 +02:00
Compare commits
No commits in common. "v1.x.x" and "v1.15.8" have entirely different histories.
139 changed files with 1357 additions and 5063 deletions
92
.github/workflows/gradle.yml
vendored
92
.github/workflows/gradle.yml
vendored
|
|
@ -12,11 +12,9 @@ on:
|
|||
branches: [ "v1.x.x", "v2.x.x" ]
|
||||
pull_request:
|
||||
branches: [ "v1.x.x", "v2.x.x" ]
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}
|
||||
group: ${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
|
|
@ -25,10 +23,6 @@ jobs:
|
|||
permissions:
|
||||
contents: write
|
||||
|
||||
env:
|
||||
MODRINTH_VERSIONS: '["1.18.x", "1.19.x", "1.20.x", "1.21.x", "26.1.x", "26.2.x"]'
|
||||
MODRINTH_PLATFORMS: '["spigot", "paper", "purpur", "folia"]'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDKs
|
||||
|
|
@ -37,41 +31,21 @@ jobs:
|
|||
java-version: |
|
||||
21
|
||||
distribution: 'temurin'
|
||||
cache: gradle
|
||||
|
||||
- name: Cache Gradle root and wrapper
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: gradle-root-${{ runner.os }}-${{ hashFiles('build.gradle*') }}
|
||||
restore-keys: gradle-root-${{ runner.os }}-
|
||||
|
||||
# Setup paperweight cache
|
||||
- name: Cache paperweight
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
./nms/*/.gradle/caches/paperweight
|
||||
key: paperweight-submodules-${{ runner.os }}-${{ hashFiles('nms/*/build.gradle*') }}
|
||||
restore-keys: |
|
||||
paperweight-submodules-${{ runner.os }}-
|
||||
cache: 'gradle'
|
||||
|
||||
# Configure Gradle for optimal use in GitHub Actions, including caching of downloaded dependencies.
|
||||
# See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v5
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Make gradlew executable
|
||||
run: chmod +x ./gradlew
|
||||
|
||||
- name: Get small commit hash
|
||||
if: ${{ github.event_name != 'release' && success() }}
|
||||
run: echo "SMALL_COMMIT_HASH=$(git rev-parse --short ${{ github.sha }})" >> $GITHUB_ENV
|
||||
|
||||
- name: Build with Gradle Wrapper
|
||||
run: ./gradlew build --parallel --stacktrace
|
||||
run: ./gradlew build --parallel
|
||||
|
||||
# only submit dependency on push
|
||||
- name: Generate and submit dependency graph
|
||||
|
|
@ -89,7 +63,7 @@ jobs:
|
|||
echo "ONLINE_JAR_NAME=$(basename $ONLINE_JAR_PATH)" >> $GITHUB_ENV
|
||||
echo "OFFLINE_JAR_NAME=$(basename $OFFLINE_JAR_PATH)" >> $GITHUB_ENV
|
||||
|
||||
# upload the named jars as artifact
|
||||
# upload the named jars
|
||||
- name: Upload online JAR artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
|
@ -105,59 +79,3 @@ jobs:
|
|||
- name: Summarize tests results
|
||||
uses: jeantessier/test-summary-action@v1
|
||||
if: ${{ always() }}
|
||||
|
||||
# upload the jar to release
|
||||
- name: Upload jar to release
|
||||
if: ${{ github.event_name == 'release' && success() }}
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
build/libs/${{ env.ONLINE_JAR_NAME }}
|
||||
build/libs/${{ env.OFFLINE_JAR_NAME }}
|
||||
|
||||
- name: Hangar release
|
||||
if: ${{ (github.event_name != 'release' || github.event_name != 'push') && github.repository_owner == 'alexcrea' && success() }}
|
||||
env:
|
||||
HANGAR_API_TOKEN: ${{ secrets.HANGAR_API_TOKEN }}
|
||||
RELEASE_CHANGELOG: ${{ github.event.release.body }}
|
||||
run: ./gradlew publishAllPublicationsToHangar --stacktrace
|
||||
|
||||
- name: Modrinth publish alpha
|
||||
if: ${{ github.event_name == 'push' && github.repository_owner == 'alexcrea' && success() }}
|
||||
uses: cloudnode-pro/modrinth-publish@v2
|
||||
with:
|
||||
token: ${{ secrets.MODRINTH_TOKEN }}
|
||||
project: S75Ueiq9
|
||||
name: dev-${{ env.SMALL_COMMIT_HASH }}
|
||||
version: dev-${{ env.SMALL_COMMIT_HASH }}
|
||||
loaders: ${{ env.MODRINTH_PLATFORMS }}
|
||||
game-versions: ${{ env.MODRINTH_VERSIONS }}
|
||||
channel: alpha
|
||||
files: build/libs/${{ env.ONLINE_JAR_NAME }}
|
||||
changelog: ${{ github.event.head_commit.message }}
|
||||
|
||||
- name: Modrinth publish release
|
||||
if: ${{ github.event_name == 'release' && github.repository_owner == 'alexcrea' && success() }}
|
||||
uses: cloudnode-pro/modrinth-publish@v2
|
||||
with:
|
||||
token: ${{ secrets.MODRINTH_TOKEN }}
|
||||
project: S75Ueiq9
|
||||
name: ${{ github.event.release.name }}
|
||||
version: ${{ github.event.release.tag_name }}${{ github.event.release.prerelease && '-pre' || '' }}
|
||||
loaders: ${{ env.MODRINTH_PLATFORMS }}
|
||||
game-versions: ${{ env.MODRINTH_VERSIONS }}
|
||||
channel: ${{ github.event.release.prerelease == false && 'release' || 'beta' }}
|
||||
files: build/libs/${{ env.ONLINE_JAR_NAME }}
|
||||
changelog: ${{ github.event.release.body }}
|
||||
|
||||
- name: Send release note to discord
|
||||
if: ${{ github.event_name == 'release' && github.repository_owner == 'alexcrea' && success() }}
|
||||
uses: tsickert/discord-webhook@v7.0.0
|
||||
with:
|
||||
webhook-url: ${{ secrets.RELEASE_WEBHOOK_URL }}
|
||||
content: |
|
||||
${{ github.event.release.prerelease == false && '<@&1338546156325568642>' || '<@&1352296092989001768>' }}
|
||||
# New ${{ github.event.release.prerelease && 'beta ' || '' }}version of custom anvil ! <:CustomAnvil:1262550667986342001>([Modrinth](https://modrinth.com/plugin/customanvil), [Hangar](https://hangar.papermc.io/alexcrea/CustomAnvil) and [GitHub](${{ github.event.release.html_url }}) links)
|
||||
-# note: automated release. spigot is not uploaded yet.
|
||||
|
||||
${{ github.event.release.body }}
|
||||
|
|
|
|||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -14,9 +14,6 @@
|
|||
/impl/*/build
|
||||
/impl/*/.gradle
|
||||
|
||||
# run folder
|
||||
/run/
|
||||
|
||||
# other random folders
|
||||
/htmlReport
|
||||
/.kotlin/errors
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Server" type="JarApplication">
|
||||
<option name="JAR_PATH" value="$PROJECT_DIR$/run/server.jar" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-nogui" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/run" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
### Bedrock issue
|
||||
For server using geyser, bedrock player cannot use custom "recipes" in the anvil.
|
||||
This is cannot be fixed on geyser or my side.
|
||||
|
||||
### Plugin Compatibility
|
||||
Here is various plugins that had issues with CustomAnvil
|
||||
where efforts was made for compatibility and should be working right:
|
||||
|
||||
some if not all of them are cool ! I recommend checking them out !
|
||||
|
||||
## Supported By CustomAnvil
|
||||
These plugins have compatibility handled by custom anvil. seek help on custom anvil and do not bother these developers
|
||||
|
||||
#### Enchantment Plugins
|
||||
- [ExcellentEnchants](https://www.spigotmc.org/resources/excellentenchants-%E2%AD%90-75-vanilla-like-enchantments.61693/) by NightExpress:
|
||||
Use ExcellentEnchants item type \
|
||||
Also use ExcellentEnchant max enchant limit
|
||||
|
||||
- [EcoEnchant](https://www.spigotmc.org/resources/ecoenchants-%E2%AD%95-250-enchantments-%E2%9C%85-create-custom-enchants-%E2%9C%A8-essentials-cmi-support.79573/) by Auxilor:
|
||||
Need to use /anvilconfigreload or a server restart to add newly added enchantment.
|
||||
Use EcoEnchant restriction system but new restriction can be added in custom anvil
|
||||
|
||||
- [Enchantment²](https://www.spigotmc.org/resources/enchants-squared-the-enchantsplus-rewrite-custom-enchantments-that-act-like-vanilla-ones.86747/) by Athlaeos:
|
||||
Support by Custom Anvil but still experimental. Automatic configuration. Plugin is not actively developed anymore
|
||||
|
||||
- [SuperEnchants](https://modrinth.com/plugin/superenchants) by Aznos:
|
||||
Use SuperEnchant restrictions system but new restriction can be added in custom anvil
|
||||
|
||||
|
||||
#### Custom Items Plugins
|
||||
Custom Items support is considered unstable. If you find issue please report it !
|
||||
|
||||
- [EcoItem](https://www.spigotmc.org/resources/30-sale%E2%8F%B3-ecoitems-%E2%AD%95-create-custom-items-%E2%9C%85-weapons-armors-tools-charms-%E2%9C%A8-item-levels-rarities.94601/) by Exanthiax:
|
||||
May have some issue. but should partially work I hope
|
||||
|
||||
- [ItemAdder](https://www.spigotmc.org/resources/%E2%9C%A8itemsadder%E2%AD%90emotes-mobs-items-armors-hud-gui-emojis-blocks-wings-hats-liquids.73355/) by LoneDev:
|
||||
Need to fix unit item not working completly correctly as in can't have twice same base item
|
||||
|
||||
#### Anvil Mechanics Plugins
|
||||
- [Disenchantment](https://www.spigotmc.org/resources/disenchantment-1-21-1-1-20-6-new-book-splitting-mechanics.110741/) by H7KZ
|
||||
Partially use Custom Anvil maximum XP settings (>= 6.1.5)
|
||||
|
||||
- [HavenBags](https://www.spigotmc.org/resources/havenbags-shulker-like-player-bound-bags-1-17-1-21-4.110420/) by hyperdefined
|
||||
For bag upgrade and skin via anvil. (version >= 1.31.0)
|
||||
|
||||
- [AxPlayerWarp](https://modrinth.com/project/QDJHDKvi) by ArtillexStudios
|
||||
For its anvil inventory usage
|
||||
|
||||
- [ToolsStats](https://modrinth.com/project/oBZj9E15) by Valorless
|
||||
For token application using anvil
|
||||
|
||||
### Known Partially Incompatible
|
||||
- [UberEnchant](https://modrinth.com/plugin/uberenchant) by coltonj96
|
||||
Anvil handling as they are doing something similar to CustomAnvil.
|
||||
It is by no mean there faults and I recommend checking them out especially if custom anvil do not work for your use case !
|
||||
|
||||
- [AdvencedEnchantments](https://ae.advancedplugins.net/) by Advanced Plugins
|
||||
Paid plugin I do not own as I did not get commissioned for support.
|
||||
may be able to use api but cannot test on my side
|
||||
|
||||
If you like Custom Anvil to support a specific plugin (custom enchant or anvil mechanic).
|
||||
You can ask, but please note implementing compatibility will be considered
|
||||
as low priority as I work for the plugin as an hobby on my free time for free.
|
||||
34
CREDITS.md
34
CREDITS.md
|
|
@ -1,34 +0,0 @@
|
|||
Thanks **DelilahEve** for making [Unsafe Enchants](https://github.com/DelilahEve/UnsafeEnchants). \
|
||||
CustomAnvil was initially a fork of Unsafe Enchants where I wanted to add more and more and here we are now !
|
||||
|
||||
Thanks for all the contributors of bukkit, spigot, the paper team and the adventure API developers \
|
||||
Thanks JetBrain for making IntelliJ
|
||||
|
||||
### Dependencies
|
||||
These dependencies (or a modified version of) are used by custom anvil
|
||||
- [IF](https://github.com/stefvanschie/IF) an inventory framework by stefvanschie
|
||||
- [Mockbukkit](https://github.com/MockBukkit/MockBukkit) for unit testing
|
||||
- [CentralPortalPlus](https://github.com/lalakii/central-portal-plus) by lalakii
|
||||
- [test-summary-action](https://github.com/jeantessier/test-summary-action) by jeantessier
|
||||
- [modrinth-publish](https://github.com/cloudnode-pro/modrinth-publish) by Zefir
|
||||
- [discord-webhook](https://github.com/tsickert/discord-webhook) by tsickert
|
||||
- Thanks [bstats](https://bstats.org/) for keeping me motivated
|
||||
- And [FastStats](https://faststats.dev/) alternative to bstats in beta test
|
||||
- [ModrinthUpdateChecker](https://github.com/Clickism/ModrinthUpdateChecker) by Clickism and thanks to the modrinth team
|
||||
|
||||
### Compatibility
|
||||
Thanks to all the cool creator making the minecraft plugin's ecosystem works ! \
|
||||
See [Compatibility list](https://github.com/alexcrea/CustomAnvil/blob/v1.x.x/COMPATIBILITY.md) for details
|
||||
|
||||
but especially, Big Thanks for H7KZ maker of [Disenchantment](https://github.com/H7KZ/Disenchantment)
|
||||
|
||||
### Special Thanks
|
||||
|
||||
Thanks for all the users trying my plugin for these niche use cases
|
||||
, reporting issues and giving ideas !
|
||||
|
||||
Thanks coltonj96 for [UberEnchant](https://modrinth.com/plugin/uberenchant).
|
||||
we may be incompatible with the anvil, but I do think it is a good alternative ! \
|
||||
I wish one day to work on cross compatibiltiy \
|
||||
* If custom anvil do not work well for you or your use case give it a try ! *
|
||||
|
||||
96
README.md
96
README.md
|
|
@ -1,11 +1,18 @@
|
|||
# Custom Anvil
|
||||
|
||||
**Custom Anvil** is a plugin that allows server administrators to customize every aspect of the anvil's mechanics.
|
||||
It is expected to work on 1.18 to 1.21.7 minecraft servers running spigot or paper.
|
||||
(the plugin support of 1.16.5 to 1.17.1 is experimental and may encounter issues)
|
||||
|
||||
**Custom Anvil** was previously named **Unsafe Enchants+**.
|
||||
It was renamed because it now affects every anvil aspect and not only unsafe enchants\
|
||||
**Custom Anvil** is based on [Unsafe Enchants](https://github.com/DelilahEve/UnsafeEnchants) by DelilahEve.
|
||||
|
||||
### Download Locations:
|
||||
|
||||
the plugin can be downloaded on
|
||||
[Modrinth](https://modrinth.com/plugin/customanvil),
|
||||
[Spigot](https://www.spigotmc.org/resources/custom-anvil.114884),
|
||||
[modrinth](https://modrinth.com/plugin/customanvil),
|
||||
[Hangar](https://hangar.papermc.io/alexcrea/CustomAnvil)
|
||||
or here [on GitHub](https://github.com/alexcrea/CustomAnvil/releases/latest)
|
||||
|
||||
|
|
@ -14,7 +21,7 @@ the plugin can be downloaded on
|
|||
- Vanilla like default configuration.
|
||||
- Custom enchantment level limit.
|
||||
- Custom anvil recipes.
|
||||
- Custom enchant restrictions (allows unsafe enchantment only for a group of item or create new restriction).
|
||||
- Custom enchant restrictions (allow unsafe enchantment only for a group of item or create new restriction).
|
||||
- Custom items of unit repairs (repair damaged with unit of "material", for example the repair of diamond sword by diamonds).
|
||||
- Custom XP cost for every aspect of the anvil.
|
||||
- Permissions to bypass level limit or enchantment restriction.
|
||||
|
|
@ -23,63 +30,75 @@ the plugin can be downloaded on
|
|||
- Gui to configure the plugin in game.
|
||||
- Support use of color code, hexadecimal color and minimessage for color/decoration
|
||||
- (Experimental) Folia support (gui do not work)
|
||||
- (Experimental) Dialog rename (allows longer rename)
|
||||
- (Experimental) Anvil with monetary cost (using vault) (require dialog rename)
|
||||
|
||||
And more !
|
||||
|
||||
---
|
||||
### Permissions:
|
||||
Note that for most of them you also need to enable feature and in most case enable use of permission for the specfic feature (indicated with `(toggleable)`)
|
||||
```yml
|
||||
# Generic and bypass permissions
|
||||
ca.affected: Player with this permission will be affected by the plugin
|
||||
ca.bypass.fuse: Allow player to combine every enchantments to every item (no custom limit)
|
||||
ca.bypass.level: Allow player to bypass every level limit (no custom limit)
|
||||
|
||||
# Command permissions
|
||||
ca.command.reload: Allow administrator to reload the plugin's configs
|
||||
ca.command.diagnostic: Allow adminastator to diagnistic some simple problem with the plugin
|
||||
ca.config.edit: Allow administrator to edit the plugin's config in game
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Bellow permissions also require some config change to allow usage of features
|
||||
# Usage of these permission is toggleable in basic config gui or config.yml
|
||||
# -----------------------------------------------------------------------------
|
||||
# usage of these permission is toggleable in basic config gui or config.yml
|
||||
|
||||
# Permissions related to use of color and minimessage
|
||||
ca.color.code: Allow player to use color code on rename if enabled (toggleable)
|
||||
ca.color.code.[thecode] (for example ca.color.code.a): Allows usage of only certain color code (toggleable)
|
||||
ca.color.hex: Allow player to use hexadecimal color on rename if enabled (toggleable)
|
||||
ca.rename.minimessage: Allow player to use minimessage formating on rename if enabled (toggleable)
|
||||
ca.rename.minimessage: Allow player to use minimessage formating on rename if enabled (toggleable) (only legacy compatible at the time)
|
||||
|
||||
# Permissions related to edition of the lore
|
||||
ca.lore_edit.book: Allow player to edit lore via book and quil if enabled (toggleable)
|
||||
ca.lore_edit.paper: Allow player to edit lore via paper if enabled (toggleable)
|
||||
|
||||
# Others
|
||||
ca.rename.dialog: Allow player to use the rename dialog (toggleable)
|
||||
```
|
||||
|
||||
### Commands
|
||||
|
||||
run `/customanvil help` to get information about available commands \
|
||||
this only show subcommands you have permission for
|
||||
|
||||
```yml
|
||||
anvilconfigreload or carl: Reload every config of this plugin
|
||||
customanvilconfig or configanvil: open a menu for administrator to edit plugin's config in game
|
||||
```
|
||||
### Supported Plugins
|
||||
See the [Compatibility list](https://github.com/alexcrea/CustomAnvil/blob/v1.x.x/COMPATIBILITY.md)
|
||||
Custom Anvil can be compatible with some custom enchantments and anvil mechanics plugins.
|
||||
|
||||
Here is a list of supported custom enchantment plugins with support status:
|
||||
- [Enchantment²](https://www.spigotmc.org/resources/enchants-squared-the-enchantsplus-rewrite-custom-enchantments-that-act-like-vanilla-ones.86747/):
|
||||
Support by Custom Anvil but still experimental. Automatic configuration.
|
||||
|
||||
- [EcoEnchant](https://www.spigotmc.org/resources/ecoenchants-%E2%AD%95-250-enchantments-%E2%9C%85-create-custom-enchants-%E2%9C%A8-essentials-cmi-support.79573/):
|
||||
Support by Custom Anvil but still experimental. Need to use /anvilconfigreload or a server restart to add newly added enchantment.
|
||||
Use EcoEnchant restriction system by default.
|
||||
|
||||
- [ExcellentEnchants](https://www.spigotmc.org/resources/excellentenchants-%E2%AD%90-75-vanilla-like-enchantments.61693/):
|
||||
Support by Custom Anvil but still experimental. Use ExcellentEnchants item type.
|
||||
|
||||
- [Superenchants](https://modrinth.com/plugin/superenchants)
|
||||
support by Superenchants. Use CustomAnvil to combine enchantment in anvil in survival.
|
||||
|
||||
Here is a list of supported anvil mechanic plugins with support status:
|
||||
- [Disenchantment](https://www.spigotmc.org/resources/disenchantment-1-21-1-1-20-6-new-book-splitting-mechanics.110741/)
|
||||
support by Custom Anvil but still experimental. Mostly use Custom Anvil basic XP settings. (version >= 6.1.5)
|
||||
|
||||
- [HavenBags](https://www.spigotmc.org/resources/havenbags-shulker-like-player-bound-bags-1-17-1-21-4.110420/)
|
||||
support by Custom Anvil. Not really enchantment related but CustomAnvil should not impact bag upgrade and skin via anvil. (version >= 1.31.0)
|
||||
|
||||
If you like Custom Anvil to support a specific plugin (custom enchant or anvil mechanic).
|
||||
You can ask, but please note implementing compatibility will be considered
|
||||
as low priority as I work for the plugin on my free time for free.
|
||||
|
||||
### Overriding Too Expensive
|
||||
|
||||
One of the configurations allow displaying price about 40 and removing Too Expensive. \
|
||||
By how the minecraft client work: price above 40 can only be displayed green, even if the player does not own enough experience level.
|
||||
spigot version 1.18 to 1.21.11 do not need any ProtocoLib dependency. (26.1.0 or above requires it) \
|
||||
Minecraft version 1.18 to latest marked as supported do not need any ProtocoLib dependency. \
|
||||
Any recent paper version also are supported for this feature.
|
||||
But you should wait for update for new version containing new enchantable item or new enchantments if any of this got added.
|
||||
Else it is, likely, fine to use the current version you are ussing on a new paper version
|
||||
But you should wait for update for new version containing new enchantable item or new enchantments.
|
||||
Other version need ProtocoLib enabled on your server for this feature. \
|
||||
You can also wait for an update of the plugin to support a newer version.
|
||||
|
||||
Please note that 1.16.5 to 1.17.1 are not officially supported. Run at your own risk.
|
||||
|
||||
### For custom enchantment plugin developers
|
||||
For information about the API, please refer to [the Wiki](https://github.com/alexcrea/CustomAnvil/wiki) \
|
||||
(Please note that the wiki is currently incomplete)
|
||||
(Please note that the wiki is currently incomplete)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -87,25 +106,12 @@ For information about the API, please refer to [the Wiki](https://github.com/ale
|
|||
see [Here](https://github.com/alexcrea/CustomAnvil/tree/master/defaultconfigs)
|
||||
|
||||
---
|
||||
### Metric And Telemetry
|
||||
Custom anvil [use bstat](https://bstats.org/plugin/bukkit/Unsafe%20Enchants%20Plus/20923)
|
||||
and [faststats](https://faststats.dev/project/customanvil/minecraft-plugin) for metric and error reporting.
|
||||
|
||||
You can select specific telemetry or disable all in config.yml. \
|
||||
You can also [disable bstat](https://bstats.org/getting-started) and [faststats](https://faststats.dev/info) in their /plugin folder if you like too.
|
||||
|
||||
faststats is in beta testing please report me or them any error you encounter
|
||||
|
||||
### Credits and Thanks
|
||||
Credits and thanks can be seen [here](https://github.com/alexcrea/CustomAnvil/blob/v1.x.x/CREDITS.md)
|
||||
Custom anvil [use bstat](https://bstats.org/plugin/bukkit/Unsafe%20Enchants%20Plus/20923) for metric. You can [disable it](https://bstats.org/getting-started) if you like.
|
||||
|
||||
### Planned:
|
||||
- Better Folia support (make gui work. fix some dirty handled parts)
|
||||
- Get restriction on unknown enchantments (planned for V2)
|
||||
- Get restriction on unknown enchantments
|
||||
- More features for custom anvil craft
|
||||
|
||||
### Known issue:
|
||||
Most unknown registered enchantments (by unsupported custom enchantment plugin & datapacks) will not have restriction by default. Planned but no eta.
|
||||
|
||||
### Do you need help with the plugin, or have any issue or suggestion?
|
||||
You can ask on the discussion page, create a [GitHub issue](https://github.com/alexcrea/CustomAnvil/issues) or join my [discord](https://discord.gg/KHUNsUfRYJ)
|
||||
|
|
|
|||
214
build.gradle.kts
214
build.gradle.kts
|
|
@ -2,13 +2,10 @@ import cn.lalaki.pub.BaseCentralPortalPlusExtension
|
|||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import groovy.util.Node
|
||||
import groovy.util.NodeList
|
||||
import io.papermc.hangarpublishplugin.model.HangarPublication
|
||||
import io.papermc.hangarpublishplugin.model.Platforms
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version "2.3.0"
|
||||
kotlin("jvm") version "2.1.0"
|
||||
java
|
||||
id("org.jetbrains.dokka").version("1.9.20")
|
||||
id("com.gradleup.shadow").version("9.3.0")
|
||||
|
|
@ -18,17 +15,13 @@ plugins {
|
|||
id("cn.lalaki.central").version("1.2.8")
|
||||
// Paper
|
||||
id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" apply false
|
||||
id("io.papermc.hangar-publish-plugin") version "0.1.2"
|
||||
}
|
||||
|
||||
group = "xyz.alexcrea"
|
||||
version = "1.17.5"
|
||||
|
||||
val isDevBuild = System.getenv("SMALL_COMMIT_HASH") != null
|
||||
val isPreRelease = System.getenv("IS_GITHUB_PRERELEASE") == "true"
|
||||
version = "1.15.8"
|
||||
|
||||
val effectiveVersion = "$version" +
|
||||
(if (isDevBuild) "-dev-${System.getenv("SMALL_COMMIT_HASH")!!}" else "")
|
||||
(if (System.getenv("SMALL_COMMIT_HASH") != null) "-dev-${System.getenv("SMALL_COMMIT_HASH")!!}" else "")
|
||||
|
||||
repositories {
|
||||
// EcoEnchants
|
||||
|
|
@ -36,18 +29,6 @@ repositories {
|
|||
|
||||
// ExcellentEnchants
|
||||
maven(url = "https://repo.nightexpressdev.com/releases")
|
||||
|
||||
// ItemsAdder
|
||||
maven(url = "https://maven.devs.beer/")
|
||||
|
||||
// For fast stats
|
||||
maven {
|
||||
name = "thenextlvlReleases"
|
||||
url = uri("https://repo.thenextlvl.net/releases")
|
||||
}
|
||||
|
||||
// For vault unlocked
|
||||
maven { url = uri("https://repo.codemc.io/repository/creatorfromhell/") }
|
||||
}
|
||||
|
||||
val reobfNMS = providers.gradleProperty("subprojects.reobfnms")
|
||||
|
|
@ -57,9 +38,6 @@ dependencies {
|
|||
// Spigot api
|
||||
compileOnly("org.spigotmc:spigot-api:1.18-R0.1-SNAPSHOT")
|
||||
|
||||
// fast stats
|
||||
implementation("dev.faststats.metrics:bukkit:0.27.0")
|
||||
|
||||
// minimessage
|
||||
implementation("net.kyori:adventure-text-minimessage:4.25.0")
|
||||
|
||||
|
|
@ -71,17 +49,13 @@ dependencies {
|
|||
// EnchantsSquaredRewritten
|
||||
compileOnly(files("libs/EnchantsSquared.jar"))
|
||||
|
||||
// EcoEnchants & item
|
||||
compileOnly("com.willfp:libreforge:4.79.0:all")
|
||||
compileOnly("com.willfp:eco:6.74.5")
|
||||
|
||||
// EcoEnchants
|
||||
compileOnly("com.willfp:EcoEnchants:12.11.1")
|
||||
compileOnly("com.willfp:eco:6.74.5")
|
||||
compileOnly(project(":impl:LegacyEcoEnchant"))
|
||||
|
||||
compileOnly("com.willfp:EcoItems:5.66.0")
|
||||
|
||||
// ExcellentEnchants
|
||||
implementation(project(":impl:ExcellentEnchant5_4"))
|
||||
implementation(project(":impl:ExcellentEnchant5_3"))
|
||||
compileOnly("su.nightexpress.excellentenchants:Core:5.1.0") {
|
||||
exclude("org.spigotmc")
|
||||
}
|
||||
|
|
@ -100,15 +74,6 @@ dependencies {
|
|||
// AxPlayerWarps
|
||||
compileOnly(files("libs/AxPlayerWarps-1.10.3.jar"))
|
||||
|
||||
// SuperEnchants
|
||||
compileOnly(files("libs/SuperEnchants-4.6.2-all.jar"))
|
||||
|
||||
// ItemsAdder API
|
||||
compileOnly("dev.lone:api-itemsadder:4.0.10")
|
||||
|
||||
// Vault api
|
||||
compileOnly("net.milkbowl.vault:VaultUnlockedAPI:2.16")
|
||||
|
||||
// Include nms
|
||||
implementation(project(":nms:nms-common"))
|
||||
implementation(project(":nms:nms-paper"))
|
||||
|
|
@ -160,7 +125,7 @@ allprojects {
|
|||
// Set target version
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
sourceCompatibility =
|
||||
"16" // We aim for java 16 for minecraft 1.16.5. even if it not really supported by custom anvil.
|
||||
"16" // We aim for java 16 for minecraft 1.16.5. even if it not really suported by custom anvil.
|
||||
targetCompatibility = "16"
|
||||
|
||||
options.encoding = "UTF-8"
|
||||
|
|
@ -168,29 +133,34 @@ allprojects {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_16)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
tasks {
|
||||
|
||||
fun ShadowJar.configureBaseShadow(suffix: String, libraries: Array<String>) {
|
||||
val processedSuffix = if(suffix.isEmpty()) "" else "-$suffix"
|
||||
val name = "${rootProject.name}-${effectiveVersion}${processedSuffix}.jar"
|
||||
// Online jar (use of libraries)
|
||||
shadowJar {
|
||||
// No suffix for this jar
|
||||
val name = "${rootProject.name}-${effectiveVersion}.jar"
|
||||
archiveFileName.set(name)
|
||||
|
||||
// Shadow necessary dependency
|
||||
relocate("com.github.stefvanschie.inventoryframework", "xyz.alexcrea.cuanvil.inventoryframework")
|
||||
relocate("dev.faststats", "xyz.alexcrea.cuanvil.faststats")
|
||||
// Exclude kotlin std and its annotation
|
||||
exclude("**/kotlin-stdlib*.jar")
|
||||
exclude("**/annotations*.jar")
|
||||
|
||||
// Shadow necessary dependency
|
||||
relocate("com.github.stefvanschie.inventoryframework", "xyz.alexcrea.inventoryframework")
|
||||
|
||||
// Replace version and example fields in plugin.yml
|
||||
filesMatching("plugin.yml") {
|
||||
expand(
|
||||
"version" to effectiveVersion + processedSuffix,
|
||||
"libraries" to libraries.joinToString(transform = { "\"$it\"" }),
|
||||
"version" to effectiveVersion,
|
||||
"libraries" to " \"org.jetbrains.kotlin:kotlin-stdlib:2.1.0\" " +
|
||||
", \"net.kyori:adventure-platform-bukkit:4.4.1\""
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -198,28 +168,36 @@ tasks {
|
|||
dependsOn(processResources)
|
||||
}
|
||||
|
||||
// Online jar (use of libraries)
|
||||
shadowJar {
|
||||
configureBaseShadow("",
|
||||
arrayOf(
|
||||
"org.jetbrains.kotlin:kotlin-stdlib:2.3.0",
|
||||
"net.kyori:adventure-text-minimessage:4.25.0",
|
||||
"net.kyori:adventure-text-serializer-plain:4.25.0",
|
||||
"net.kyori:adventure-text-serializer-legacy:4.25.0",
|
||||
))
|
||||
// Offline jar (include kotlin std in the final jar fine)
|
||||
val offlineJar by // Shadow necessary dependency
|
||||
registering(
|
||||
|
||||
// Exclude kotlin std, annotations and adventure api
|
||||
exclude("*kotlin/**")
|
||||
exclude("**/annotations/**")
|
||||
exclude("net/kyori/**")
|
||||
// Include all project other dependencies
|
||||
ShadowJar
|
||||
|
||||
// Add custom anvil compiled
|
||||
::class, fun ShadowJar.() {
|
||||
val name = "${rootProject.name}-${effectiveVersion}-offline.jar"
|
||||
archiveFileName.set(name)
|
||||
|
||||
// Shadow necessary dependency
|
||||
relocate("com.github.stefvanschie.inventoryframework", "xyz.alexcrea.inventoryframework")
|
||||
|
||||
filesMatching("plugin.yml") {
|
||||
expand(
|
||||
"version" to "$effectiveVersion-offline",
|
||||
"libraries" to ""
|
||||
)
|
||||
}
|
||||
|
||||
val offlineJar by registering(ShadowJar::class) {
|
||||
configureBaseShadow("offline", emptyArray())
|
||||
// Include all project other dependencies
|
||||
from(project.configurations.runtimeClasspath)
|
||||
|
||||
// Add custom anvil compiled
|
||||
from(sourceSets.main.get().output)
|
||||
configurations = listOf(project.configurations.runtimeClasspath.get())
|
||||
}
|
||||
|
||||
dependsOn(processResources)
|
||||
})
|
||||
|
||||
// Make the online and offline jar on build
|
||||
named("build") {
|
||||
|
|
@ -355,101 +333,3 @@ publishing {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// hangar publish
|
||||
|
||||
fun executeGitCommand(vararg command: String): String {
|
||||
val byteOut = ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine = listOf("git", *command)
|
||||
standardOutput = byteOut
|
||||
}
|
||||
return byteOut.toString(Charsets.UTF_8.name()).trim()
|
||||
}
|
||||
|
||||
|
||||
fun latestCommitMessage(): String {
|
||||
return executeGitCommand("log", "-1", "--pretty=%B")
|
||||
}
|
||||
|
||||
fun changelog(isOnline: Boolean): String {
|
||||
var changelog = if(isDevBuild) latestCommitMessage()
|
||||
else System.getenv("RELEASE_CHANGELOG")
|
||||
|
||||
if(!isOnline) {
|
||||
changelog = "This is an offline version of the plugin. \\\n" +
|
||||
"This mean that this plugin libraries are shaded into this plugin \\\n" +
|
||||
"You likely want to use the normal version of this plugin\n\n" + changelog
|
||||
}
|
||||
|
||||
if(changelog == null || changelog.isEmpty()) {
|
||||
changelog = "empty changelog"
|
||||
}
|
||||
|
||||
return changelog
|
||||
}
|
||||
|
||||
hangarPublish {
|
||||
|
||||
fun HangarPublication.configure(isOnline: Boolean, devChannel: String, releaseChannel: String) {
|
||||
var versionName = effectiveVersion
|
||||
if(isPreRelease) versionName+= "-pre"
|
||||
if(!isOnline) versionName+= "-offline"
|
||||
|
||||
version.set(versionName)
|
||||
channel.set(if (isDevBuild || isPreRelease) devChannel else releaseChannel)
|
||||
|
||||
changelog.set(changelog(isOnline))
|
||||
id.set("CustomAnvil")
|
||||
apiKey.set(System.getenv("HANGAR_API_TOKEN"))
|
||||
|
||||
platforms {
|
||||
register(Platforms.PAPER) {
|
||||
// Set the JAR file to upload
|
||||
var task = if(isOnline) tasks.shadowJar
|
||||
else tasks.named<ShadowJar>("offlineJar")
|
||||
|
||||
jar.set(task.flatMap { it.archiveFile })
|
||||
|
||||
// Set platform versions from gradle.properties file
|
||||
val versions: List<String> = (property("paperVersion") as String)
|
||||
.split(",")
|
||||
.map { it.trim() }
|
||||
platformVersions.set(versions)
|
||||
|
||||
dependencies {
|
||||
hangar("ProtocolLib") {
|
||||
required.set(false)
|
||||
}
|
||||
url("Disenchantment", "https://modrinth.com/plugin/disenchantment") {
|
||||
required.set(false)
|
||||
}
|
||||
url("ToolStats", "https://modrinth.com/plugin/toolstats") {
|
||||
required.set(false)
|
||||
}
|
||||
url("HavenBags", "https://www.spigotmc.org/resources/havenbags-shulker-like-player-bound-bags-1-17-1-21-4.110420/") {
|
||||
required.set(false)
|
||||
}
|
||||
url("EcoEnchants", "https://www.spigotmc.org/resources/ecoenchants-%E2%AD%95-250-enchantments-%E2%9C%85-create-custom-enchants-%E2%9C%A8-essentials-cmi-support.79573/") {
|
||||
required.set(false)
|
||||
}
|
||||
hangar("EnchantsSquared") {
|
||||
required.set(false)
|
||||
}
|
||||
url("ExcellentEnchants", "https://www.spigotmc.org/resources/excellentenchants-%E2%AD%90-75-vanilla-like-enchantments.61693/") {
|
||||
required.set(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
publications.register("plugin") {
|
||||
configure(true, "DevSnapshot", "Release")
|
||||
}
|
||||
|
||||
publications.register("offline") {
|
||||
configure(false, "OfflineSnapshot", "OfflineRelease")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,19 +3,6 @@
|
|||
# You can still manually edit here if you like to. but if you do, don't forget to /anvilconfigreload after you changes !
|
||||
#
|
||||
|
||||
# What service of metric should custom anvil use
|
||||
# Custom anvil collect generic information like server minecraft version, type, etc...
|
||||
# It can also collect error information if error is happening (currently faststats only)
|
||||
# It can also be disabled
|
||||
# Please refer to README for public metric link
|
||||
# Possible options: auto, bstat, faststats, disabled (auto by default)
|
||||
metric_type: auto
|
||||
|
||||
# Allow to report errors made caused by this plugin (only for faststats)
|
||||
# This allows me to fix potentials issue that I'm not aware of
|
||||
# Accept true or false (true by default)
|
||||
metric_collect_errors: true
|
||||
|
||||
# All anvil cost will be capped to limit_repair_value if enabled.
|
||||
#
|
||||
# In other words:
|
||||
|
|
@ -77,18 +64,6 @@ allow_color_code: false
|
|||
allow_hexadecimal_color: false
|
||||
allow_minimessage: false
|
||||
|
||||
# This enables restricting color code for player having specific permission
|
||||
# It requires allow_color_code enabled for... obvious reasons
|
||||
#
|
||||
# For example: if player want to use "&aHello" it will be required that the player has
|
||||
# the permission "ca.color.code.a" as he used the color code "a"
|
||||
# In general permission to give to the player is "ca.color.code.[code]"
|
||||
# where [code] is the color code you wish to allow the player
|
||||
#
|
||||
# It is kinda of useless when minimessage is supported as players would be able to bypass
|
||||
# that using the equivalent minimessage tag
|
||||
per_color_code_permission: false
|
||||
|
||||
# Toggle if color should only be applicable if the player a certain permission.
|
||||
#
|
||||
# permission are "ca.color.code" for use of color code and "ca.color.hex" for use of hexadecimal color.
|
||||
|
|
@ -99,23 +74,10 @@ permission_needed_for_color: true
|
|||
# Valid values include 0 to 1000.
|
||||
use_of_color_cost: 0
|
||||
|
||||
# Dialogue rename menu make use of dialog menu to allow bigger rename
|
||||
# You can also change the maximum size and set it to -1 or less for maximum
|
||||
# Default limit to apply to any enchants missing from enchant_limits
|
||||
#
|
||||
# This feature only work on paper 1.21.7 or later
|
||||
#
|
||||
# At the moment only english is available for this menu... sorry !
|
||||
#
|
||||
# CustomAnvil use "ca.rename.dialog" when permission
|
||||
enable_dialog_rename: false
|
||||
dialog_rename_max_size: 256
|
||||
permission_needed_for_dialog_rename: false
|
||||
|
||||
# This allows custom anvil to not "guess" the text used for rename but store it in the item
|
||||
# It will make item stackable only and only if it had used the same rename text
|
||||
#
|
||||
# For practical reason. this only work when dialog rename is enabled
|
||||
dialog_rename_keep_user_text: true
|
||||
# Valid values include 1 to 1000
|
||||
default_limit: 5
|
||||
|
||||
# Override limits for specific enchants
|
||||
#
|
||||
|
|
@ -123,8 +85,7 @@ dialog_rename_keep_user_text: true
|
|||
#
|
||||
# Overrides provided default from aqua_affinity to depth_strider won't change effect with extra levels
|
||||
#
|
||||
# Valid range of 0 - 255 for each enchantment
|
||||
# -1 mean keep default
|
||||
# Valid range of 1 - 255 for each enchantment
|
||||
enchant_limits:
|
||||
minecraft:aqua_affinity: 1
|
||||
minecraft:binding_curse: 1
|
||||
|
|
@ -306,7 +267,7 @@ enchant_values:
|
|||
# Even if disable-merge-over of unbreaking is set to 2
|
||||
# -1 mean enchantment merge for this enchantment is not disabled. default to -1 if absent.
|
||||
disable-merge-over:
|
||||
# Sharpness is set to -1. it equivalent to it not being set to anything (and work as vanilla on default configuration)
|
||||
# Sharpness is set to -1. it equivalent to it not being set to anything (and work as vanilla)
|
||||
minecraft:sharpness: -1
|
||||
# If uncommented. 2 unbreaking II book would not give an unbreaking III book. but unbreaking III book can still be applied
|
||||
#minecraft:unbreaking: 2
|
||||
|
|
@ -430,37 +391,16 @@ lore_edit:
|
|||
allow_hexadecimal_color: false
|
||||
allow_minimessage: true
|
||||
|
||||
# Allow to replace the xp cost by a monetary cost
|
||||
# If enabled it will not be bound to the experience level limits
|
||||
#
|
||||
# It also requires to enable dialog rename (set "enable_dialog_rename: false" a bit higher)
|
||||
# If dialog rename permission is enabled and player do not have the permission merge will fall back to vanilla xp cost
|
||||
#
|
||||
# If you are using custom craft I recommend using Linear Xp Cost with Exact Linear Xp as normal Xp Cost will act "weird"
|
||||
# But Linear Xp will act as 1$ time global multiplier. In other word: like you expect
|
||||
#
|
||||
# As this feature require dialog rename, it can only be enabled starting with paper 1.21.6 and later
|
||||
monetary_cost:
|
||||
enabled: false
|
||||
# If using vault unlocked this allow to specify what currency should be used for anvil usage
|
||||
# default being the default currency
|
||||
currency: default
|
||||
# multiply the anvil cost by a value to allow to have price a big bigger than like 40
|
||||
multipliers:
|
||||
# global multipliers. all usage type will be multiplied by this value
|
||||
global: 1.0
|
||||
# usage specific type. it will only apply for specific xp "reason"
|
||||
enchantment: 1.0 # related to enchantments level
|
||||
repair: 1.0 # for repairing via unit repair (per unit)
|
||||
rename: 1.0 # for renaming the item
|
||||
lore_edit: 1.0 # for changing the lore of the item (only if lore edit is enabled)
|
||||
work_penalty: 1.0 # for work penalty (aka use penalty)
|
||||
recipe: 1.0 # for custom anvil recipe cost
|
||||
|
||||
# Whether to show debug logging
|
||||
debug_log: false
|
||||
|
||||
# Whether to show verbose debug logging
|
||||
debug_log_verbose: false
|
||||
|
||||
# In case something when wrong with CustomAnvil packet manager.
|
||||
# If you see "missing class exception" or similar you may test this.
|
||||
# If enabled and Protocolib absent or disabled "Replace to expensive" will not work.
|
||||
# ProtocoLib may also be used if the server is in an "unsupported" version even if this option is disabled.
|
||||
force_protocolib: false
|
||||
|
||||
configVersion: 1.11.0
|
||||
|
|
|
|||
|
|
@ -3,19 +3,6 @@
|
|||
# You can still manually edit here if you like to. but if you do, don't forget to /anvilconfigreload after you changes !
|
||||
#
|
||||
|
||||
# What service of metric should custom anvil use
|
||||
# Custom anvil collect generic information like server minecraft version, type, etc...
|
||||
# It can also collect error information if error is happening (currently faststats only)
|
||||
# It can also be disabled
|
||||
# Please refer to README for public metric link
|
||||
# Possible options: auto, bstat, faststats, disabled (auto by default)
|
||||
metric_type: auto
|
||||
|
||||
# Allow to report errors made caused by this plugin (only for faststats)
|
||||
# This allows me to fix potentials issue that I'm not aware of
|
||||
# Accept true or false (true by default)
|
||||
metric_collect_errors: true
|
||||
|
||||
# All anvil cost will be capped to limit_repair_value if enabled.
|
||||
#
|
||||
# In other words:
|
||||
|
|
@ -79,18 +66,6 @@ allow_color_code: false
|
|||
allow_hexadecimal_color: false
|
||||
allow_minimessage: false
|
||||
|
||||
# This enables restricting color code for player having specific permission
|
||||
# It requires allow_color_code enabled for... obvious reasons
|
||||
#
|
||||
# For example: if player want to use "&aHello" it will be required that the player has
|
||||
# the permission "ca.color.code.a" as he used the color code "a"
|
||||
# In general permission to give to the player is "ca.color.code.[code]"
|
||||
# where [code] is the color code you wish to allow the player
|
||||
#
|
||||
# It is kinda of useless when minimessage is supported as players would be able to bypass
|
||||
# that using the equivalent minimessage tag
|
||||
per_color_code_permission: false
|
||||
|
||||
# Toggle if color should only be applicable if the player a certain permission.
|
||||
#
|
||||
# permission are "ca.color.code" for use of color code and "ca.color.hex" for use of hexadecimal color.
|
||||
|
|
@ -101,23 +76,10 @@ permission_needed_for_color: true
|
|||
# Valid values include 0 to 1000.
|
||||
use_of_color_cost: 0
|
||||
|
||||
# Dialogue rename menu make use of dialog menu to allow bigger rename
|
||||
# You can also change the maximum size and set it to -1 or less for maximum
|
||||
# Default limit to apply to any enchants missing from enchant_limits
|
||||
#
|
||||
# This feature only work on paper 1.21.7 or later
|
||||
#
|
||||
# At the moment only english is available for this menu... sorry !
|
||||
#
|
||||
# CustomAnvil use "ca.rename.dialog" when permission
|
||||
enable_dialog_rename: false
|
||||
dialog_rename_max_size: 256
|
||||
permission_needed_for_dialog_rename: false
|
||||
|
||||
# This allows custom anvil to not "guess" the text used for rename but store it in the item
|
||||
# It will make item stackable only and only if it had used the same rename text
|
||||
#
|
||||
# For practical reason. this only work when dialog rename is enabled
|
||||
dialog_rename_keep_user_text: true
|
||||
# Valid values include 1 to 1000
|
||||
default_limit: 5
|
||||
|
||||
# Override limits for specific enchants
|
||||
#
|
||||
|
|
@ -125,8 +87,7 @@ dialog_rename_keep_user_text: true
|
|||
#
|
||||
# Overrides provided default from aqua_affinity to depth_strider won't change effect with extra levels
|
||||
#
|
||||
# Valid range of 0 - 255 for each enchantment
|
||||
# -1 mean keep default
|
||||
# Valid range of 1 - 255 for each enchantment
|
||||
enchant_limits:
|
||||
minecraft:aqua_affinity: 1
|
||||
minecraft:binding_curse: 1
|
||||
|
|
@ -324,7 +285,7 @@ enchant_values:
|
|||
# Even if disable-merge-over of unbreaking is set to 2
|
||||
# -1 mean enchantment merge for this enchantment is not disabled. default to -1 if absent.
|
||||
disable-merge-over:
|
||||
# Sharpness is set to -1. it equivalent to it not being set to anything (and work as vanilla on default configuration)
|
||||
# Sharpness is set to -1. it equivalent to it not being set to anything (and work as vanilla)
|
||||
minecraft:sharpness: -1
|
||||
# If uncommented. 2 unbreaking II book would not give an unbreaking III book. but unbreaking III book can still be applied
|
||||
# minecraft:unbreaking: 2
|
||||
|
|
@ -450,38 +411,17 @@ lore_edit:
|
|||
allow_hexadecimal_color: false
|
||||
allow_minimessage: true
|
||||
|
||||
# Allow to replace the xp cost by a monetary cost
|
||||
# If enabled it will not be bound to the experience level limits
|
||||
#
|
||||
# It also requires to enable dialog rename (set "enable_dialog_rename: false" a bit higher)
|
||||
# If dialog rename permission is enabled and player do not have the permission merge will fall back to vanilla xp cost
|
||||
#
|
||||
# If you are using custom craft I recommend using Linear Xp Cost with Exact Linear Xp as normal Xp Cost will act "weird"
|
||||
# But Linear Xp will act as 1$ time global multiplier. In other word: like you expect
|
||||
#
|
||||
# As this feature require dialog rename, it can only be enabled starting with paper 1.21.6 and later
|
||||
monetary_cost:
|
||||
enabled: false
|
||||
# If using vault unlocked this allow to specify what currency should be used for anvil usage
|
||||
# default being the default currency
|
||||
currency: default
|
||||
# multiply the anvil cost by a value to allow to have price a big bigger than like 40
|
||||
multipliers:
|
||||
# global multipliers. all usage type will be multiplied by this value
|
||||
global: 1.0
|
||||
# usage specific type. it will only apply for specific xp "reason"
|
||||
enchantment: 1.0 # related to enchantments level
|
||||
repair: 1.0 # for repairing via unit repair (per unit)
|
||||
rename: 1.0 # for renaming the item
|
||||
lore_edit: 1.0 # for changing the lore of the item (only if lore edit is enabled)
|
||||
work_penalty: 1.0 # for work penalty (aka use penalty)
|
||||
recipe: 1.0 # for custom anvil recipe cost
|
||||
|
||||
# Whether to show debug logging
|
||||
debug_log: false
|
||||
|
||||
# Whether to show verbose debug logging
|
||||
debug_log_verbose: false
|
||||
|
||||
# In case something when wrong with CustomAnvil packet manager.
|
||||
# If you see "missing class exception" or similar you may test this.
|
||||
# If enabled and Protocolib absent or disabled "Replace to expensive" will not work.
|
||||
# ProtocoLib may also be used if the server is in an "unsupported" version even if this option is disabled.
|
||||
force_protocolib: false
|
||||
|
||||
configVersion: 1.15.5
|
||||
lowMinecraftVersion: 1.21.11
|
||||
|
|
|
|||
|
|
@ -3,19 +3,6 @@
|
|||
# You can still manually edit here if you like to. but if you do, don't forget to /anvilconfigreload after you changes !
|
||||
#
|
||||
|
||||
# What service of metric should custom anvil use
|
||||
# Custom anvil collect generic information like server minecraft version, type, etc...
|
||||
# It can also collect error information if error is happening (currently faststats only)
|
||||
# It can also be disabled
|
||||
# Please refer to README for public metric link
|
||||
# Possible options: auto, bstat, faststats, disabled (auto by default)
|
||||
metric_type: auto
|
||||
|
||||
# Allow to report errors made caused by this plugin (only for faststats)
|
||||
# This allows me to fix potentials issue that I'm not aware of
|
||||
# Accept true or false (true by default)
|
||||
metric_collect_errors: true
|
||||
|
||||
# All anvil cost will be capped to limit_repair_value if enabled.
|
||||
#
|
||||
# In other words:
|
||||
|
|
@ -77,18 +64,6 @@ allow_color_code: false
|
|||
allow_hexadecimal_color: false
|
||||
allow_minimessage: false
|
||||
|
||||
# This enables restricting color code for player having specific permission
|
||||
# It requires allow_color_code enabled for... obvious reasons
|
||||
#
|
||||
# For example: if player want to use "&aHello" it will be required that the player has
|
||||
# the permission "ca.color.code.a" as he used the color code "a"
|
||||
# In general permission to give to the player is "ca.color.code.[code]"
|
||||
# where [code] is the color code you wish to allow the player
|
||||
#
|
||||
# It is kinda of useless when minimessage is supported as players would be able to bypass
|
||||
# that using the equivalent minimessage tag
|
||||
per_color_code_permission: false
|
||||
|
||||
# Toggle if color should only be applicable if the player a certain permission.
|
||||
#
|
||||
# permission are "ca.color.code" for use of color code and "ca.color.hex" for use of hexadecimal color.
|
||||
|
|
@ -99,23 +74,10 @@ permission_needed_for_color: true
|
|||
# Valid values include 0 to 1000.
|
||||
use_of_color_cost: 0
|
||||
|
||||
# Dialogue rename menu make use of dialog menu to allow bigger rename
|
||||
# You can also change the maximum size and set it to -1 or less for maximum
|
||||
# Default limit to apply to any enchants missing from enchant_limits
|
||||
#
|
||||
# This feature only work on paper 1.21.7 or later
|
||||
#
|
||||
# At the moment only english is available for this menu... sorry !
|
||||
#
|
||||
# CustomAnvil use "ca.rename.dialog" when permission
|
||||
enable_dialog_rename: false
|
||||
dialog_rename_max_size: 256
|
||||
permission_needed_for_dialog_rename: false
|
||||
|
||||
# This allows custom anvil to not "guess" the text used for rename but store it in the item
|
||||
# It will make item stackable only and only if it had used the same rename text
|
||||
#
|
||||
# For practical reason. this only work when dialog rename is enabled
|
||||
dialog_rename_keep_user_text: true
|
||||
# Valid values include 1 to 1000
|
||||
default_limit: 5
|
||||
|
||||
# Override limits for specific enchants
|
||||
#
|
||||
|
|
@ -123,8 +85,7 @@ dialog_rename_keep_user_text: true
|
|||
#
|
||||
# Overrides provided default from aqua_affinity to depth_strider won't change effect with extra levels
|
||||
#
|
||||
# Valid range of 0 - 255 for each enchantment
|
||||
# -1 mean keep default
|
||||
# Valid range of 1 - 255 for each enchantment
|
||||
enchant_limits:
|
||||
minecraft:aqua_affinity: 1
|
||||
minecraft:binding_curse: 1
|
||||
|
|
@ -318,7 +279,7 @@ enchant_values:
|
|||
# Even if disable-merge-over of unbreaking is set to 2
|
||||
# -1 mean enchantment merge for this enchantment is not disabled. default to -1 if absent.
|
||||
disable-merge-over:
|
||||
# Sharpness is set to -1. it equivalent to it not being set to anything (and work as vanilla on default configuration)
|
||||
# Sharpness is set to -1. it equivalent to it not being set to anything (and work as vanilla)
|
||||
minecraft:sharpness: -1
|
||||
# If uncommented. 2 unbreaking II book would not give an unbreaking III book. but unbreaking III book can still be applied
|
||||
# minecraft:unbreaking: 2
|
||||
|
|
@ -442,38 +403,17 @@ lore_edit:
|
|||
allow_hexadecimal_color: false
|
||||
allow_minimessage: true
|
||||
|
||||
# Allow to replace the xp cost by a monetary cost
|
||||
# If enabled it will not be bound to the experience level limits
|
||||
#
|
||||
# It also requires to enable dialog rename (set "enable_dialog_rename: false" a bit higher)
|
||||
# If dialog rename permission is enabled and player do not have the permission merge will fall back to vanilla xp cost
|
||||
#
|
||||
# If you are using custom craft I recommend using Linear Xp Cost with Exact Linear Xp as normal Xp Cost will act "weird"
|
||||
# But Linear Xp will act as 1$ time global multiplier. In other word: like you expect
|
||||
#
|
||||
# As this feature require dialog rename, it can only be enabled starting with paper 1.21.6 and later
|
||||
monetary_cost:
|
||||
enabled: false
|
||||
# If using vault unlocked this allow to specify what currency should be used for anvil usage
|
||||
# default being the default currency
|
||||
currency: default
|
||||
# multiply the anvil cost by a value to allow to have price a big bigger than like 40
|
||||
multipliers:
|
||||
# global multipliers. all usage type will be multiplied by this value
|
||||
global: 1.0
|
||||
# usage specific type. it will only apply for specific xp "reason"
|
||||
enchantment: 1.0 # related to enchantments level
|
||||
repair: 1.0 # for repairing via unit repair (per unit)
|
||||
rename: 1.0 # for renaming the item
|
||||
lore_edit: 1.0 # for changing the lore of the item (only if lore edit is enabled)
|
||||
work_penalty: 1.0 # for work penalty (aka use penalty)
|
||||
recipe: 1.0 # for custom anvil recipe cost
|
||||
|
||||
# Whether to show debug logging
|
||||
debug_log: false
|
||||
|
||||
# Whether to show verbose debug logging
|
||||
debug_log_verbose: false
|
||||
|
||||
# In case something when wrong with CustomAnvil packet manager.
|
||||
# If you see "missing class exception" or similar you may test this.
|
||||
# If enabled and Protocolib absent or disabled "Replace to expensive" will not work.
|
||||
# ProtocoLib may also be used if the server is in an "unsupported" version even if this option is disabled.
|
||||
force_protocolib: false
|
||||
|
||||
configVersion: 1.11.0
|
||||
lowMinecraftVersion: 1.21.9
|
||||
|
|
|
|||
|
|
@ -3,19 +3,6 @@
|
|||
# You can still manually edit here if you like to. but if you do, don't forget to /anvilconfigreload after you changes !
|
||||
#
|
||||
|
||||
# What service of metric should custom anvil use
|
||||
# Custom anvil collect generic information like server minecraft version, type, etc...
|
||||
# It can also collect error information if error is happening (currently faststats only)
|
||||
# It can also be disabled
|
||||
# Please refer to README for public metric link
|
||||
# Possible options: auto, bstat, faststats, disabled (auto by default)
|
||||
metric_type: auto
|
||||
|
||||
# Allow to report errors made caused by this plugin (only for faststats)
|
||||
# This allows me to fix potentials issue that I'm not aware of
|
||||
# Accept true or false (true by default)
|
||||
metric_collect_errors: true
|
||||
|
||||
# All anvil cost will be capped to limit_repair_value if enabled.
|
||||
#
|
||||
# In other words:
|
||||
|
|
@ -77,18 +64,6 @@ allow_color_code: false
|
|||
allow_hexadecimal_color: false
|
||||
allow_minimessage: false
|
||||
|
||||
# This enables restricting color code for player having specific permission
|
||||
# It requires allow_color_code enabled for... obvious reasons
|
||||
#
|
||||
# For example: if player want to use "&aHello" it will be required that the player has
|
||||
# the permission "ca.color.code.a" as he used the color code "a"
|
||||
# In general permission to give to the player is "ca.color.code.[code]"
|
||||
# where [code] is the color code you wish to allow the player
|
||||
#
|
||||
# It is kinda of useless when minimessage is supported as players would be able to bypass
|
||||
# that using the equivalent minimessage tag
|
||||
per_color_code_permission: false
|
||||
|
||||
# Toggle if color should only be applicable if the player a certain permission.
|
||||
#
|
||||
# permission are "ca.color.code" for use of color code and "ca.color.hex" for use of hexadecimal color.
|
||||
|
|
@ -99,23 +74,10 @@ permission_needed_for_color: true
|
|||
# Valid values include 0 to 1000.
|
||||
use_of_color_cost: 0
|
||||
|
||||
# Dialogue rename menu make use of dialog menu to allow bigger rename
|
||||
# You can also change the maximum size and set it to -1 or less for maximum
|
||||
# Default limit to apply to any enchants missing from enchant_limits
|
||||
#
|
||||
# This feature only work on paper 1.21.7 or later
|
||||
#
|
||||
# At the moment only english is available for this menu... sorry !
|
||||
#
|
||||
# CustomAnvil use "ca.rename.dialog" when permission
|
||||
enable_dialog_rename: false
|
||||
dialog_rename_max_size: 256
|
||||
permission_needed_for_dialog_rename: false
|
||||
|
||||
# This allows custom anvil to not "guess" the text used for rename but store it in the item
|
||||
# It will make item stackable only and only if it had used the same rename text
|
||||
#
|
||||
# For practical reason. this only work when dialog rename is enabled
|
||||
dialog_rename_keep_user_text: true
|
||||
# Valid values include 1 to 1000
|
||||
default_limit: 5
|
||||
|
||||
# Override limits for specific enchants
|
||||
#
|
||||
|
|
@ -123,8 +85,7 @@ dialog_rename_keep_user_text: true
|
|||
#
|
||||
# Overrides provided default from aqua_affinity to depth_strider won't change effect with extra levels
|
||||
#
|
||||
# Valid range of 0 - 255 for each enchantment
|
||||
# -1 mean keep default
|
||||
# Valid range of 1 - 255 for each enchantment
|
||||
enchant_limits:
|
||||
minecraft:aqua_affinity: 1
|
||||
minecraft:binding_curse: 1
|
||||
|
|
@ -306,7 +267,7 @@ enchant_values:
|
|||
# Even if disable-merge-over of unbreaking is set to 2
|
||||
# -1 mean enchantment merge for this enchantment is not disabled. default to -1 if absent.
|
||||
disable-merge-over:
|
||||
# Sharpness is set to -1. it equivalent to it not being set to anything (and work as vanilla on default configuration)
|
||||
# Sharpness is set to -1. it equivalent to it not being set to anything (and work as vanilla)
|
||||
minecraft:sharpness: -1
|
||||
# If uncommented. 2 unbreaking II book would not give an unbreaking III book. but unbreaking III book can still be applied
|
||||
# minecraft:unbreaking: 2
|
||||
|
|
@ -430,37 +391,16 @@ lore_edit:
|
|||
allow_hexadecimal_color: false
|
||||
allow_minimessage: true
|
||||
|
||||
# Allow to replace the xp cost by a monetary cost
|
||||
# If enabled it will not be bound to the experience level limits
|
||||
#
|
||||
# It also requires to enable dialog rename (set "enable_dialog_rename: false" a bit higher)
|
||||
# If dialog rename permission is enabled and player do not have the permission merge will fall back to vanilla xp cost
|
||||
#
|
||||
# If you are using custom craft I recommend using Linear Xp Cost with Exact Linear Xp as normal Xp Cost will act "weird"
|
||||
# But Linear Xp will act as 1$ time global multiplier. In other word: like you expect
|
||||
#
|
||||
# As this feature require dialog rename, it can only be enabled starting with paper 1.21.6 and later
|
||||
monetary_cost:
|
||||
enabled: false
|
||||
# If using vault unlocked this allow to specify what currency should be used for anvil usage
|
||||
# default being the default currency
|
||||
currency: default
|
||||
# multiply the anvil cost by a value to allow to have price a big bigger than like 40
|
||||
multipliers:
|
||||
# global multipliers. all usage type will be multiplied by this value
|
||||
global: 1.0
|
||||
# usage specific type. it will only apply for specific xp "reason"
|
||||
enchantment: 1.0 # related to enchantments level
|
||||
repair: 1.0 # for repairing via unit repair (per unit)
|
||||
rename: 1.0 # for renaming the item
|
||||
lore_edit: 1.0 # for changing the lore of the item (only if lore edit is enabled)
|
||||
work_penalty: 1.0 # for work penalty (aka use penalty)
|
||||
recipe: 1.0 # for custom anvil recipe cost
|
||||
|
||||
# Whether to show debug logging
|
||||
debug_log: false
|
||||
|
||||
# Whether to show verbose debug logging
|
||||
debug_log_verbose: false
|
||||
|
||||
# In case something when wrong with CustomAnvil packet manager.
|
||||
# If you see "missing class exception" or similar you may test this.
|
||||
# If enabled and Protocolib absent or disabled "Replace to expensive" will not work.
|
||||
# ProtocoLib may also be used if the server is in an "unsupported" version even if this option is disabled.
|
||||
force_protocolib: false
|
||||
|
||||
configVersion: 1.11.0
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
### Default Plugin's Configurations
|
||||
From 1.18 to 1.20.6 use [1.18 configurations](https://github.com/alexcrea/CustomAnvil/tree/master/defaultconfigs/1.18) \
|
||||
From 1.21 to 1.21.8 use [1.21 configurations](https://github.com/alexcrea/CustomAnvil/tree/master/defaultconfigs/1.21) \
|
||||
From 1.21.9 to 1.21.10 use [1.21.9 configurations](https://github.com/alexcrea/CustomAnvil/tree/master/defaultconfigs/1.21.9) \
|
||||
From 1.21 to 1.21.8 use [1.21 configurations](https://github.com/alexcrea/CustomAnvil/tree/master/defaultconfigs/1.21)
|
||||
From 1.21.9 to 1.21.10 use [1.21.9 configurations](https://github.com/alexcrea/CustomAnvil/tree/master/defaultconfigs/1.21.9)
|
||||
From 1.21.11 use [1.21.11 configurations](https://github.com/alexcrea/CustomAnvil/tree/master/defaultconfigs/1.21.11)
|
||||
|
|
@ -7,7 +7,3 @@ kotlin.daemon.jvmargs=-Xmx8G
|
|||
|
||||
# list of nms
|
||||
subprojects.reobfnms=v1_17R1,v1_18R1,v1_18R2,v1_19R1,v1_19R2,v1_19R3,v1_20R1,v1_20R2,v1_20R3,v1_20R4,v1_21R1,v1_21R2,v1_21R3,v1_21R4,v1_21R5,v1_21R6,v1_21R7
|
||||
|
||||
# list of version for hangar release
|
||||
paperVersion=1.18-26.2
|
||||
|
||||
|
|
|
|||
21
impl/ExcellentEnchant5_3/build.gradle.kts
Normal file
21
impl/ExcellentEnchant5_3/build.gradle.kts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
group = rootProject.group
|
||||
version = rootProject.version
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version "2.1.0"
|
||||
}
|
||||
|
||||
repositories {
|
||||
// ExcellentEnchants
|
||||
maven(url = "https://repo.nightexpressdev.com/releases")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Spigot api
|
||||
compileOnly("org.spigotmc:spigot-api:1.18-R0.1-SNAPSHOT")
|
||||
|
||||
// Excellent Enchant
|
||||
compileOnly("su.nightexpress.excellentenchants:Core:5.3.0") {
|
||||
exclude("org.spigotmc")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
group = rootProject.group
|
||||
version = rootProject.version
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version "2.3.0"
|
||||
}
|
||||
|
||||
repositories {
|
||||
// ExcellentEnchants
|
||||
maven(url = "https://repo.nightexpressdev.com/releases")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Excellent Enchant
|
||||
compileOnly("su.nightexpress.excellentenchants:Core:5.4.3")
|
||||
compileOnly("su.nightexpress.nightcore:main:2.16.2")
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.dependency.plugins;
|
||||
|
||||
import su.nightexpress.excellentenchants.EnchantsAPI;
|
||||
|
||||
public class ExcellentEnchant5_4EnchantSettings {
|
||||
|
||||
|
||||
public static int anvilLimit() {
|
||||
return EnchantsAPI.getEnchantManager().getSettings().getAnvilEnchantsLimit();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ group = rootProject.group
|
|||
version = rootProject.version
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version "2.3.0"
|
||||
kotlin("jvm") version "2.1.0"
|
||||
}
|
||||
|
||||
// Imitate needed class and method to support legacy version of EcoEnchant
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -29,7 +29,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_16)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package xyz.alexcrea.cuanvil.dependency.gui
|
||||
|
||||
import org.bukkit.inventory.InventoryView
|
||||
|
||||
interface ExternGuiTester {
|
||||
|
||||
fun getContainerClass(view: InventoryView): Class<Any>?
|
||||
|
||||
fun testIfGui(inventory: InventoryView): Boolean {
|
||||
// container class only allow default bukkit craft view or test class
|
||||
|
||||
val clazz = getContainerClass(inventory)
|
||||
return clazz == null
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.dialog
|
||||
|
||||
import org.bukkit.NamespacedKey
|
||||
import org.bukkit.entity.HumanEntity
|
||||
import org.bukkit.event.inventory.PrepareAnvilEvent
|
||||
|
||||
interface AnvilRenameDialog {
|
||||
|
||||
companion object {
|
||||
val PCD_KEEP_RENAME_TEXT_KEY = NamespacedKey.fromString("customanvil:last_rename_text")!!
|
||||
}
|
||||
|
||||
fun canSendDialog(): Boolean
|
||||
|
||||
fun tryShowDialog(player: HumanEntity, event: PrepareAnvilEvent)
|
||||
|
||||
fun closeInventory(player: HumanEntity)
|
||||
|
||||
fun currentText(player: HumanEntity): String?
|
||||
|
||||
fun isOpenFor(player: HumanEntity): Boolean
|
||||
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ dependencies {
|
|||
implementation(project(":nms:nms-common"))
|
||||
|
||||
// Used for nms
|
||||
paperweight.paperDevBundle("1.21.7-R0.1-SNAPSHOT")
|
||||
paperweight.paperDevBundle("1.20.6-R0.1-SNAPSHOT")
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
|
@ -29,7 +29,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_18)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ class PaperPacketManager : PacketManagerBase(), PacketManager {
|
|||
sendedAbilities.mayfly = playerAbilities.mayfly
|
||||
sendedAbilities.instabuild = instantBuild
|
||||
sendedAbilities.mayBuild = playerAbilities.mayBuild
|
||||
sendedAbilities.setFlyingSpeed(playerAbilities.getFlyingSpeed())
|
||||
sendedAbilities.setWalkingSpeed(playerAbilities.getWalkingSpeed())
|
||||
sendedAbilities.flyingSpeed = playerAbilities.flyingSpeed
|
||||
sendedAbilities.walkingSpeed = playerAbilities.walkingSpeed
|
||||
}
|
||||
val packet = ClientboundPlayerAbilitiesPacket(sendedAbilities)
|
||||
nmsPlayer.connection.send(packet)
|
||||
|
|
|
|||
|
|
@ -1,236 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.dialog
|
||||
|
||||
import io.papermc.paper.dialog.Dialog
|
||||
import io.papermc.paper.registry.data.dialog.ActionButton
|
||||
import io.papermc.paper.registry.data.dialog.DialogBase
|
||||
import io.papermc.paper.registry.data.dialog.action.DialogAction
|
||||
import io.papermc.paper.registry.data.dialog.body.DialogBody
|
||||
import io.papermc.paper.registry.data.dialog.input.DialogInput
|
||||
import io.papermc.paper.registry.data.dialog.type.DialogType
|
||||
import io.papermc.paper.threadedregions.scheduler.ScheduledTask
|
||||
import net.kyori.adventure.text.Component
|
||||
import net.kyori.adventure.text.event.ClickCallback
|
||||
import net.kyori.adventure.text.format.TextColor
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer
|
||||
import net.minecraft.world.inventory.AnvilMenu
|
||||
import org.bukkit.craftbukkit.event.CraftEventFactory
|
||||
import org.bukkit.craftbukkit.inventory.CraftInventoryView
|
||||
import org.bukkit.craftbukkit.inventory.view.CraftAnvilView
|
||||
import org.bukkit.entity.HumanEntity
|
||||
import org.bukkit.event.inventory.PrepareAnvilEvent
|
||||
import org.bukkit.inventory.InventoryView
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.persistence.PersistentDataType
|
||||
import org.bukkit.plugin.Plugin
|
||||
import java.util.*
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Consumer
|
||||
import java.util.function.Supplier
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
class AnvilRenameDialogImpl(
|
||||
val fromFormated: BiFunction<HumanEntity, Component?, String?>,
|
||||
val keepUserPreviousDialog: Supplier<Boolean>,
|
||||
val maxLength: Supplier<Int>,
|
||||
val plugin: Plugin,
|
||||
) : AnvilRenameDialog {
|
||||
|
||||
companion object {
|
||||
private const val RENAME_TEXT_KEY = "rename"
|
||||
|
||||
private const val MAX_WIDTH = 512
|
||||
|
||||
private val PLAIN_TEXT_SERIALIZER = PlainTextComponentSerializer.plainText()
|
||||
|
||||
// Need to be able to translate it later !
|
||||
private val USER_FACING_RENAME_TITLE = Component.text("Rename Your Item")
|
||||
private val USER_FACING_WARNING = Component.text(
|
||||
"Note that the repair text will appear blank after Confirm\n" +
|
||||
"But the name will be correctly applied"
|
||||
)
|
||||
private val USER_FACING_CONFIRM = Component.text("Confirm").color(TextColor.fromHexString("#40FF40"))
|
||||
private val USER_FACING_CANCEL = Component.text("Cancel").color(TextColor.fromHexString("#FF4040"))
|
||||
|
||||
fun itemDefaultName(item: ItemStack?): String? {
|
||||
return PLAIN_TEXT_SERIALIZER.serializeOrNull(item?.effectiveName())
|
||||
}
|
||||
}
|
||||
|
||||
private val lastNames = HashMap<UUID, String>()
|
||||
private val lastRenames = HashMap<UUID, String>()
|
||||
|
||||
|
||||
private val lastLeftItem = HashMap<UUID, String>()
|
||||
private val runTaskMap = HashMap<UUID, ScheduledTask>()
|
||||
|
||||
// For monetary cost
|
||||
val hasUiOpen = HashSet<UUID>()
|
||||
|
||||
private val containerField = CraftInventoryView::class.java.getDeclaredField("container")
|
||||
|
||||
init {
|
||||
containerField.setAccessible(true)
|
||||
}
|
||||
|
||||
override fun canSendDialog(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
fun makeDialog(playerID: UUID, initial: String?, callback: Consumer<String?>): Dialog {
|
||||
val maxLength = this.maxLength.get()
|
||||
val initialFinal = initial?.take(maxLength)
|
||||
|
||||
val baseBuilder = DialogBase.builder(USER_FACING_RENAME_TITLE)
|
||||
.canCloseWithEscape(true)
|
||||
.afterAction(DialogBase.DialogAfterAction.CLOSE)
|
||||
.inputs(
|
||||
listOf(
|
||||
DialogInput.text(RENAME_TEXT_KEY, Component.text("Rename text"))
|
||||
.maxLength(maxLength)
|
||||
.initial(initialFinal ?: "")
|
||||
.labelVisible(false)
|
||||
.width(MAX_WIDTH)
|
||||
.build(),
|
||||
),
|
||||
)
|
||||
baseBuilder.body(
|
||||
listOf(
|
||||
DialogBody.plainMessage(USER_FACING_WARNING, MAX_WIDTH)
|
||||
)
|
||||
)
|
||||
|
||||
return Dialog.create { builder ->
|
||||
builder.empty()
|
||||
.base(baseBuilder.build())
|
||||
.type(
|
||||
DialogType.confirmation(
|
||||
ActionButton.builder(USER_FACING_CONFIRM)
|
||||
.action(DialogAction.customClick({ response, _ ->
|
||||
hasUiOpen.remove(playerID)
|
||||
val text = response.getText(RENAME_TEXT_KEY)!!
|
||||
callback.accept(text)
|
||||
}, ClickCallback.Options.builder().build()))
|
||||
.build(),
|
||||
ActionButton.builder(USER_FACING_CANCEL)
|
||||
.action(DialogAction.customClick({ response, _ ->
|
||||
hasUiOpen.remove(playerID)
|
||||
}, ClickCallback.Options.builder().build()))
|
||||
.build(),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setResult(player: HumanEntity, view: InventoryView, result: String?) {
|
||||
val defaultName = itemDefaultName(view.getItem(0))
|
||||
if (defaultName == result) {
|
||||
setName(player, view, "", null)
|
||||
if (defaultName != null) lastNames[player.uniqueId] = defaultName
|
||||
} else setName(player, view, result, result)
|
||||
}
|
||||
|
||||
private fun setName(player: HumanEntity, view: InventoryView, name: String?, rename: String?) {
|
||||
val menu = (containerField.get(view) as AnvilMenu)
|
||||
val isSameName = menu.itemName == name
|
||||
menu.itemName = rename
|
||||
|
||||
if (name == null)
|
||||
lastNames.remove(player.uniqueId)
|
||||
else
|
||||
lastNames[player.uniqueId] = name
|
||||
|
||||
if (rename == null)
|
||||
lastRenames.remove(player.uniqueId)
|
||||
else
|
||||
lastRenames[player.uniqueId] = rename
|
||||
|
||||
if (!isSameName)
|
||||
CraftEventFactory.callPrepareResultEvent(menu, 2);
|
||||
}
|
||||
|
||||
private fun nameFromItem(player: HumanEntity, item: ItemStack?): String? {
|
||||
// Already has text
|
||||
if (item?.hasItemMeta() != true || !item.itemMeta.hasCustomName())
|
||||
return PLAIN_TEXT_SERIALIZER.serializeOrNull(item?.effectiveName())
|
||||
|
||||
if (keepUserPreviousDialog.get() && item.hasItemMeta()) {
|
||||
val lastName = item.itemMeta.persistentDataContainer.get(
|
||||
AnvilRenameDialog.PCD_KEEP_RENAME_TEXT_KEY,
|
||||
PersistentDataType.STRING
|
||||
)
|
||||
|
||||
if (lastName != null) return lastName
|
||||
}
|
||||
|
||||
return fromFormated.apply(player, item.effectiveName())
|
||||
}
|
||||
|
||||
private fun tryShowDialogScheduled(player: HumanEntity, event: PrepareAnvilEvent) {
|
||||
val view = event.view
|
||||
if (view !is CraftAnvilView) return
|
||||
|
||||
val renameText = view.renameText
|
||||
val leftItem = view.getItem(0)
|
||||
val leftItemStr = leftItem?.toString()
|
||||
|
||||
val lastName = lastNames.getOrDefault(player.uniqueId, null)
|
||||
val lastRename = lastRenames.getOrDefault(player.uniqueId, null)
|
||||
|
||||
if (lastLeftItem.getOrDefault(player.uniqueId, null) != leftItemStr) {
|
||||
if (leftItemStr == null)
|
||||
lastLeftItem.remove(player.uniqueId)
|
||||
else lastLeftItem[player.uniqueId] = leftItemStr
|
||||
|
||||
setName(player, view, renameText, nameFromItem(player, leftItem))
|
||||
return
|
||||
}
|
||||
|
||||
if (lastName == renameText || lastRename == renameText)
|
||||
return
|
||||
|
||||
if (renameText?.isBlank() == true || renameText == itemDefaultName(leftItem)) {
|
||||
setName(player, view, lastName, lastRename)
|
||||
return
|
||||
}
|
||||
|
||||
val dialog = makeDialog(player.uniqueId, lastRename)
|
||||
{ result -> setResult(player, view, result) }
|
||||
player.showDialog(dialog)
|
||||
|
||||
hasUiOpen.add(player.uniqueId)
|
||||
}
|
||||
|
||||
// We need to wait for a short time as changing item will change the name BEFORE the item change
|
||||
// no guaranty both of them came in the same tick too so let's wait 2 tick....
|
||||
override fun tryShowDialog(player: HumanEntity, event: PrepareAnvilEvent) {
|
||||
runTaskMap.remove(player.uniqueId)?.cancel()
|
||||
|
||||
val task = player.scheduler.runDelayed(
|
||||
plugin,
|
||||
{ _ ->
|
||||
run { tryShowDialogScheduled(player, event) }
|
||||
},
|
||||
{},
|
||||
2
|
||||
)
|
||||
if (task == null) return
|
||||
|
||||
runTaskMap[player.uniqueId] = task
|
||||
}
|
||||
|
||||
override fun closeInventory(player: HumanEntity) {
|
||||
lastNames.remove(player.uniqueId)
|
||||
lastRenames.remove(player.uniqueId)
|
||||
lastLeftItem.remove(player.uniqueId)
|
||||
runTaskMap.remove(player.uniqueId)?.cancel()
|
||||
}
|
||||
|
||||
override fun currentText(player: HumanEntity): String? {
|
||||
return lastNames[player.uniqueId]
|
||||
}
|
||||
|
||||
override fun isOpenFor(player: HumanEntity): Boolean {
|
||||
return hasUiOpen.contains(player.uniqueId)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.util
|
||||
|
||||
import io.papermc.paper.threadedregions.scheduler.ScheduledTask
|
||||
import org.bukkit.entity.HumanEntity
|
||||
import org.bukkit.inventory.InventoryView
|
||||
import org.bukkit.plugin.Plugin
|
||||
import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialog
|
||||
import java.util.HashMap
|
||||
import java.util.UUID
|
||||
|
||||
object AnvilTitleUtil {
|
||||
|
||||
private val runTaskMap = HashMap<UUID, ScheduledTask>()
|
||||
|
||||
private fun actualRename(view: InventoryView, name: String, player: HumanEntity, anvilDialog: AnvilRenameDialog) {
|
||||
runTaskMap.remove(player.uniqueId)
|
||||
if (view.title == name) return
|
||||
|
||||
// We assume rename impl is used
|
||||
if (anvilDialog.isOpenFor(player)) return
|
||||
|
||||
view.title = name
|
||||
}
|
||||
|
||||
// We don't want to rename instantly it is causing issue with rename text
|
||||
// especially as it can "override" current ui when it is rename ui time but rename ui also need some delay
|
||||
fun rename(view: InventoryView, name: String, player: HumanEntity, anvilDialog: AnvilRenameDialog, plugin: Plugin) {
|
||||
runTaskMap.remove(player.uniqueId)?.cancel()
|
||||
|
||||
val task = player.scheduler.runDelayed(
|
||||
plugin,
|
||||
{ _ ->
|
||||
run { actualRename(view, name, player, anvilDialog) }
|
||||
},
|
||||
{
|
||||
runTaskMap.remove(player.uniqueId)
|
||||
},
|
||||
2
|
||||
)
|
||||
|
||||
if (task == null) return
|
||||
runTaskMap[player.uniqueId] = task
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_16)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_17)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_17)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_17)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_17)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_17)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_18)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_18)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_18)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.util
|
||||
|
||||
import org.bukkit.inventory.meta.Damageable
|
||||
|
||||
// I LOVE support of old versions and needing to do modules like that
|
||||
// That truly is my favorite activity
|
||||
// TODO clean this one of legacy removal branch
|
||||
object MaxDamageCheckerUtil {
|
||||
|
||||
/**
|
||||
* @return max damage or int max if not set
|
||||
*/
|
||||
fun getMaxDamage(meta: Damageable): Int {
|
||||
if(!meta.hasMaxDamage()) return Integer.MAX_VALUE
|
||||
return meta.maxDamage
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_21)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_21)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_21)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_21)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_21)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_21)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ tasks.withType<JavaCompile>().configureEach {
|
|||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
|
||||
jvmTarget.set(JvmTarget.JVM_21)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,5 +18,5 @@ for (nmsPart in reobfNMS) {
|
|||
// compatibility subprojects
|
||||
include(":impl:LegacyEcoEnchant")
|
||||
findProject(":impl:LegacyEcoEnchant")?.name = "LegacyEcoEnchant"
|
||||
include("impl:ExcellentEnchant5_4")
|
||||
findProject(":impl:ExcellentEnchant5_4")?.name = "ExcellentEnchant5_4"
|
||||
include("impl:ExcellentEnchant5_3")
|
||||
findProject(":impl:ExcellentEnchant5_3")?.name = "ExcellentEnchant5_3"
|
||||
|
|
@ -13,7 +13,6 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
//TODO add conflict after level
|
||||
/**
|
||||
* A Builder for material conflict.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package xyz.alexcrea.cuanvil.api;
|
||||
|
||||
import io.delilaheve.CustomAnvil;
|
||||
import io.delilaheve.util.ConfigOptions;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
|
|
@ -181,13 +180,13 @@ public class EnchantmentApi {
|
|||
private static boolean tryWriteDefaultConfig(FileConfiguration defaultConfig, CAEnchantment enchantment, boolean override) {
|
||||
boolean hasChange = false;
|
||||
|
||||
String levelPath = ConfigOptions.ENCHANT_LIMIT_ROOT + "." + enchantment.getKey();
|
||||
String levelPath = "enchant_limits." + enchantment.getKey();
|
||||
if(override || !defaultConfig.isSet(levelPath)){
|
||||
defaultConfig.set(levelPath, enchantment.defaultMaxLevel());
|
||||
hasChange = true;
|
||||
}
|
||||
|
||||
String basePath = ConfigOptions.ENCHANT_VALUES_ROOT + "." + enchantment.getKey();
|
||||
String basePath = "enchant_values." + enchantment.getKey();
|
||||
EnchantmentRarity rarity = enchantment.defaultRarity();
|
||||
|
||||
String itemPath = basePath + ".item";
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package xyz.alexcrea.cuanvil.api;
|
|||
import io.delilaheve.CustomAnvil;
|
||||
import io.delilaheve.util.ConfigOptions;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
|
@ -124,7 +123,7 @@ public class MaterialGroupApi {
|
|||
FileConfiguration config = ConfigHolder.ITEM_GROUP_HOLDER.getConfig();
|
||||
|
||||
String basePath = group.getName() + ".";
|
||||
Set<NamespacedKey> materialSet = group.getNonGroupInheritedMaterials();
|
||||
Set<Material> materialSet = group.getNonGroupInheritedMaterials();
|
||||
Set<AbstractMaterialGroup> groupSet = group.getGroups();
|
||||
|
||||
boolean empty = true;
|
||||
|
|
@ -154,7 +153,7 @@ public class MaterialGroupApi {
|
|||
FileConfiguration config = ConfigHolder.ITEM_GROUP_HOLDER.getConfig();
|
||||
|
||||
String basePath = group.getName() + ".";
|
||||
Set<NamespacedKey> materials = group.getMaterials();
|
||||
EnumSet<Material> materials = group.getMaterials();
|
||||
|
||||
if (materials.isEmpty()) return false;
|
||||
|
||||
|
|
@ -164,8 +163,8 @@ public class MaterialGroupApi {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static List<String> materialSetToStringList(@NotNull Set<NamespacedKey> materials) {
|
||||
return materials.stream().map(NamespacedKey::toString).toList();
|
||||
public static List<String> materialSetToStringList(@NotNull Set<Material> materials) {
|
||||
return materials.stream().map(material -> material.getKey().getKey().toLowerCase()).toList();
|
||||
}
|
||||
|
||||
public static List<String> materialGroupSetToStringList(@NotNull Set<AbstractMaterialGroup> groups) {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import org.jetbrains.annotations.NotNull;
|
|||
* Most of the time you would likely need {@link CAPreAnvilBypassEvent} or {@link CAEarlyPreAnvilBypassEvent}
|
||||
* for this event to be useful.
|
||||
* <p>
|
||||
* There is also {@link CATreatAnvilResult2Event} that may be better for some use case.
|
||||
* There is also {@link CATreatAnvilResultEvent} that may be better for some use case.
|
||||
*/
|
||||
public class CAClickResultBypassEvent extends Event implements Cancellable {
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import org.jetbrains.annotations.NotNull;
|
|||
* <p>
|
||||
* You should also use {@link CAClickResultBypassEvent} if you want to use this event for something useful.
|
||||
* <p>
|
||||
* It is also recommended that you read about {@link CAPreAnvilBypassEvent} and {@link CATreatAnvilResult2Event}
|
||||
* It is also recommended that you read about {@link CAPreAnvilBypassEvent} and {@link CATreatAnvilResultEvent}
|
||||
* as your use case may be more prone to use theses.
|
||||
*/
|
||||
public class CAEarlyPreAnvilBypassEvent extends Event implements Cancellable {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import org.jetbrains.annotations.NotNull;
|
|||
* <p>
|
||||
* You should also use {@link CAClickResultBypassEvent} if you want to use this event for something useful.
|
||||
* <p>
|
||||
* It is also recommended that you read about {@link CAEarlyPreAnvilBypassEvent} and {@link CATreatAnvilResult2Event}
|
||||
* It is also recommended that you read about {@link CAEarlyPreAnvilBypassEvent} and {@link CATreatAnvilResultEvent}
|
||||
* as your use case may be more prone to use theses.
|
||||
*/
|
||||
public class CAPreAnvilBypassEvent extends Event implements Cancellable {
|
||||
|
|
|
|||
|
|
@ -1,196 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.api.event.listener;
|
||||
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.alexcrea.cuanvil.anvil.AnvilCost;
|
||||
import xyz.alexcrea.cuanvil.anvil.AnvilUseType;
|
||||
|
||||
/**
|
||||
* Called after custom anvil processed the click on the result on the anvil inventory.
|
||||
* This event should be used to modify the result of an anvil use.
|
||||
* <p>
|
||||
* You may also want to check {@link CAClickResultBypassEvent},
|
||||
* {@link CAPreAnvilBypassEvent}
|
||||
* and {@link CAEarlyPreAnvilBypassEvent} for your use case
|
||||
* <p>
|
||||
* A null result will cancel this event
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class CATreatAnvilResult2Event extends Event {
|
||||
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final InventoryView view;
|
||||
|
||||
private final AnvilUseType useType;
|
||||
|
||||
@Nullable
|
||||
private final ItemStack left;
|
||||
@Nullable
|
||||
private final ItemStack right;
|
||||
|
||||
@Nullable
|
||||
private ItemStack result;
|
||||
|
||||
private final AnvilCost cost;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public CATreatAnvilResult2Event(
|
||||
@NotNull InventoryView view,
|
||||
Inventory inv,
|
||||
AnvilUseType useType,
|
||||
@Nullable ItemStack result,
|
||||
AnvilCost cost) {
|
||||
this.view = view;
|
||||
this.useType = useType;
|
||||
|
||||
this.left = inv.getItem(0); // TODO use view here
|
||||
this.right = inv.getItem(1);
|
||||
this.result = result;
|
||||
this.cost = cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bukkit inventory view.
|
||||
* <p>
|
||||
* Temporarily marked as internal as it will get changed to anvil view on legacy removal
|
||||
* so signature will change
|
||||
*
|
||||
* @return The inventory view of this event.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public @NotNull InventoryView getView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the type of use source of the result.
|
||||
*
|
||||
* @return The craft use type.
|
||||
*/
|
||||
public AnvilUseType getUseType() {
|
||||
return useType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the left item of the anvil use
|
||||
*
|
||||
* @return the left item
|
||||
*/
|
||||
public @Nullable ItemStack getLeftItem() {
|
||||
return left;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the right item of the anvil use
|
||||
*
|
||||
* @return the right item
|
||||
*/
|
||||
public @Nullable ItemStack getRightItem() {
|
||||
return right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current result
|
||||
* <p>
|
||||
* note that it will not be null unless another listener previously set it to null.
|
||||
*
|
||||
* @return The current result.
|
||||
*/
|
||||
public @Nullable ItemStack getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current result
|
||||
* <p>
|
||||
* note that a null result will cancel this anvil use.
|
||||
*
|
||||
* @param result The new result
|
||||
*/
|
||||
public void setResult(@Nullable ItemStack result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the level cost displayed on the anvil.
|
||||
* <h3>Important note:</h3>
|
||||
* the final price are re calculated on click for the following use case:
|
||||
* <ul>
|
||||
* <li>Custom craft</li>
|
||||
* <li>Unit repair</li>
|
||||
* <li>Lore edit</li>
|
||||
* </ul>
|
||||
* This value will be used as final price for:
|
||||
* <li>Item merge</li>
|
||||
* <li>Item rename</li>
|
||||
* </ul>
|
||||
*
|
||||
* @return The current cost.
|
||||
* @deprecated use #{@link #getCost()} instead
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "1.17.0")
|
||||
public int getLevelCost() {
|
||||
return cost.asXpCost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the level cost displayed on the anvil.
|
||||
* <h3>Important note:</h3>
|
||||
* the final price are re calculated on click for the following use case:
|
||||
* <ul>
|
||||
* <li>Custom craft</li>
|
||||
* <li>Unit repair</li>
|
||||
* <li>Lore edit</li>
|
||||
* </ul>
|
||||
* This value will be used as final price for:
|
||||
* <li>Item merge</li>
|
||||
* <li>Item rename</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param levelCost The new cost.
|
||||
* @deprecated use #{@link #getCost()} and set value on this instead
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "1.17.0")
|
||||
public void setLevelCost(int levelCost) {
|
||||
cost.setGeneric(levelCost - cost.getGeneric() - cost.asXpCost());
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow access to the current cost of the event
|
||||
* Note that modifying this object will change the event resulting cost
|
||||
*
|
||||
* <h3>Important note:</h3>
|
||||
* the final price are re calculated on click for the following use case:
|
||||
* <ul>
|
||||
* <li>Custom craft</li>
|
||||
* <li>Unit repair</li>
|
||||
* <li>Lore edit</li>
|
||||
* </ul>
|
||||
* This value will be used as final price for:
|
||||
* <li>Item merge</li>
|
||||
* <li>Item rename</li>
|
||||
*
|
||||
* @return the current anvil cost
|
||||
*/
|
||||
public AnvilCost getCost() {
|
||||
return cost;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,8 +6,7 @@ import org.bukkit.event.inventory.PrepareAnvilEvent;
|
|||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.alexcrea.cuanvil.anvil.AnvilCost;
|
||||
import xyz.alexcrea.cuanvil.anvil.AnvilUseType;
|
||||
import xyz.alexcrea.cuanvil.util.AnvilUseType;
|
||||
|
||||
/**
|
||||
* Called after custom anvil processed the click on the result on the anvil inventory.
|
||||
|
|
@ -18,12 +17,8 @@ import xyz.alexcrea.cuanvil.anvil.AnvilUseType;
|
|||
* and {@link CAEarlyPreAnvilBypassEvent} for your use case
|
||||
* <p>
|
||||
* A null result will cancel this pre anvil event
|
||||
*
|
||||
* @deprecated Prepare anvil Event cannot be provided as it can be called on result and therefore not have prepared anvil event
|
||||
* use {@link CATreatAnvilResult2Event} instead
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@Deprecated(forRemoval = true, since = "1.17.0")
|
||||
public class CATreatAnvilResultEvent extends Event {
|
||||
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
|
|
@ -45,13 +40,13 @@ public class CATreatAnvilResultEvent extends Event {
|
|||
@Nullable
|
||||
private ItemStack result;
|
||||
|
||||
private final AnvilCost cost;
|
||||
private int levelCost;
|
||||
|
||||
public CATreatAnvilResultEvent(@NotNull PrepareAnvilEvent event, AnvilUseType useType, @Nullable ItemStack result, AnvilCost cost) {
|
||||
public CATreatAnvilResultEvent(@NotNull PrepareAnvilEvent event, AnvilUseType useType, @Nullable ItemStack result, int levelCost) {
|
||||
this.event = event;
|
||||
this.useType = useType;
|
||||
this.result = result;
|
||||
this.cost = cost;
|
||||
this.levelCost = levelCost;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -109,11 +104,9 @@ public class CATreatAnvilResultEvent extends Event {
|
|||
* </ul>
|
||||
*
|
||||
* @return The current cost.
|
||||
* @deprecated use #{@link #getCost()} instead
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "1.17.0")
|
||||
public int getLevelCost() {
|
||||
return cost.asXpCost();
|
||||
return levelCost;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -131,32 +124,8 @@ public class CATreatAnvilResultEvent extends Event {
|
|||
* </ul>
|
||||
*
|
||||
* @param levelCost The new cost.
|
||||
* @deprecated use #{@link #getCost()} and set value on this instead
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "1.17.0")
|
||||
public void setLevelCost(int levelCost) {
|
||||
cost.setGeneric(levelCost - cost.getGeneric() - cost.asXpCost());
|
||||
this.levelCost = levelCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow access to the current cost of the event
|
||||
* Note that modifying this object will change the event resulting cost
|
||||
*
|
||||
* <h3>Important note:</h3>
|
||||
* the final price are re calculated on click for the following use case:
|
||||
* <ul>
|
||||
* <li>Custom craft</li>
|
||||
* <li>Unit repair</li>
|
||||
* <li>Lore edit</li>
|
||||
* </ul>
|
||||
* This value will be used as final price for:
|
||||
* <li>Item merge</li>
|
||||
* <li>Item rename</li>
|
||||
*
|
||||
* @return the current anvil cost
|
||||
*/
|
||||
public AnvilCost getCost() {
|
||||
return cost;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import org.jetbrains.annotations.Nullable;
|
|||
import xyz.alexcrea.cuanvil.group.EnchantConflictManager;
|
||||
import xyz.alexcrea.cuanvil.group.ItemGroupManager;
|
||||
import xyz.alexcrea.cuanvil.recipe.CustomAnvilRecipeManager;
|
||||
import xyz.alexcrea.cuanvil.util.MetricsUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
|
@ -146,7 +145,6 @@ public abstract class ConfigHolder {
|
|||
sufficientSuccess = true;
|
||||
} catch (IOException e) {
|
||||
CustomAnvil.instance.getLogger().log(Level.WARNING, "Could not copy backup saving config " + base.getName(), e);
|
||||
MetricsUtil.INSTANCE.trackError(e);
|
||||
}
|
||||
}
|
||||
// save last backup
|
||||
|
|
@ -277,7 +275,6 @@ public abstract class ConfigHolder {
|
|||
this.deletedConfigFile.createNewFile();
|
||||
} catch (IOException e) {
|
||||
CustomAnvil.instance.getLogger().log(Level.WARNING, "Could not create " + this.deletedConfigFile.getPath(), e);
|
||||
MetricsUtil.INSTANCE.trackError(e);
|
||||
}
|
||||
loadDeletedListFile(false);
|
||||
|
||||
|
|
@ -315,7 +312,6 @@ public abstract class ConfigHolder {
|
|||
this.deletedListConfig.save(this.deletedConfigFile);
|
||||
} catch (IOException e) {
|
||||
CustomAnvil.instance.getLogger().log(Level.WARNING, "Could not save " + this.deletedConfigFile.getPath(), e);
|
||||
MetricsUtil.INSTANCE.trackError(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package xyz.alexcrea.cuanvil.config;
|
|||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.alexcrea.cuanvil.anvil.AnvilUseType;
|
||||
import xyz.alexcrea.cuanvil.util.AnvilUseType;
|
||||
|
||||
import java.util.EnumMap;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package xyz.alexcrea.cuanvil.enchant;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
|
@ -12,23 +11,24 @@ public interface AdditionalTestEnchantment {
|
|||
/**
|
||||
* Test if the provided enchantments can be compatible with this enchantment. only non-Custom Anvil conflict.
|
||||
* @param enchantments Immutable map of validated enchantments for the item.
|
||||
* @param itemType Material namespaced key of the tested item.
|
||||
* @param itemMat Material of the tested item.
|
||||
* @return If there is a conflict with the enchantments.
|
||||
*/
|
||||
boolean isEnchantConflict(
|
||||
@NotNull Map<CAEnchantment, Integer> enchantments,
|
||||
@NotNull NamespacedKey itemType);
|
||||
@NotNull Material itemMat);
|
||||
|
||||
|
||||
/**
|
||||
* Test if the provided item can be compatible with this enchantment. only non-Custom Anvil conflict.
|
||||
* @param enchantments Immutable map of validated enchantments for the item.
|
||||
* @param itemType Material namespaced key of the tested item.
|
||||
* @param itemMat Material of the tested item.
|
||||
* @param item Provide a new instance of the used item stack with the partial enchantment applied.
|
||||
* @return If there is a conflict with the enchantment and the item.
|
||||
*/
|
||||
boolean isItemConflict(
|
||||
@NotNull Map<CAEnchantment, Integer> enchantments,
|
||||
@NotNull NamespacedKey itemType,
|
||||
@NotNull Material itemMat,
|
||||
@NotNull ItemStack item);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import xyz.alexcrea.cuanvil.enchant.bulk.BukkitEnchantBulkOperation;
|
|||
import xyz.alexcrea.cuanvil.enchant.bulk.BulkCleanEnchantOperation;
|
||||
import xyz.alexcrea.cuanvil.enchant.bulk.BulkGetEnchantOperation;
|
||||
import xyz.alexcrea.cuanvil.enchant.wrapped.CABukkitEnchantment;
|
||||
import xyz.alexcrea.cuanvil.util.MetricsUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
|
|
@ -86,13 +85,11 @@ public class CAEnchantmentRegistry {
|
|||
return false;
|
||||
}
|
||||
|
||||
var error = new IllegalStateException("enchantment " + enchantment.getKey() + " was already registered");
|
||||
CustomAnvil.instance.getLogger().log(Level.WARNING,
|
||||
"Duplicate distinct registered enchantment. This should NOT happen any time.\n" +
|
||||
"If you are a custom anvil developer: Maybe custom anvil detected your enchantment as a bukkit enchantment. " +
|
||||
"you should maybe remove enchantment with the same key before registering yours",
|
||||
error);
|
||||
MetricsUtil.INSTANCE.trackError(error);
|
||||
new IllegalStateException("enchantment " + enchantment.getKey() + " was already registered"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.enchant.bulk;
|
||||
|
||||
import com.maddoxh.superEnchants.items.EnchantApplicator;
|
||||
import com.maddoxh.superEnchants.items.EnchantReader;
|
||||
import io.delilaheve.CustomAnvil;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.alexcrea.cuanvil.api.EnchantmentApi;
|
||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class SuperEnchantBulkOperation implements BulkGetEnchantOperation, BulkCleanEnchantOperation {
|
||||
|
||||
private Plugin plugin;
|
||||
public SuperEnchantBulkOperation(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bulkGet(@NotNull Map<CAEnchantment, Integer> enchantmentMap, @NotNull ItemStack item, @NotNull ItemMeta meta) {
|
||||
EnchantReader.INSTANCE.readEnchants(item).forEach((ench, level) -> {
|
||||
var enchantment = EnchantmentApi.getByKey(NamespacedKey.fromString(ench, plugin));
|
||||
if(enchantment == null) {
|
||||
CustomAnvil.log("Enchantment " + ench + " not found in custom anvil");
|
||||
return;
|
||||
}
|
||||
|
||||
enchantmentMap.put(enchantment, level);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bulkClear(@NotNull ItemStack item) {
|
||||
EnchantApplicator.INSTANCE.clearAllCustomEnchants(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bulkClear(@NotNull ItemStack item, @NotNull ItemMeta meta) {
|
||||
// item meta is not preferred for enchantment squared clear
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package xyz.alexcrea.cuanvil.enchant.wrapped;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.CustomEnchantment;
|
||||
|
|
@ -40,7 +39,7 @@ public class CAEEPreV5Enchantment extends CABukkitEnchantment implements Additio
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull NamespacedKey itemType) {
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull Material itemMat) {
|
||||
if (!definition.hasConflicts()) return false;
|
||||
|
||||
Set<String> conflicts = definition.getConflicts();
|
||||
|
|
@ -53,8 +52,8 @@ public class CAEEPreV5Enchantment extends CABukkitEnchantment implements Additio
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull NamespacedKey itemType, @NotNull ItemStack item) {
|
||||
if (Material.ENCHANTED_BOOK.getKey().equals(itemType)) return false;
|
||||
public boolean isItemConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull Material itemMat, @NotNull ItemStack item) {
|
||||
if (Material.ENCHANTED_BOOK.equals(itemMat)) return false;
|
||||
|
||||
return !definition.getSupportedItems().is(item);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,51 +1,48 @@
|
|||
package xyz.alexcrea.cuanvil.enchant.wrapped;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.CustomEnchantment;
|
||||
import su.nightexpress.excellentenchants.api.item.ItemSet;
|
||||
import su.nightexpress.excellentenchants.api.wrapper.EnchantDefinition;
|
||||
import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment;
|
||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
|
||||
import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class CAEEV5Enchantment extends CABukkitEnchantment implements AdditionalTestEnchantment {
|
||||
|
||||
@NotNull CustomEnchantment eeenchantment;
|
||||
@NotNull Object definition;
|
||||
@NotNull EnchantDefinition definition;
|
||||
|
||||
public CAEEV5Enchantment(@NotNull CustomEnchantment enchantment) {
|
||||
super(enchantment.getBukkitEnchantment(), EnchantmentRarity.getRarity(getAnvilCost(enchantment)));
|
||||
super(enchantment.getBukkitEnchantment(), EnchantmentRarity.getRarity(enchantment.getDefinition().getAnvilCost()));
|
||||
this.eeenchantment = enchantment;
|
||||
this.definition = getDefinition(enchantment);
|
||||
this.definition = enchantment.getDefinition();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull NamespacedKey itemType) {
|
||||
if (!hasConflicts()) return false;
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull Material itemMat) {
|
||||
if (!definition.hasConflicts()) return false;
|
||||
|
||||
Set<String> conflicts = getExclusiveSet();
|
||||
Set<String> conflicts = definition.getExclusiveSet();
|
||||
|
||||
for (CAEnchantment caEnchantment : enchantments.keySet()) {
|
||||
if (conflicts.contains(caEnchantment.getName())) return true;
|
||||
if (conflicts.contains(caEnchantment.getKey().toString())) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull NamespacedKey itemType, @NotNull ItemStack item) {
|
||||
if (Material.ENCHANTED_BOOK.getKey().equals(itemType)) return false;
|
||||
public boolean isItemConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull Material itemMat, @NotNull ItemStack item) {
|
||||
if (Material.ENCHANTED_BOOK.equals(itemMat)) return false;
|
||||
|
||||
String key = itemType.getKey();
|
||||
String key = itemMat.getKey().getKey();
|
||||
ItemSet primary = eeenchantment.getPrimaryItems();
|
||||
if (primary.getMaterials().contains(key)) return false;
|
||||
|
||||
|
|
@ -55,74 +52,4 @@ public class CAEEV5Enchantment extends CABukkitEnchantment implements Additional
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
private static final Method getDefinitonMethod;
|
||||
|
||||
private static final Method getAnvilCostMethod;
|
||||
private static final Method hasConflictsMethod;
|
||||
private static final Method getExclusiveSetMethod;
|
||||
static {
|
||||
var enchClazz = CustomEnchantment.class;
|
||||
try {
|
||||
getDefinitonMethod = enchClazz.getDeclaredMethod("getDefinition");
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
Class<?> definitionClazz;
|
||||
try {
|
||||
definitionClazz = Class.forName("su.nightexpress.excellentenchants.api.EnchantDefinition");
|
||||
} catch (ClassNotFoundException e) {
|
||||
try {
|
||||
definitionClazz = Class.forName("su.nightexpress.excellentenchants.api.wrapper.EnchantDefinition");
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Now definition methods
|
||||
try {
|
||||
getAnvilCostMethod = definitionClazz.getDeclaredMethod("getAnvilCost");
|
||||
hasConflictsMethod = definitionClazz.getDeclaredMethod("hasConflicts");
|
||||
getExclusiveSetMethod = definitionClazz.getDeclaredMethod("getExclusiveSet");
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Object getDefinition(CustomEnchantment enchantment) {
|
||||
try {
|
||||
return getDefinitonMethod.invoke(enchantment);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static int getAnvilCost(CustomEnchantment enchantment) {
|
||||
try {
|
||||
return (int) getAnvilCostMethod.invoke(getDefinition(enchantment));
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasConflicts() {
|
||||
try {
|
||||
return (boolean) hasConflictsMethod.invoke(definition);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Set<String> getExclusiveSet() {
|
||||
try {
|
||||
return (Set<String>) getExclusiveSetMethod.invoke(definition);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.enchant.wrapped;
|
||||
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.CustomEnchantment;
|
||||
import xyz.alexcrea.cuanvil.dependency.plugins.ExcellentEnchant5_4EnchantSettings;
|
||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class CAEEV5_4Enchantment extends CAEEV5Enchantment {
|
||||
|
||||
public CAEEV5_4Enchantment(@NotNull CustomEnchantment enchantment) {
|
||||
super(enchantment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull NamespacedKey itemMat) {
|
||||
if(super.isEnchantConflict(enchantments, itemMat)) return true;
|
||||
|
||||
var limit = ExcellentEnchant5_4EnchantSettings.anvilLimit();
|
||||
var count = enchantments.keySet().stream()
|
||||
.filter(key -> key instanceof CAEEV5_4Enchantment)
|
||||
.count();
|
||||
|
||||
return count > limit;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ import com.willfp.ecoenchants.enchant.EcoEnchant;
|
|||
import com.willfp.ecoenchants.target.EnchantmentTarget;
|
||||
import com.willfp.ecoenchants.type.EnchantmentType;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment;
|
||||
|
|
@ -24,13 +23,9 @@ public class CAEcoEnchant extends CABukkitEnchantment implements AdditionalTestE
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull NamespacedKey itemType) {
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull Material itemMat) {
|
||||
if (enchantments.isEmpty()) return false;
|
||||
|
||||
// Check if there is only self
|
||||
if (enchantments.size() == 1 && this.equals(enchantments.keySet().stream().findFirst().get()))
|
||||
return false;
|
||||
|
||||
if (this.ecoEnchant.getConflictsWithEverything()) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -62,9 +57,9 @@ public class CAEcoEnchant extends CABukkitEnchantment implements AdditionalTestE
|
|||
|
||||
@Override
|
||||
public boolean isItemConflict(@NotNull Map<CAEnchantment, Integer> enchantments,
|
||||
@NotNull NamespacedKey itemType,
|
||||
@NotNull Material itemMat,
|
||||
@NotNull ItemStack item) {
|
||||
if (Material.ENCHANTED_BOOK.getKey().equals(itemType)) {
|
||||
if (Material.ENCHANTED_BOOK.equals(itemMat)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package xyz.alexcrea.cuanvil.enchant.wrapped;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
|
@ -25,12 +24,12 @@ public class CAIncompatibleAllEnchant extends CABukkitEnchantment implements Add
|
|||
|
||||
|
||||
@Override
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull NamespacedKey itemType) {
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull Material itemMat) {
|
||||
return !enchantments.isEmpty() && !(enchantments.size() == 1 && enchantments.containsKey(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull NamespacedKey itemType, @NotNull ItemStack item) {
|
||||
public boolean isItemConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull Material itemMat, @NotNull ItemStack item) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package xyz.alexcrea.cuanvil.enchant.wrapped;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
|
||||
|
|
@ -23,7 +22,7 @@ public class CALegacyEEEnchantment extends CABukkitEnchantment implements Additi
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull NamespacedKey itemType) {
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull Material itemMat) {
|
||||
if (!eeenchantment.hasConflicts()) return false;
|
||||
|
||||
Set<String> conflicts = eeenchantment.getConflicts();
|
||||
|
|
@ -36,8 +35,8 @@ public class CALegacyEEEnchantment extends CABukkitEnchantment implements Additi
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull NamespacedKey itemType, @NotNull ItemStack item) {
|
||||
if (Material.ENCHANTED_BOOK.getKey().equals(itemType)) return false;
|
||||
public boolean isItemConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull Material itemMat, @NotNull ItemStack item) {
|
||||
if (Material.ENCHANTED_BOOK.equals(itemMat)) return false;
|
||||
|
||||
return !eeenchantment.getSupportedItems().is(item);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,12 @@ import com.willfp.ecoenchants.enchantments.EcoEnchant;
|
|||
import com.willfp.ecoenchants.enchantments.meta.EnchantmentTarget;
|
||||
import com.willfp.ecoenchants.enchantments.meta.EnchantmentType;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment;
|
||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
|
||||
import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity;
|
||||
import xyz.alexcrea.cuanvil.util.MaterialUtil;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
|
@ -25,7 +23,7 @@ public class CALegacyEcoEnchant extends CABukkitEnchantment implements Additiona
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull NamespacedKey itemType) {
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull Material itemMat) {
|
||||
if (enchantments.isEmpty()) return false;
|
||||
|
||||
EnchantmentType type = this.ecoEnchant.getType();
|
||||
|
|
@ -50,15 +48,14 @@ public class CALegacyEcoEnchant extends CABukkitEnchantment implements Additiona
|
|||
|
||||
@Override
|
||||
public boolean isItemConflict(@NotNull Map<CAEnchantment, Integer> enchantments,
|
||||
@NotNull NamespacedKey itemType,
|
||||
@NotNull Material itemMat,
|
||||
@NotNull ItemStack item) {
|
||||
if (Material.ENCHANTED_BOOK.getKey().equals(itemType)) {
|
||||
if (Material.ENCHANTED_BOOK.equals(itemMat)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var mat = MaterialUtil.INSTANCE.getMatFromKey(itemType);
|
||||
for (EnchantmentTarget target : this.ecoEnchant.getTargets()) {
|
||||
if (target.getMaterials().contains(mat)) {
|
||||
if (target.getMaterials().contains(itemMat)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,76 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.enchant.wrapped;
|
||||
|
||||
import com.maddoxh.superEnchants.enchants.CustomEnchant;
|
||||
import com.maddoxh.superEnchants.enchants.EnchantManager;
|
||||
import com.maddoxh.superEnchants.items.EnchantApplicator;
|
||||
import com.maddoxh.superEnchants.items.EnchantReader;
|
||||
import com.maddoxh.superEnchants.util.ConflictChecker;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment;
|
||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
|
||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantmentBase;
|
||||
import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CASuperEnchantEnchantment extends CAEnchantmentBase implements AdditionalTestEnchantment {
|
||||
|
||||
private @NotNull CustomEnchant enchant;
|
||||
private @NotNull EnchantManager enchantManager;
|
||||
|
||||
public CASuperEnchantEnchantment(@NotNull CustomEnchant enchant, @NotNull Plugin plugin, @NotNull EnchantManager enchantManager) {
|
||||
super(NamespacedKey.fromString(enchant.getId(), plugin), EnchantmentRarity.COMMON, enchant.getMaxLevel());
|
||||
|
||||
this.enchant = enchant;
|
||||
this.enchantManager = enchantManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLevel(@NotNull ItemStack item, @NotNull ItemMeta meta) {
|
||||
return EnchantReader.INSTANCE.getEnchantLevel(item, enchant.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnchantmentPresent(@NotNull ItemStack item, @NotNull ItemMeta meta) {
|
||||
return EnchantReader.INSTANCE.hasEnchant(item, enchant.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEnchantmentUnsafe(@NotNull ItemStack item, int level) {
|
||||
EnchantApplicator.INSTANCE.applyEnchant(item, enchant.getId(), level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFrom(@NotNull ItemStack item) {
|
||||
EnchantApplicator.INSTANCE.removeEnchant(item, enchant.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull NamespacedKey itemType) {
|
||||
var idMap = new HashMap<String, Integer>();
|
||||
|
||||
enchantments.forEach((enchant, level) -> {
|
||||
if(!(enchant instanceof CASuperEnchantEnchantment superEnch)) return;
|
||||
idMap.put(superEnch.enchant.getId(), level);
|
||||
});
|
||||
|
||||
return ConflictChecker.INSTANCE.hasConflict(
|
||||
idMap,
|
||||
enchant.getId(),
|
||||
enchantManager
|
||||
) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull NamespacedKey itemType, @NotNull ItemStack item) {
|
||||
if(Material.ENCHANTED_BOOK.equals(item.getType())) return false;
|
||||
|
||||
return !enchant.canApplyTo(item.getType());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +1,34 @@
|
|||
package xyz.alexcrea.cuanvil.gui.config;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public interface SelectMaterialContainer {
|
||||
|
||||
Set<NamespacedKey> getSelectedMaterials();
|
||||
EnumSet<Material> getSelectedMaterials();
|
||||
|
||||
boolean setSelectedMaterials(Set<NamespacedKey> materials);
|
||||
boolean setSelectedMaterials(EnumSet<Material> materials);
|
||||
|
||||
Set<NamespacedKey> illegalMaterials();
|
||||
EnumSet<Material> illegalMaterials();
|
||||
|
||||
static List<String> getMaterialLore(SelectMaterialContainer container, String containerType, String action){
|
||||
// Prepare material lore
|
||||
ArrayList<String> groupLore = new ArrayList<>();
|
||||
groupLore.add("§7Allow you to select a list of §ematerials §7that this " + containerType + " should " + action);
|
||||
Set<NamespacedKey> materialSet = container.getSelectedMaterials();
|
||||
Set<Material> materialSet = container.getSelectedMaterials();
|
||||
if (materialSet.isEmpty()) {
|
||||
groupLore.add("§7There is no "+action+"d material for this "+containerType+".");
|
||||
} else {
|
||||
groupLore.add("§7List of "+action+"d materials for this "+containerType+":");
|
||||
Iterator<NamespacedKey> materialIterator = materialSet.iterator();
|
||||
Iterator<Material> materialIterator = materialSet.iterator();
|
||||
|
||||
boolean greaterThanMax = materialSet.size() > 5;
|
||||
int maxindex = (greaterThanMax ? 4 : materialSet.size());
|
||||
for (int i = 0; i < maxindex; i++) {
|
||||
// format string like "- Stone Sword"
|
||||
String formattedName = CasedStringUtil.snakeToUpperSpacedCase(materialIterator.next().getKey().toLowerCase());
|
||||
String formattedName = CasedStringUtil.snakeToUpperSpacedCase(materialIterator.next().name().toLowerCase());
|
||||
groupLore.add("§7- §e" + formattedName);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import org.bukkit.inventory.meta.ItemMeta;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
|
||||
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
|
||||
import xyz.alexcrea.cuanvil.util.MetricsUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Supplier;
|
||||
|
|
@ -42,7 +41,6 @@ public class ConfirmActionGui extends AbstractAskGui {
|
|||
success = onConfirm.get();
|
||||
} catch (Exception e) {
|
||||
CustomAnvil.instance.getLogger().log(Level.WARNING, "Could not process confirmation supplier.", e);
|
||||
MetricsUtil.INSTANCE.trackError(e);
|
||||
success = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import org.jetbrains.annotations.NotNull;
|
|||
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
|
||||
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
|
||||
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
|
||||
import xyz.alexcrea.cuanvil.util.MaterialUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
|
@ -53,7 +52,7 @@ public class SelectItemTypeGui extends AbstractAskGui {
|
|||
event.setCancelled(true);
|
||||
|
||||
ItemStack cursor = event.getWhoClicked().getItemOnCursor();
|
||||
if(MaterialUtil.INSTANCE.isAir(cursor)) return;
|
||||
if(cursor.getType().isAir()) return;
|
||||
|
||||
ItemStack finalItem;
|
||||
if(materialOnly){
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import org.bukkit.inventory.meta.ItemMeta;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.alexcrea.cuanvil.config.ConfigHolder;
|
||||
import xyz.alexcrea.cuanvil.dependency.MinecraftVersionUtil;
|
||||
import xyz.alexcrea.cuanvil.dependency.packet.PacketManager;
|
||||
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
|
||||
import xyz.alexcrea.cuanvil.gui.config.MainConfigGui;
|
||||
|
|
@ -284,7 +283,7 @@ public class BasicConfigGui extends ChestGui implements ValueUpdatableGui {
|
|||
|
||||
if(!this.packetManager.getCanSetInstantBuild()){
|
||||
lore.add("");
|
||||
lore.add("§4/!\\§cCaution§4/!\\ §cYou need ProtocoLib installed and working or a paper server.");
|
||||
lore.add("§4/!\\§cCaution§4/!\\ §cYou need ProtocoLib installed and working or a newer version of this plugin for this to work.");
|
||||
lore.add("§cCurrently ProtocoLib is not detected.");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import java.util.Locale;
|
|||
*/
|
||||
public class EnchantLimitConfigGui extends AbstractEnchantConfigGui<IntSettingsGui.IntSettingFactory> {
|
||||
|
||||
private static final String SECTION_NAME = ConfigOptions.ENCHANT_LIMIT_ROOT;
|
||||
private static final String SECTION_NAME = "enchant_limits";
|
||||
|
||||
private static EnchantLimitConfigGui INSTANCE = null;
|
||||
|
||||
|
|
@ -41,34 +41,18 @@ public class EnchantLimitConfigGui extends AbstractEnchantConfigGui<IntSettingsG
|
|||
String key = enchant.getKey().toString().toLowerCase(Locale.ROOT);
|
||||
String prettyKey = CasedStringUtil.snakeToUpperSpacedCase(key.replace(":", "_"));
|
||||
|
||||
var defaultValue = enchant.defaultMaxLevel();
|
||||
|
||||
return new IntSettingsGui.IntSettingFactory(prettyKey + " Limit", this,
|
||||
SECTION_NAME + '.' + key, ConfigHolder.DEFAULT_CONFIG,
|
||||
Collections.singletonList(
|
||||
"§7Maximum applied level of " + prettyKey
|
||||
),
|
||||
-1, 255, -1,
|
||||
0, 255,
|
||||
enchant.defaultMaxLevel(),
|
||||
1, 5, 10, 50, 100){
|
||||
|
||||
@Override
|
||||
public int getConfiguredValue() {
|
||||
var value = ConfigOptions.INSTANCE.rawEnchantLimit(enchant);
|
||||
return Math.min(value, ConfigOptions.ENCHANT_LIMIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String valueDisplayName(IntSettingsGui.ValueDisplayType type, int value) {
|
||||
|
||||
if(value < 0) {
|
||||
return switch (type) {
|
||||
case CURRENT -> "Default (" + defaultValue + ")";
|
||||
case RESET -> String.valueOf(defaultValue);
|
||||
default -> "Default";
|
||||
};
|
||||
|
||||
}
|
||||
else return super.valueDisplayName(type, value);
|
||||
return ConfigOptions.INSTANCE.enchantLimit(enchant);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
|
|||
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
|
||||
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
|
||||
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
|
||||
import xyz.alexcrea.cuanvil.util.MetricsUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
|
@ -265,7 +264,6 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
|
|||
updateGuiValues();
|
||||
} catch (Exception e) {
|
||||
CustomAnvil.instance.getLogger().log(Level.WARNING, "An error occurred while updating enchants for " + this.enchantConflict, e);
|
||||
MetricsUtil.INSTANCE.trackError(e);
|
||||
}
|
||||
|
||||
// Save file configuration to disk
|
||||
|
|
@ -310,7 +308,6 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
|
|||
updateGuiValues();
|
||||
} catch (Exception e) {
|
||||
CustomAnvil.instance.getLogger().log(Level.WARNING, "An error occurred while updating group for " + this.enchantConflict, e);
|
||||
MetricsUtil.INSTANCE.trackError(e);
|
||||
}
|
||||
|
||||
// Save file configuration to disk
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import com.github.stefvanschie.inventoryframework.pane.PatternPane;
|
|||
import com.github.stefvanschie.inventoryframework.pane.util.Pattern;
|
||||
import io.delilaheve.CustomAnvil;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
|
|
@ -326,19 +325,19 @@ public class GroupConfigSubSettingGui extends MappedToListSubSettingGui implemen
|
|||
// ----------------------------
|
||||
|
||||
@Override
|
||||
public Set<NamespacedKey> getSelectedMaterials() {
|
||||
public EnumSet<Material> getSelectedMaterials() {
|
||||
return this.group.getNonGroupInheritedMaterials();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setSelectedMaterials(Set<NamespacedKey> materials) {
|
||||
public boolean setSelectedMaterials(EnumSet<Material> materials) {
|
||||
this.group.setNonGroupInheritedMaterials(materials);
|
||||
|
||||
// Write to file configuration
|
||||
String[] groupNames = new String[materials.size()];
|
||||
int index = 0;
|
||||
for (NamespacedKey otherGroup : materials) {
|
||||
groupNames[index++] = otherGroup.getKey().toLowerCase();
|
||||
for (Material otherGroup : materials) {
|
||||
groupNames[index++] = otherGroup.name().toLowerCase();
|
||||
}
|
||||
|
||||
ConfigHolder.ITEM_GROUP_HOLDER.getConfig().set(this.group.getName()+"."+ItemGroupManager.MATERIAL_LIST_PATH, groupNames);
|
||||
|
|
@ -354,8 +353,8 @@ public class GroupConfigSubSettingGui extends MappedToListSubSettingGui implemen
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<NamespacedKey> illegalMaterials() {
|
||||
return Set.of(Material.AIR.getKey());
|
||||
public EnumSet<Material> illegalMaterials() {
|
||||
return EnumSet.of(Material.AIR);
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
|
|
|
|||
|
|
@ -72,8 +72,7 @@ public class IntSettingsGui extends AbstractSettingGui {
|
|||
assert meta != null;
|
||||
|
||||
meta.setDisplayName("§eReset to default value");
|
||||
meta.setLore(Collections.singletonList("§7Default value is §e" +
|
||||
holder.valueDisplayName(ValueDisplayType.RESET, holder.defaultVal)));
|
||||
meta.setLore(Collections.singletonList("§7Default value is §e" + holder.defaultVal));
|
||||
item.setItemMeta(meta);
|
||||
returnToDefault = new GuiItem(item, event -> {
|
||||
event.setCancelled(true);
|
||||
|
|
@ -87,23 +86,41 @@ public class IntSettingsGui extends AbstractSettingGui {
|
|||
* Update item using the setting value to match the new value.
|
||||
*/
|
||||
protected void updateValueDisplay() {
|
||||
|
||||
PatternPane pane = getPane();
|
||||
|
||||
// minus item
|
||||
GuiItem minusItem;
|
||||
if (now > holder.min) {
|
||||
int planned = Math.max(holder.min, now - step);
|
||||
minusItem = valueEditItem(Material.RED_TERRACOTTA, ValueDisplayType.REMOVE, planned);
|
||||
ItemStack item = new ItemStack(Material.RED_TERRACOTTA);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
assert meta != null;
|
||||
|
||||
meta.setDisplayName("§e" + now + " §f-> §e" + planned + " §r(§c-" + (now - planned) + "§r)");
|
||||
meta.setLore(Collections.singletonList(AbstractSettingGui.CLICK_LORE));
|
||||
item.setItemMeta(meta);
|
||||
|
||||
minusItem = new GuiItem(item, updateNowConsumer(planned), CustomAnvil.instance);
|
||||
} else {
|
||||
minusItem = GuiGlobalItems.backgroundItem(Material.BARRIER);
|
||||
}
|
||||
pane.bindItem('-', minusItem);
|
||||
|
||||
//plus item
|
||||
// may do a function to generalise ?
|
||||
GuiItem plusItem;
|
||||
if (now < holder.max) {
|
||||
int planned = Math.min(holder.max, now + step);
|
||||
plusItem = valueEditItem(Material.GREEN_TERRACOTTA, ValueDisplayType.ADD, planned);
|
||||
ItemStack item = new ItemStack(Material.GREEN_TERRACOTTA);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
assert meta != null;
|
||||
|
||||
meta.setDisplayName("§e" + now + " §f-> §e" + planned + " §r(§a+" + (planned - now) + "§r)");
|
||||
meta.setLore(Collections.singletonList(AbstractSettingGui.CLICK_LORE));
|
||||
item.setItemMeta(meta);
|
||||
|
||||
plusItem = new GuiItem(item, updateNowConsumer(planned), CustomAnvil.instance);
|
||||
} else {
|
||||
plusItem = GuiGlobalItems.backgroundItem(Material.BARRIER);
|
||||
}
|
||||
|
|
@ -114,7 +131,7 @@ public class IntSettingsGui extends AbstractSettingGui {
|
|||
ItemMeta resultMeta = resultPaper.getItemMeta();
|
||||
assert resultMeta != null;
|
||||
|
||||
resultMeta.setDisplayName("§fValue: §e" + holder.valueDisplayName(ValueDisplayType.CURRENT, now));
|
||||
resultMeta.setDisplayName("§fValue: §e" + now);
|
||||
resultMeta.setLore(holder.displayLore);
|
||||
|
||||
resultPaper.setItemMeta(resultMeta);
|
||||
|
|
@ -132,21 +149,7 @@ public class IntSettingsGui extends AbstractSettingGui {
|
|||
}
|
||||
pane.bindItem('D', returnToDefault);
|
||||
|
||||
}
|
||||
|
||||
private GuiItem valueEditItem(Material mat, ValueDisplayType type, int planned) {
|
||||
ItemStack item = new ItemStack(mat);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
assert meta != null;
|
||||
|
||||
var nowDisplay = holder.valueDisplayName(type, now);
|
||||
var plannedDisplay = holder.valueDisplayName(type, planned);
|
||||
var deltaDisplay = holder.deltaDisplay(type, now, planned);
|
||||
meta.setDisplayName("§e" + nowDisplay + " §f-> §e" + plannedDisplay + " §r(§c" + deltaDisplay + "§r)");
|
||||
|
||||
meta.setLore(Collections.singletonList(AbstractSettingGui.CLICK_LORE));
|
||||
item.setItemMeta(meta);
|
||||
return new GuiItem(item, updateNowConsumer(planned), CustomAnvil.instance);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -386,23 +389,6 @@ public class IntSettingsGui extends AbstractSettingGui {
|
|||
return getItem(itemMat, CasedStringUtil.detectToUpperSpacedCase(configPath));
|
||||
}
|
||||
|
||||
protected String valueDisplayName(ValueDisplayType type, int value) {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
protected String deltaDisplay(ValueDisplayType type, int now, int planned) {
|
||||
var delta = planned - now;
|
||||
if(delta < 0) return "§c" + delta;
|
||||
else return "§a+" + delta;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum ValueDisplayType {
|
||||
ADD,
|
||||
CURRENT,
|
||||
REMOVE,
|
||||
RESET,
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import com.github.stefvanschie.inventoryframework.gui.type.util.Gui;
|
|||
import com.github.stefvanschie.inventoryframework.pane.util.Pattern;
|
||||
import io.delilaheve.CustomAnvil;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
|
|
@ -19,19 +18,18 @@ import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
|
|||
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
|
||||
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
|
||||
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
|
||||
import xyz.alexcrea.cuanvil.util.MaterialUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class MaterialSelectSettingGui extends MappedElementListConfigGui<NamespacedKey, GuiItem> {
|
||||
public class MaterialSelectSettingGui extends MappedElementListConfigGui<Material, GuiItem> {
|
||||
|
||||
private final SelectMaterialContainer selector;
|
||||
private final Gui backGui;
|
||||
private boolean instantRemove;
|
||||
|
||||
private final List<NamespacedKey> defaultMaterials;
|
||||
private final Set<NamespacedKey> illegalMaterials;
|
||||
private final List<Material> defaultMaterials;
|
||||
private final EnumSet<Material> illegalMaterials;
|
||||
private final int defaultMaterialHash;
|
||||
private int nowMaterialHash;
|
||||
|
||||
|
|
@ -163,7 +161,8 @@ public class MaterialSelectSettingGui extends MappedElementListConfigGui<Namespa
|
|||
|
||||
|
||||
// Save setting
|
||||
Set<NamespacedKey> result = new HashSet<>(this.elementGuiMap.keySet());
|
||||
EnumSet<Material> result = EnumSet.noneOf(Material.class);
|
||||
result.addAll(this.elementGuiMap.keySet());
|
||||
|
||||
if(!this.selector.setSelectedMaterials(result)){
|
||||
player.sendMessage("§cSomething went wrong while saving the change of value.");
|
||||
|
|
@ -186,8 +185,8 @@ public class MaterialSelectSettingGui extends MappedElementListConfigGui<Namespa
|
|||
ItemStack cursor = player.getItemOnCursor();
|
||||
|
||||
// Test if cursor material allowed
|
||||
NamespacedKey cursorMat = MaterialUtil.INSTANCE.getCustomType(cursor);
|
||||
if(MaterialUtil.INSTANCE.isAir(cursorMat)) return;
|
||||
Material cursorMat = cursor.getType();
|
||||
if(cursorMat.isAir()) return;
|
||||
if(this.illegalMaterials.contains(cursorMat)) return;
|
||||
|
||||
// Update gui only if item did not exist before.
|
||||
|
|
@ -202,12 +201,12 @@ public class MaterialSelectSettingGui extends MappedElementListConfigGui<Namespa
|
|||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack createItemForGeneric(NamespacedKey material) {
|
||||
ItemStack item = new ItemStack(Objects.requireNonNull(MaterialUtil.INSTANCE.getMatFromKey(material)));
|
||||
protected ItemStack createItemForGeneric(Material material) {
|
||||
ItemStack item = new ItemStack(material);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
|
||||
if(meta == null) return item;
|
||||
meta.setDisplayName("§a" + CasedStringUtil.snakeToUpperSpacedCase(material.getKey().toLowerCase()));
|
||||
meta.setDisplayName("§a" + CasedStringUtil.snakeToUpperSpacedCase(material.name().toLowerCase()));
|
||||
meta.setLore(Collections.singletonList("§7Click here to remove this material from the list"));
|
||||
meta.addItemFlags(ItemFlag.values());
|
||||
|
||||
|
|
@ -217,22 +216,22 @@ public class MaterialSelectSettingGui extends MappedElementListConfigGui<Namespa
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Collection<NamespacedKey> getEveryDisplayableInstanceOfGeneric() {
|
||||
protected Collection<Material> getEveryDisplayableInstanceOfGeneric() {
|
||||
return this.defaultMaterials;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateElement(NamespacedKey material, GuiItem element) {
|
||||
protected void updateElement(Material material, GuiItem element) {
|
||||
// Nothing happen here I think
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GuiItem newElementRequested(NamespacedKey material, GuiItem newItem) {
|
||||
protected GuiItem newElementRequested(Material material, GuiItem newItem) {
|
||||
newItem.setAction(event -> {
|
||||
if(this.instantRemove){
|
||||
removeMaterial(material);
|
||||
}else {
|
||||
String materialName = CasedStringUtil.snakeToUpperSpacedCase(material.getKey().toLowerCase());
|
||||
String materialName = CasedStringUtil.snakeToUpperSpacedCase(material.name().toLowerCase());
|
||||
|
||||
// Create and show confirm remove gui.
|
||||
ConfirmActionGui confirmGui = new ConfirmActionGui(
|
||||
|
|
@ -251,7 +250,7 @@ public class MaterialSelectSettingGui extends MappedElementListConfigGui<Namespa
|
|||
return newItem;
|
||||
}
|
||||
|
||||
private void removeMaterial(NamespacedKey material) {
|
||||
private void removeMaterial(Material material) {
|
||||
if(this.elementGuiMap.containsKey(material)){
|
||||
this.nowMaterialHash ^= material.hashCode();
|
||||
setSaveItem();
|
||||
|
|
@ -261,18 +260,18 @@ public class MaterialSelectSettingGui extends MappedElementListConfigGui<Namespa
|
|||
}
|
||||
|
||||
@Override
|
||||
protected GuiItem findItemFromElement(NamespacedKey generic, GuiItem element) {
|
||||
protected GuiItem findItemFromElement(Material generic, GuiItem element) {
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GuiItem findGuiItemForRemoval(NamespacedKey generic, GuiItem element) {
|
||||
protected GuiItem findGuiItemForRemoval(Material generic, GuiItem element) {
|
||||
return element;
|
||||
}
|
||||
|
||||
private static int hashFromMaterialList(List<NamespacedKey> materialList){
|
||||
private static int hashFromMaterialList(List<Material> materialList){
|
||||
int defaultMaterialHash = 0;
|
||||
for (NamespacedKey material : materialList) {
|
||||
for (Material material : materialList) {
|
||||
defaultMaterialHash ^= material.hashCode();
|
||||
}
|
||||
return defaultMaterialHash;
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@ import org.bukkit.entity.HumanEntity;
|
|||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.alexcrea.cuanvil.anvil.AnvilUseType;
|
||||
import xyz.alexcrea.cuanvil.config.ConfigHolder;
|
||||
import xyz.alexcrea.cuanvil.config.WorkPenaltyType;
|
||||
import xyz.alexcrea.cuanvil.gui.config.global.BasicConfigGui;
|
||||
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
|
||||
import xyz.alexcrea.cuanvil.util.AnvilUseType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
|
|
|
|||
|
|
@ -1,214 +0,0 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2025 Clickism
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package xyz.alexcrea.cuanvil.update;
|
||||
|
||||
import com.google.gson.*;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Utility class to check for newer versions of a project hosted on Modrinth.
|
||||
*/
|
||||
public class ModrinthUpdateChecker {
|
||||
|
||||
private static final String API_URL = "https://api.modrinth.com/v2/project/{id}/version";
|
||||
|
||||
private final String projectId;
|
||||
private final String loader;
|
||||
@Nullable
|
||||
private final String minecraftVersion;
|
||||
|
||||
@Nullable
|
||||
private Boolean featured = null;
|
||||
|
||||
@Nullable
|
||||
public Consumer<Exception> onError = null;
|
||||
@Nullable
|
||||
public Function<String, String> getRawVersion = ModrinthUpdateChecker::getRawVersion;
|
||||
|
||||
/**
|
||||
* Create a new update checker for the given project.
|
||||
* This will check the latest version for the given loader and any minecraft version.
|
||||
*
|
||||
* @param projectId the project ID
|
||||
* @param loader the loader
|
||||
*/
|
||||
public ModrinthUpdateChecker(String projectId, String loader) {
|
||||
this(projectId, loader, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new update checker for the given project.
|
||||
* This will check the latest version for the given loader and minecraft version.
|
||||
*
|
||||
* @param projectId the project ID
|
||||
* @param loader the loader
|
||||
* @param minecraftVersion the minecraft version, or null for any version
|
||||
*/
|
||||
public ModrinthUpdateChecker(String projectId, String loader, @Nullable String minecraftVersion) {
|
||||
this.projectId = projectId;
|
||||
this.loader = loader;
|
||||
this.minecraftVersion = minecraftVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the latest version of the project for the given loader and minecraft version
|
||||
* and call the consumer with it.
|
||||
*
|
||||
* @param consumer the consumer
|
||||
*/
|
||||
public void checkVersion(Consumer<String> consumer) {
|
||||
try {
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(prepareURI())
|
||||
.GET()
|
||||
.build();
|
||||
|
||||
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
|
||||
.thenAcceptAsync(response -> {
|
||||
if (response.statusCode() != 200) {
|
||||
if(onError != null)
|
||||
onError.accept(new RuntimeException("wrong response status code: " + response.statusCode()));
|
||||
return;
|
||||
}
|
||||
JsonArray versionsArray = JsonParser.parseString(response.body()).getAsJsonArray();
|
||||
String latestVersion = getLatestVersion(versionsArray);
|
||||
if (latestVersion == null) {
|
||||
if(onError != null)
|
||||
onError.accept(new RuntimeException("latest version is null"));
|
||||
return;
|
||||
}
|
||||
consumer.accept(latestVersion);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
if(onError != null) onError.accept(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest compatible version from the versions array.
|
||||
*
|
||||
* @param versions the versions array
|
||||
* @return the latest compatible version
|
||||
*/
|
||||
@Nullable
|
||||
protected String getLatestVersion(JsonArray versions) {
|
||||
return versions.asList().stream().findFirst()
|
||||
.map(JsonElement::getAsJsonObject)
|
||||
.map(version -> version.get("version_number").getAsString())
|
||||
.map(getRawVersion != null ? getRawVersion : (v -> v))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the raw version from a version string.
|
||||
* i.E: "fabric-1.2+1.17.1" -> "1.2"
|
||||
*
|
||||
* @param version the version string
|
||||
* @return the raw version string
|
||||
*/
|
||||
public static String getRawVersion(String version) {
|
||||
if (version.isEmpty()) return version;
|
||||
version = version.replaceAll("^\\D+", "");
|
||||
String[] split = version.split("\\+");
|
||||
return split[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare this request uri based on current parameters.
|
||||
* @return the request uri
|
||||
*/
|
||||
private URI prepareURI() {
|
||||
var url = new StringBuilder(API_URL.replace("{id}", projectId));
|
||||
|
||||
var parameters = prepareParameters();
|
||||
String[] paramArray = new String[parameters.size()];
|
||||
int i = 0;
|
||||
for (Map.Entry<String, String> entry : parameters.entrySet()) {
|
||||
paramArray[i++] = entry.getKey() + '=' + entry.getValue();
|
||||
}
|
||||
url.append('?').append(String.join("&", paramArray));
|
||||
|
||||
return URI.create(url.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parameters for the version request.
|
||||
*
|
||||
* @return a map of key-value map of the request parameters
|
||||
*/
|
||||
private Map<String, String> prepareParameters(){
|
||||
var parameters = new HashMap<String, String>();
|
||||
|
||||
parameters.put("loaders", List.of(loader).toString());
|
||||
if(minecraftVersion != null) parameters.put("game_versions", List.of(minecraftVersion).toString());
|
||||
if(featured != null) parameters.put("featured", featured.toString());
|
||||
|
||||
parameters.put("include_changelog", "false");
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only get featured or non-featured versions.
|
||||
* Null represent no filter.
|
||||
* @param featured should be restricted to featured version ? default null if not called
|
||||
* @return this
|
||||
*/
|
||||
public ModrinthUpdateChecker setFeatured(@Nullable Boolean featured) {
|
||||
this.featured = featured;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function called on error calling the api.
|
||||
* @param onError What should happen on error
|
||||
* @return this
|
||||
*/
|
||||
public ModrinthUpdateChecker setOnError(@Nullable Consumer<Exception> onError) {
|
||||
this.onError = onError;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the function to get raw version from the modrinth version.
|
||||
* If null provided raw version will act as in the identity function.
|
||||
* @param getRawVersion The function transforming modrinth version to raw version
|
||||
* @return this
|
||||
*/
|
||||
public ModrinthUpdateChecker setGetRawVersion(@Nullable Function<String, String> getRawVersion) {
|
||||
this.getRawVersion = getRawVersion;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@ import io.delilaheve.util.ConfigOptions;
|
|||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.alexcrea.cuanvil.config.ConfigHolder;
|
||||
import xyz.alexcrea.cuanvil.util.MetricType;
|
||||
import xyz.alexcrea.cuanvil.util.config.LoreEditConfigUtil;
|
||||
import xyz.alexcrea.cuanvil.util.config.LoreEditType;
|
||||
|
||||
|
|
@ -19,9 +18,6 @@ public class PluginSetDefault {
|
|||
|
||||
int nbSet = 0;
|
||||
|
||||
nbSet += trySetDefault(config, METRIC_TYPE, MetricType.AUTO.getValue());
|
||||
nbSet += trySetDefault(config, METRIC_COLLECT_ERROR, true);
|
||||
|
||||
nbSet += trySetDefault(config, CAP_ANVIL_COST, DEFAULT_CAP_ANVIL_COST);
|
||||
nbSet += trySetDefault(config, MAX_ANVIL_COST, DEFAULT_MAX_ANVIL_COST);
|
||||
nbSet += trySetDefault(config, REMOVE_ANVIL_COST_LIMIT, DEFAULT_REMOVE_ANVIL_COST_LIMIT);
|
||||
|
|
@ -34,7 +30,7 @@ public class PluginSetDefault {
|
|||
nbSet += trySetDefault(config, ALLOW_HEXADECIMAL_COLOR, DEFAULT_ALLOW_HEXADECIMAL_COLOR);
|
||||
nbSet += trySetDefault(config, PERMISSION_NEEDED_FOR_COLOR, DEFAULT_PERMISSION_NEEDED_FOR_COLOR);
|
||||
nbSet += trySetDefault(config, USE_OF_COLOR_COST, DEFAULT_USE_OF_COLOR_COST);
|
||||
nbSet += trySetDefault(config, PER_COLOR_CODE_PERMISSION, DEFAULT_PER_COLOR_CODE_PERMISSION);
|
||||
nbSet += trySetDefault(config, DEFAULT_LIMIT_PATH, DEFAULT_ENCHANT_LIMIT);
|
||||
|
||||
// Lore Edit defaults
|
||||
for (@NotNull LoreEditType value : LoreEditType.values()) {
|
||||
|
|
@ -61,11 +57,6 @@ public class PluginSetDefault {
|
|||
|
||||
nbSet += trySetDefault(config, PAPER_EDIT_ORDER, DEFAULT_PAPER_EDIT_ORDER);
|
||||
|
||||
nbSet += trySetDefault(config, DIALOG_RENAME_ENABLED, DEFAULT_DIALOG_RENAME_ENABLED);
|
||||
nbSet += trySetDefault(config, DIALOG_MAX_SIZE, DEFAULT_DIALOG_MAX_SIZE);
|
||||
nbSet += trySetDefault(config, DIALOG_RENAME_USE_PERMISSION, DEFAULT_DIALOG_RENAME_USE_PERMISSION);
|
||||
nbSet += trySetDefault(config, DIALOG_KEEP_USER_TEXT, DEFAULT_DIALOG_KEEP_USER_TEXT);
|
||||
|
||||
if (nbSet > 0) {
|
||||
CustomAnvil.instance.getLogger().info("Adding " + nbSet + " absent default config values.");
|
||||
ConfigHolder.DEFAULT_CONFIG.saveToDisk(true);
|
||||
|
|
|
|||
|
|
@ -77,12 +77,6 @@ public class UpdateHandler {
|
|||
if (hadUpdate) {
|
||||
CustomAnvil.instance.getLogger().info("Updating Done !");
|
||||
}
|
||||
|
||||
if(current.major() == 1 && current.minor() < 21) {
|
||||
var logger = CustomAnvil.instance.getLogger();
|
||||
logger.warning("Your are running an old version of minecraft (lower than 1.21)");
|
||||
logger.warning("Custom Anvil will stop supporting this version on the first of july 2026");
|
||||
}
|
||||
}
|
||||
|
||||
private static void finishConfiguration(@Nonnull String newVersion, @Nonnull Set<ConfigHolder> toSave) {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,22 @@ public class UpdateUtils {
|
|||
return Version.fromString(versionString);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static int[] currentMinecraftVersionArray() {
|
||||
String versionString = Bukkit.getServer().getBukkitVersion().split("-")[0];
|
||||
return UpdateUtils.readVersionFromString(versionString);
|
||||
}
|
||||
|
||||
public static int[] readVersionFromString(String versionString) {
|
||||
String[] partialVersion = versionString.split("\\.");
|
||||
int[] versionParts = new int[]{0, 0, 0};
|
||||
|
||||
for (int i = 0; i < Math.min(3, partialVersion.length); i++) {
|
||||
versionParts[i] = Integer.parseInt(partialVersion[i]);
|
||||
}
|
||||
return versionParts;
|
||||
}
|
||||
|
||||
public static void addToStringList(FileConfiguration config, String path, String... toAdd) {
|
||||
List<String> groups = new ArrayList<>(config.getStringList(path));
|
||||
groups.addAll(Arrays.asList(toAdd));
|
||||
|
|
|
|||
|
|
@ -21,11 +21,7 @@ public record Version(int major, int minor, int patch) {
|
|||
int[] versionParts = new int[]{0, 0, 0};
|
||||
|
||||
for (int i = 0; i < Math.min(3, partialVersion.length); i++) {
|
||||
try {
|
||||
versionParts[i] = Integer.parseInt(partialVersion[i]);
|
||||
} catch (NumberFormatException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return new Version(versionParts[0], versionParts[1], versionParts[2]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package xyz.alexcrea.cuanvil.update.plugin;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
|
@ -12,7 +11,6 @@ import xyz.alexcrea.cuanvil.group.AbstractMaterialGroup;
|
|||
import xyz.alexcrea.cuanvil.group.IncludeGroup;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
|
@ -71,12 +69,7 @@ public class PUpdate_1_11_0 {
|
|||
|
||||
// Create new group
|
||||
IncludeGroup group = new IncludeGroup(toolset);
|
||||
NamespacedKey[] keys = new NamespacedKey[toolMats.length];
|
||||
for (int i = 0; i < toolMats.length; i++) {
|
||||
keys[i] = toolMats[i].getKey();
|
||||
}
|
||||
|
||||
group.addAll(keys);
|
||||
group.addAll(toolMats);
|
||||
|
||||
MaterialGroupApi.addMaterialGroup(group, true);
|
||||
|
||||
|
|
@ -84,8 +77,8 @@ public class PUpdate_1_11_0 {
|
|||
if (tools == null) return;
|
||||
if (!(tools instanceof IncludeGroup include)) return;
|
||||
|
||||
List<NamespacedKey> mats = List.of(keys);
|
||||
Set<NamespacedKey> matSet = include.getNonGroupInheritedMaterials();
|
||||
List<Material> mats = List.of(toolMats);
|
||||
Set<Material> matSet = include.getNonGroupInheritedMaterials();
|
||||
if (!matSet.containsAll(mats)) return;
|
||||
|
||||
mats.forEach(matSet::remove);
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ package xyz.alexcrea.cuanvil.update.plugin;
|
|||
|
||||
import io.delilaheve.util.ConfigOptions;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import xyz.alexcrea.cuanvil.anvil.AnvilUseType;
|
||||
import xyz.alexcrea.cuanvil.config.ConfigHolder;
|
||||
import xyz.alexcrea.cuanvil.config.WorkPenaltyType;
|
||||
import xyz.alexcrea.cuanvil.gui.config.settings.WorkPenaltyTypeSettingGui;
|
||||
import xyz.alexcrea.cuanvil.util.AnvilUseType;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.EnumMap;
|
||||
|
|
|
|||
|
|
@ -6,13 +6,10 @@ import org.bukkit.configuration.file.YamlConfiguration
|
|||
import org.bukkit.plugin.java.JavaPlugin
|
||||
import xyz.alexcrea.cuanvil.api.event.CAConfigReadyEvent
|
||||
import xyz.alexcrea.cuanvil.api.event.CAEnchantRegistryReadyEvent
|
||||
import xyz.alexcrea.cuanvil.command.CustomAnvilCommand
|
||||
import xyz.alexcrea.cuanvil.command.EditConfigExecutor
|
||||
import xyz.alexcrea.cuanvil.command.ReloadExecutor
|
||||
import xyz.alexcrea.cuanvil.config.ConfigHolder
|
||||
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
||||
import xyz.alexcrea.cuanvil.dependency.MinecraftVersionUtil
|
||||
import xyz.alexcrea.cuanvil.dependency.economy.EconomyManager
|
||||
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil
|
||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry
|
||||
import xyz.alexcrea.cuanvil.gui.config.MainConfigGui
|
||||
|
|
@ -21,10 +18,9 @@ import xyz.alexcrea.cuanvil.listener.AnvilCloseListener
|
|||
import xyz.alexcrea.cuanvil.listener.AnvilResultListener
|
||||
import xyz.alexcrea.cuanvil.listener.ChatEventListener
|
||||
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener
|
||||
import xyz.alexcrea.cuanvil.update.ModrinthUpdateChecker
|
||||
import xyz.alexcrea.cuanvil.update.PluginSetDefault
|
||||
import xyz.alexcrea.cuanvil.update.UpdateHandler
|
||||
import xyz.alexcrea.cuanvil.util.MetricsUtil
|
||||
import xyz.alexcrea.cuanvil.util.Metrics
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.util.logging.Level
|
||||
|
|
@ -35,8 +31,8 @@ import java.util.logging.Level
|
|||
open class CustomAnvil : JavaPlugin() {
|
||||
|
||||
companion object {
|
||||
// pluginIDS
|
||||
private const val modrinthPluginID = "S75Ueiq9"
|
||||
// bstats plugin id
|
||||
private const val bstatsPluginId = 20923
|
||||
|
||||
// Permission string required to use the plugin's features
|
||||
const val affectedByPluginPermission = "ca.affected"
|
||||
|
|
@ -50,13 +46,9 @@ open class CustomAnvil : JavaPlugin() {
|
|||
// Permission string required to reload the config
|
||||
const val commandReloadPermission = "ca.command.reload"
|
||||
|
||||
// Permission string required to get diagnostic data
|
||||
const val diagnosticPermission = "ca.command.diagnostic"
|
||||
|
||||
// Permission string required to edit the plugin's config
|
||||
const val editConfigPermission = "ca.config.edit"
|
||||
|
||||
|
||||
// Command Name to reload the config
|
||||
const val commandReloadName = "anvilconfigreload"
|
||||
|
||||
|
|
@ -69,8 +61,6 @@ open class CustomAnvil : JavaPlugin() {
|
|||
// Chat message listener
|
||||
lateinit var chatListener: ChatEventListener
|
||||
|
||||
var latestVer: String? = null
|
||||
|
||||
/**
|
||||
* Logging handler
|
||||
*/
|
||||
|
|
@ -91,99 +81,12 @@ open class CustomAnvil : JavaPlugin() {
|
|||
|
||||
}
|
||||
|
||||
// stop plugin if we do not force a dirty start (true by default)
|
||||
// Return true if start was stopped
|
||||
private fun tryDirtyStart(): Boolean {
|
||||
if(!ConfigHolder.DEFAULT_CONFIG.config.getBoolean("dirty_start", false)) {
|
||||
Bukkit.getPluginManager().disablePlugin(this)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// stop plugin if we force a safe start (false by default)
|
||||
// Return true if start was stopped
|
||||
private fun trySafeStart(): Boolean {
|
||||
if(ConfigHolder.DEFAULT_CONFIG.config.getBoolean("safe_start", false)) {
|
||||
Bukkit.getPluginManager().disablePlugin(this)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup plugin for use
|
||||
*/
|
||||
override fun onEnable() {
|
||||
instance = this
|
||||
try {
|
||||
legacyCheck()
|
||||
} catch (e: Exception) {
|
||||
logger.log(Level.SEVERE, "error trying to check for legacy system", e)
|
||||
MetricsUtil.trackError(e)
|
||||
if(trySafeStart()) return
|
||||
}
|
||||
|
||||
// Add commands
|
||||
try {
|
||||
prepareCommand()
|
||||
} catch (e: Exception) {
|
||||
logger.log(Level.SEVERE, "error trying to register commands", e)
|
||||
MetricsUtil.trackError(e)
|
||||
if(trySafeStart()) return
|
||||
}
|
||||
|
||||
// Load default configuration
|
||||
try {
|
||||
if(!ConfigHolder.loadDefaultConfig())
|
||||
throw RuntimeException("Error loading configuration file")
|
||||
} catch (e: Exception) {
|
||||
logger.log(Level.SEVERE, "error occurred loading default configuration", e)
|
||||
MetricsUtil.trackError(e)
|
||||
if(tryDirtyStart()) return
|
||||
}
|
||||
|
||||
// Load dependency
|
||||
try {
|
||||
DependencyManager.loadDependency()
|
||||
} catch (e: Exception) {
|
||||
logger.log(Level.SEVERE, "error loading dependency compatibility", e)
|
||||
MetricsUtil.trackError(e)
|
||||
if(tryDirtyStart()) return
|
||||
}
|
||||
|
||||
// Register listeners
|
||||
try {
|
||||
registerListeners()
|
||||
} catch (e: Exception) {
|
||||
logger.log(Level.SEVERE, "error registering listeners", e)
|
||||
MetricsUtil.trackError(e)
|
||||
if(tryDirtyStart()) return
|
||||
}
|
||||
|
||||
// Load metrics
|
||||
MetricsUtil.loadMetrics(this)
|
||||
|
||||
// Load other thing later.
|
||||
// It is so other dependent plugins can implement there event listener before we fire them.
|
||||
DependencyManager.scheduler.scheduleGlobally(this) { loadEnchantmentSystemDirty() }
|
||||
}
|
||||
|
||||
override fun onDisable() {
|
||||
MetricsUtil.shutdownMetrics()
|
||||
}
|
||||
|
||||
private fun loadEnchantmentSystemDirty() {
|
||||
try {
|
||||
loadEnchantmentSystem()
|
||||
} catch (e: Exception) {
|
||||
logger.log(Level.SEVERE, "error initializing enchantment system", e)
|
||||
MetricsUtil.trackError(e)
|
||||
tryDirtyStart()
|
||||
}
|
||||
}
|
||||
|
||||
private fun legacyCheck() {
|
||||
// Disable old plugin name if exist
|
||||
val potentialPlugin = Bukkit.getPluginManager().getPlugin("UnsafeEnchantsPlus")
|
||||
if (potentialPlugin != null) {
|
||||
|
|
@ -192,43 +95,38 @@ open class CustomAnvil : JavaPlugin() {
|
|||
logger.warning("Please note CustomAnvil is a more recent version of UnsafeEnchantsPlus")
|
||||
}
|
||||
|
||||
val isPaper = PlatformUtil.isPaper
|
||||
if(!isPaper) {
|
||||
if(!PlatformUtil.isPaper) {
|
||||
logger.warning("It seems you are using spigot")
|
||||
logger.warning("Please take notice that spigot is less supported than paper and derivatives")
|
||||
if(MinecraftVersionUtil.isTooNewForSpigot) {
|
||||
logger.warning("If replace too expensive is not working this is likely because of spigot")
|
||||
logger.warning("As native nms is not supported for spigot starting 26.1")
|
||||
}
|
||||
}
|
||||
|
||||
val loader = if(isPaper) "paper" else "spigot"
|
||||
// Add commands
|
||||
prepareCommand()
|
||||
|
||||
val version = description.version
|
||||
val featured = if(version.contains("dev")) null else true
|
||||
|
||||
ModrinthUpdateChecker(modrinthPluginID, loader, null)
|
||||
.setFeatured(featured)
|
||||
.setOnError {
|
||||
logger.log(Level.WARNING, "error trying to fetch latest update", it)
|
||||
}
|
||||
.checkVersion { latestVer: String? ->
|
||||
CustomAnvil.latestVer = latestVer
|
||||
if(latestVer == null || version.contains(latestVer)) return@checkVersion
|
||||
|
||||
logger.warning("An update may be available: $latestVer")
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerListeners() {
|
||||
// Register chat listener
|
||||
// Load chat listener
|
||||
chatListener = ChatEventListener()
|
||||
server.pluginManager.registerEvents(chatListener, this)
|
||||
|
||||
// Load default configuration
|
||||
if (!ConfigHolder.loadDefaultConfig()) {
|
||||
logger.log(Level.SEVERE,"could not load default config.")
|
||||
return
|
||||
}
|
||||
|
||||
// Load dependency
|
||||
DependencyManager.loadDependency()
|
||||
|
||||
// Register anvil events
|
||||
server.pluginManager.registerEvents(PrepareAnvilListener(), this)
|
||||
server.pluginManager.registerEvents(AnvilResultListener(), this)
|
||||
server.pluginManager.registerEvents(AnvilCloseListener(DependencyManager.packetManager), this)
|
||||
|
||||
// Load metrics
|
||||
Metrics(this, bstatsPluginId)
|
||||
|
||||
// Load other thing later.
|
||||
// It is so other dependent plugins can implement there event listener before we fire them.
|
||||
DependencyManager.scheduler.scheduleGlobally(this, {loadEnchantmentSystem()})
|
||||
}
|
||||
|
||||
private fun loadEnchantmentSystem(){
|
||||
|
|
@ -241,8 +139,7 @@ open class CustomAnvil : JavaPlugin() {
|
|||
|
||||
// Load config
|
||||
if (!ConfigHolder.loadNonDefaultConfig()) {
|
||||
logger.log(Level.SEVERE,"Plugin has an issue while trying to load non default config... exiting...")
|
||||
server.pluginManager.disablePlugin(this)
|
||||
logger.log(Level.SEVERE,"could not load non default config.")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -260,11 +157,9 @@ open class CustomAnvil : JavaPlugin() {
|
|||
MainConfigGui.getInstance().init(DependencyManager.packetManager)
|
||||
GuiSharedConstant.loadConstants()
|
||||
|
||||
// Prepare economy if possible
|
||||
EconomyManager.setupEconomy(this)
|
||||
|
||||
// Finally, re add default we may be missing
|
||||
PluginSetDefault.reAddMissingDefault()
|
||||
|
||||
}
|
||||
|
||||
fun reloadResource(
|
||||
|
|
@ -316,8 +211,6 @@ open class CustomAnvil : JavaPlugin() {
|
|||
|
||||
command = getCommand(commandConfigName)
|
||||
command?.setExecutor(EditConfigExecutor())
|
||||
|
||||
CustomAnvilCommand(this)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,17 +2,14 @@ package io.delilaheve.util
|
|||
|
||||
import io.delilaheve.CustomAnvil
|
||||
import io.delilaheve.util.EnchantmentUtil.enchantmentName
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.NamespacedKey
|
||||
import org.bukkit.entity.HumanEntity
|
||||
import xyz.alexcrea.cuanvil.anvil.AnvilUseType
|
||||
import xyz.alexcrea.cuanvil.config.ConfigHolder
|
||||
import xyz.alexcrea.cuanvil.config.WorkPenaltyType
|
||||
import xyz.alexcrea.cuanvil.config.WorkPenaltyType.WorkPenaltyPart
|
||||
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
||||
import xyz.alexcrea.cuanvil.dependency.economy.EconomyManager
|
||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
|
||||
import xyz.alexcrea.cuanvil.util.dialog.AnvilRenameDialogUtil
|
||||
import java.math.BigDecimal
|
||||
import xyz.alexcrea.cuanvil.util.AnvilUseType
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
|
|
@ -24,9 +21,6 @@ object ConfigOptions {
|
|||
// Path for config values
|
||||
// ----------------------
|
||||
|
||||
const val METRIC_TYPE = "metric_type"
|
||||
const val METRIC_COLLECT_ERROR = "metric_collect_errors"
|
||||
|
||||
const val CAP_ANVIL_COST = "limit_repair_cost"
|
||||
const val MAX_ANVIL_COST = "limit_repair_value"
|
||||
const val REMOVE_ANVIL_COST_LIMIT = "remove_repair_limit"
|
||||
|
|
@ -48,8 +42,6 @@ object ConfigOptions {
|
|||
const val PERMISSION_NEEDED_FOR_COLOR = "permission_needed_for_color"
|
||||
const val USE_OF_COLOR_COST = "use_of_color_cost"
|
||||
|
||||
const val PER_COLOR_CODE_PERMISSION = "per_color_code_permission"
|
||||
|
||||
// Work penalty config
|
||||
const val WORK_PENALTY_ROOT = "work_penalty"
|
||||
const val WORK_PENALTY_INCREASE = "shared_increase"
|
||||
|
|
@ -62,25 +54,15 @@ object ConfigOptions {
|
|||
const val ENCHANT_COUNT_LIMIT_DEFAULT = "$ENCHANT_COUNT_LIMIT_ROOT.default"
|
||||
const val ENCHANT_COUNT_LIMIT_ITEMS = "$ENCHANT_COUNT_LIMIT_ROOT.items"
|
||||
|
||||
const val DEFAULT_LIMIT_PATH = "default_limit"
|
||||
|
||||
const val ENCHANT_LIMIT_ROOT = "enchant_limits"
|
||||
const val ENCHANT_VALUES_ROOT = "enchant_values"
|
||||
|
||||
// Dialog menu rename
|
||||
const val DIALOG_RENAME_ENABLED = "enable_dialog_rename"
|
||||
const val DIALOG_MAX_SIZE = "dialog_rename_max_size"
|
||||
const val DIALOG_RENAME_USE_PERMISSION = "permission_needed_for_dialog_rename"
|
||||
const val DIALOG_KEEP_USER_TEXT = "dialog_rename_keep_user_text"
|
||||
|
||||
// Others
|
||||
const val DISABLE_MERGE_OVER_ROOT = "disable-merge-over"
|
||||
|
||||
const val IMMUTABLE_ENCHANTMENT_LIST = "immutable_enchantments"
|
||||
|
||||
// Monetary configs
|
||||
const val MONETARY_USAGE_ROOT = "monetary_cost"
|
||||
const val SHOULD_USE_MONEY = "$MONETARY_USAGE_ROOT.enabled"
|
||||
const val MONEY_CURRENCY = "$MONETARY_USAGE_ROOT.currency"
|
||||
const val MONETARY_MULTIPLIER_ROOT = "$MONETARY_USAGE_ROOT.multipliers"
|
||||
|
||||
// Keys for specific enchantment values
|
||||
private const val KEY_BOOK = "book"
|
||||
|
|
@ -117,23 +99,12 @@ object ConfigOptions {
|
|||
const val DEFAULT_PERMISSION_NEEDED_FOR_COLOR = true
|
||||
const val DEFAULT_USE_OF_COLOR_COST = 0
|
||||
|
||||
const val DEFAULT_PER_COLOR_CODE_PERMISSION = false
|
||||
|
||||
// Monetary configs
|
||||
const val DEFAULT_SHOULD_USE_MONEY = false
|
||||
const val DEFAULT_MONEY_CURRENCY = "default"
|
||||
const val DEFAULT_MONEY_MULTIPLIER = 1.0
|
||||
const val DEFAULT_ENCHANT_LIMIT = 5
|
||||
|
||||
// Debug flag
|
||||
private const val DEFAULT_DEBUG_LOG = false
|
||||
private const val DEFAULT_VERBOSE_DEBUG_LOG = false
|
||||
|
||||
// Dialog menu rename
|
||||
const val DEFAULT_DIALOG_RENAME_ENABLED = false
|
||||
const val DEFAULT_DIALOG_MAX_SIZE = 256
|
||||
const val DEFAULT_DIALOG_RENAME_USE_PERMISSION = false
|
||||
const val DEFAULT_DIALOG_KEEP_USER_TEXT = true
|
||||
|
||||
// -------------
|
||||
// Config Ranges
|
||||
// -------------
|
||||
|
|
@ -158,11 +129,9 @@ object ConfigOptions {
|
|||
@JvmField
|
||||
val USE_OF_COLOR_COST_RANGE = 0..1000
|
||||
|
||||
@JvmField
|
||||
val DIALOG_MAX_SIZE_RANGE = 0..Int.MAX_VALUE
|
||||
|
||||
// Valid range for an enchantment limit
|
||||
const val ENCHANT_LIMIT = 255
|
||||
@JvmField
|
||||
val ENCHANT_LIMIT_RANGE = 1..255
|
||||
|
||||
// Valid range for an enchantment count limit
|
||||
@JvmField
|
||||
|
|
@ -178,11 +147,6 @@ object ConfigOptions {
|
|||
// Default max before merge disabled (negative mean enabled)
|
||||
const val DEFAULT_MAX_BEFORE_MERGE_DISABLED = -1
|
||||
|
||||
// -----------
|
||||
// Permissions
|
||||
// -----------
|
||||
private const val RENAME_DIALOG_PERMISSION = "ca.rename.dialog"
|
||||
|
||||
// -------------
|
||||
// Get methods
|
||||
// -------------
|
||||
|
|
@ -335,16 +299,6 @@ object ConfigOptions {
|
|||
.getBoolean(PERMISSION_NEEDED_FOR_COLOR, DEFAULT_PERMISSION_NEEDED_FOR_COLOR)
|
||||
}
|
||||
|
||||
/**
|
||||
* Should each color code require a permission
|
||||
*/
|
||||
val usePerColorCodePermission: Boolean
|
||||
get() {
|
||||
return ConfigHolder.DEFAULT_CONFIG
|
||||
.config
|
||||
.getBoolean(PER_COLOR_CODE_PERMISSION, DEFAULT_PER_COLOR_CODE_PERMISSION)
|
||||
}
|
||||
|
||||
/**
|
||||
* How many xp should use of color should cost
|
||||
*/
|
||||
|
|
@ -391,12 +345,22 @@ object ConfigOptions {
|
|||
return WorkPenaltyPart(penaltyIncrease, penaltyAdditive, exclusivePenaltyIncrease, exclusivePenaltyAdditive)
|
||||
}
|
||||
|
||||
/**
|
||||
* Default enchantment limit
|
||||
*/
|
||||
private val defaultEnchantLimit: Int
|
||||
get() {
|
||||
return ConfigHolder.DEFAULT_CONFIG
|
||||
.config
|
||||
.getInt(DEFAULT_LIMIT_PATH, DEFAULT_ENCHANT_LIMIT)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get material enchantment count limit
|
||||
*
|
||||
* @return the current enchantment limit. -1 if none
|
||||
*/
|
||||
fun getEnchantCountLimit(type: NamespacedKey): Int? {
|
||||
fun getEnchantCountLimit(type: Material): Int? {
|
||||
val limit = materialEnchantCountLimit(type)
|
||||
|
||||
if(limit != null) return limit
|
||||
|
|
@ -410,8 +374,8 @@ object ConfigOptions {
|
|||
*
|
||||
* @return The current enchantment limit. -1 if none
|
||||
*/
|
||||
private fun materialEnchantCountLimit(type: NamespacedKey): Int? {
|
||||
val path = "$ENCHANT_COUNT_LIMIT_ITEMS.${type.key.lowercase()}"
|
||||
private fun materialEnchantCountLimit(type: Material): Int? {
|
||||
val path = "$ENCHANT_COUNT_LIMIT_ITEMS.${type.key.key.lowercase()}"
|
||||
if(!ConfigHolder.DEFAULT_CONFIG.config.isInt(path))
|
||||
return null
|
||||
|
||||
|
|
@ -451,90 +415,46 @@ object ConfigOptions {
|
|||
.getBoolean(VERBOSE_DEBUG_LOGGING, DEFAULT_VERBOSE_DEBUG_LOG)
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the dialog menu for rename enabled
|
||||
*/
|
||||
val doRenameDialog: Boolean
|
||||
get() {
|
||||
return ConfigHolder.DEFAULT_CONFIG
|
||||
.config
|
||||
.getBoolean(DIALOG_RENAME_ENABLED, DEFAULT_DIALOG_RENAME_ENABLED)
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the dialog menu require permission
|
||||
*/
|
||||
val doRenameDialogUsePermission: Boolean
|
||||
get() {
|
||||
return ConfigHolder.DEFAULT_CONFIG
|
||||
.config
|
||||
.getBoolean(DIALOG_RENAME_USE_PERMISSION, DEFAULT_DIALOG_RENAME_USE_PERMISSION)
|
||||
}
|
||||
|
||||
fun canUseDialogRename(player: HumanEntity): Boolean {
|
||||
if(!doRenameDialog || !AnvilRenameDialogUtil.anvilRenameDialog.canSendDialog()) return false
|
||||
if(doRenameDialogUsePermission && !player.hasPermission(RENAME_DIALOG_PERMISSION)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the dialog menu require permission
|
||||
*/
|
||||
val renameDialogMaxSize: Int
|
||||
get() {
|
||||
return ConfigHolder.DEFAULT_CONFIG
|
||||
.config
|
||||
.getInt(DIALOG_MAX_SIZE, DEFAULT_DIALOG_MAX_SIZE)
|
||||
.takeIf { it in DIALOG_MAX_SIZE_RANGE }
|
||||
?: Int.MAX_VALUE
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the text used for rename should be kept in the item's pdc
|
||||
*/
|
||||
val shouldKeepRenameText: Boolean
|
||||
get() {
|
||||
return ConfigHolder.DEFAULT_CONFIG
|
||||
.config
|
||||
.getBoolean(DIALOG_KEEP_USER_TEXT, DEFAULT_DIALOG_KEEP_USER_TEXT)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the given [enchantment]'s limit
|
||||
*/
|
||||
fun enchantLimit(enchantment: CAEnchantment): Int {
|
||||
val limit = rawEnchantLimit(enchantment)
|
||||
if(limit >= 0) return limit.coerceAtMost(ENCHANT_LIMIT)
|
||||
|
||||
// get default
|
||||
return enchantment.defaultMaxLevel()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the given [enchantment]'s limit
|
||||
*/
|
||||
fun rawEnchantLimit(enchantment: CAEnchantment): Int {
|
||||
// Test namespace
|
||||
var limit = enchantLimit(enchantment.key.toString())
|
||||
if (limit >= 0) return limit
|
||||
if (limit != null) return limit
|
||||
|
||||
// Test legacy (name only)
|
||||
limit = enchantLimit(enchantment.enchantmentName)
|
||||
if (limit >= 0) return limit
|
||||
if (limit != null) return limit
|
||||
|
||||
// Default to negative
|
||||
return -1
|
||||
// get default (and test old legacy if present)
|
||||
return getDefaultLevel(enchantment.enchantmentName)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the given [enchantmentName]'s limit
|
||||
*/
|
||||
private fun enchantLimit(enchantmentName: String): Int {
|
||||
private fun enchantLimit(enchantmentName: String): Int? {
|
||||
|
||||
val path = "${ENCHANT_LIMIT_ROOT}.$enchantmentName"
|
||||
return CustomAnvil.instance.config
|
||||
.getInt(path, -1)
|
||||
return CustomAnvil.instance
|
||||
.config
|
||||
.getInt(path, ENCHANT_LIMIT_RANGE.first - 1)
|
||||
.takeIf { it in ENCHANT_LIMIT_RANGE }
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default value if enchantment do not exist on config
|
||||
*/
|
||||
private fun getDefaultLevel(
|
||||
enchantmentName: String, // compatibility with 1.20.5. TODO better update system
|
||||
): Int {
|
||||
if (enchantmentName == "sweeping_edge") {
|
||||
val limit = enchantLimit("sweeping")
|
||||
if (limit != null) return limit
|
||||
|
||||
}
|
||||
return defaultEnchantLimit
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -606,20 +526,20 @@ object ConfigOptions {
|
|||
fun maxBeforeMergeDisabled(enchantment: CAEnchantment): Int {
|
||||
val key = enchantment.key.toString()
|
||||
var value = maxBeforeMergeDisabled(key)
|
||||
if (value >= 0) return value
|
||||
if (value != null) return value
|
||||
|
||||
// Legacy name
|
||||
val legacy = enchantment.enchantmentName
|
||||
value = maxBeforeMergeDisabled(legacy)
|
||||
if (value >= 0) return value
|
||||
if (value != null) return value
|
||||
|
||||
if (key == "minecraft:sweeping_edge") {
|
||||
value = maxBeforeMergeDisabled("minecraft:sweeping")
|
||||
if (value >= 0) return value
|
||||
if (value != null) return value
|
||||
|
||||
// legacy name of legacy enchantment name
|
||||
value = maxBeforeMergeDisabled("sweeping")
|
||||
if (value >= 0) return value
|
||||
if (value != null) return value
|
||||
}
|
||||
|
||||
return DEFAULT_MAX_BEFORE_MERGE_DISABLED
|
||||
|
|
@ -629,13 +549,14 @@ object ConfigOptions {
|
|||
* Get the given [enchantmentName]'s level before merge is disabled
|
||||
* a negative value would mean never disabled
|
||||
*/
|
||||
private fun maxBeforeMergeDisabled(enchantmentName: String): Int {
|
||||
private fun maxBeforeMergeDisabled(enchantmentName: String): Int? {
|
||||
// find if set
|
||||
val path = "${DISABLE_MERGE_OVER_ROOT}.$enchantmentName"
|
||||
|
||||
return CustomAnvil.instance
|
||||
.config
|
||||
.getInt(path, -1)
|
||||
.getInt(path, ENCHANT_LIMIT_RANGE.min() - 1)
|
||||
.takeIf { it in ENCHANT_LIMIT_RANGE }
|
||||
}
|
||||
|
||||
fun isImmutable(key: NamespacedKey): Boolean {
|
||||
|
|
@ -651,29 +572,4 @@ object ConfigOptions {
|
|||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
* Monetary configs (only for 1.21.6+)
|
||||
* Also require dialog rename
|
||||
*/
|
||||
fun shouldUseMoney(player: HumanEntity): Boolean {
|
||||
return EconomyManager.economy?.initialized() == true &&
|
||||
canUseDialogRename(player) &&
|
||||
ConfigHolder.DEFAULT_CONFIG
|
||||
.config
|
||||
.getBoolean(SHOULD_USE_MONEY, DEFAULT_SHOULD_USE_MONEY)
|
||||
}
|
||||
|
||||
val usedCurrency: String
|
||||
get() {
|
||||
return ConfigHolder.DEFAULT_CONFIG
|
||||
.config
|
||||
.getString(MONEY_CURRENCY, DEFAULT_MONEY_CURRENCY)!!
|
||||
}
|
||||
|
||||
fun getMonetaryMultiplier(type: String): BigDecimal {
|
||||
return BigDecimal(ConfigHolder.DEFAULT_CONFIG
|
||||
.config
|
||||
.getDouble("$MONETARY_MULTIPLIER_ROOT.$type", DEFAULT_MONEY_MULTIPLIER))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ import io.delilaheve.CustomAnvil
|
|||
import org.bukkit.entity.HumanEntity
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import xyz.alexcrea.cuanvil.config.ConfigHolder
|
||||
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
|
||||
import xyz.alexcrea.cuanvil.group.ConflictType
|
||||
import xyz.alexcrea.cuanvil.util.MaterialUtil.customType
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
|
|
@ -31,77 +31,24 @@ object EnchantmentUtil {
|
|||
) = mutableMapOf<CAEnchantment, Int>().apply {
|
||||
putAll(this@combineWith)
|
||||
|
||||
CustomAnvil.verboseLog("Testing merge")
|
||||
val bypassFuse = player.hasPermission(CustomAnvil.bypassFusePermission)
|
||||
val bypassLevel = player.hasPermission(CustomAnvil.bypassLevelPermission)
|
||||
|
||||
var maxEnchantCount = ConfigOptions.getEnchantCountLimit(item.customType)
|
||||
var maxEnchantCount = ConfigOptions.getEnchantCountLimit(item.type)
|
||||
if(maxEnchantCount == null || maxEnchantCount < 0) maxEnchantCount = Int.MAX_VALUE
|
||||
|
||||
val allowed = other.filter { (enchantment, _) -> enchantment.isAllowed(player) }
|
||||
val new = allowed.filter{ (enchantment, _) -> !containsKey(enchantment)}
|
||||
val old = allowed.filter{ (enchantment, _) -> containsKey(enchantment)}
|
||||
other.forEach { (enchantment, level) ->
|
||||
if(!enchantment.isAllowed(player)) return@forEach
|
||||
|
||||
fun maxLevel(enchantment: CAEnchantment): Int {
|
||||
val max = if (bypassLevel) { 255 }
|
||||
// Get max level or 255 if player can bypass
|
||||
val maxLevel = if (bypassLevel) { 255 }
|
||||
else { ConfigOptions.enchantLimit(enchantment) }
|
||||
CustomAnvil.verboseLog("Max level of ${enchantment.key} is $maxLevel (bypassLevel is $bypassLevel)")
|
||||
|
||||
CustomAnvil.verboseLog("Max level of ${enchantment.key} is $max (bypassLevel is $bypassLevel)")
|
||||
return max
|
||||
}
|
||||
|
||||
old.forEach { (enchantment, level) ->
|
||||
// Get max level or 255 if player can bypass
|
||||
val maxLevel = maxLevel(enchantment)
|
||||
val cappedLevel = min(level, maxLevel)
|
||||
|
||||
val oldLevel = this[enchantment]!! // <- should not be null. (enchantment already in result list)
|
||||
|
||||
// ... and they're not the same level
|
||||
if (oldLevel != cappedLevel) {
|
||||
// apply the greater of the two or left one if right is above max
|
||||
this[enchantment] = max(oldLevel, cappedLevel)
|
||||
}
|
||||
// ... and they're the same level
|
||||
else {
|
||||
// We test if it is allowed to merge at this level
|
||||
if(!bypassLevel){
|
||||
val maxBeforeDisabled = ConfigOptions.maxBeforeMergeDisabled(enchantment)
|
||||
if((maxBeforeDisabled > 0) && (oldLevel >= maxBeforeDisabled)) {
|
||||
CustomAnvil.verboseLog(
|
||||
"Reached max merge before disable for ${enchantment.key}: $oldLevel/$maxBeforeDisabled)")
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
|
||||
// Now we increase the enchantment level by 1
|
||||
var newLevel = oldLevel + 1
|
||||
newLevel = max(min(newLevel, maxLevel), oldLevel)
|
||||
this[enchantment] = newLevel
|
||||
}
|
||||
|
||||
if(bypassFuse){
|
||||
CustomAnvil.verboseLog("Bypassed conflict check for ${enchantment.key}")
|
||||
} else {
|
||||
val conflictType = ConfigHolder.CONFLICT_HOLDER.conflictManager
|
||||
.isConflicting(this, item, enchantment)
|
||||
|
||||
// ... and they are conflicting
|
||||
if(conflictType != ConflictType.NO_CONFLICT){
|
||||
CustomAnvil.verboseLog(
|
||||
"Enchantment already in result list, and they are conflicting (${enchantment.key}, conflict: $conflictType)")
|
||||
this[enchantment] = oldLevel
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to add new now
|
||||
new.forEach { (enchantment, level) ->
|
||||
// Get max level or 255 if player can bypass
|
||||
val maxLevel = maxLevel(enchantment)
|
||||
val cappedLevel = min(level, maxLevel)
|
||||
|
||||
// Enchantment not yet in result list
|
||||
if (!containsKey(enchantment)) {
|
||||
// Do not allow new enchantment if above maximum
|
||||
if(this.size >= maxEnchantCount) return@forEach
|
||||
|
||||
|
|
@ -121,7 +68,50 @@ object EnchantmentUtil {
|
|||
}
|
||||
|
||||
}
|
||||
// Enchantment already in result list
|
||||
else {
|
||||
val oldLevel = this[enchantment]!! // <- should not be null. (enchantment already in result list)
|
||||
|
||||
if(bypassFuse){
|
||||
CustomAnvil.verboseLog("Bypassed conflict check for ${enchantment.key}")
|
||||
} else {
|
||||
val conflictType = ConfigHolder.CONFLICT_HOLDER.conflictManager
|
||||
.isConflicting(this, item, enchantment)
|
||||
|
||||
// ... and they are conflicting
|
||||
if(conflictType != ConflictType.NO_CONFLICT){
|
||||
CustomAnvil.verboseLog(
|
||||
"Enchantment already in result list, and they are conflicting (${enchantment.key}, conflict: $conflictType)")
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
|
||||
// ... and they're not the same level
|
||||
if (oldLevel != cappedLevel) {
|
||||
// apply the greater of the two or left one if right is above max
|
||||
this[enchantment] = max(oldLevel, cappedLevel)
|
||||
|
||||
}
|
||||
// ... and they're the same level
|
||||
else {
|
||||
// We test if it is allowed to merge at this level
|
||||
if(!bypassLevel){
|
||||
val maxBeforeDisabled = ConfigOptions.maxBeforeMergeDisabled(enchantment)
|
||||
if((maxBeforeDisabled > 0) && (oldLevel >= maxBeforeDisabled)) {
|
||||
CustomAnvil.verboseLog(
|
||||
"Reached max merge before disable for ${enchantment.key}: $oldLevel/$maxBeforeDisabled)")
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
|
||||
// Now we increase the enchantment level by 1
|
||||
var newLevel = oldLevel + 1
|
||||
newLevel = max(min(newLevel, maxLevel), oldLevel)
|
||||
this[enchantment] = newLevel
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,6 @@ import org.bukkit.Material.ENCHANTED_BOOK
|
|||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.inventory.meta.Damageable
|
||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
|
||||
import xyz.alexcrea.cuanvil.update.UpdateUtils
|
||||
import xyz.alexcrea.cuanvil.util.MaterialUtil.customType
|
||||
import xyz.alexcrea.cuanvil.util.MaxDamageCheckerUtil
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
|
@ -38,13 +35,6 @@ object ItemUtil {
|
|||
|
||||
}
|
||||
|
||||
private fun maxDamage(damageable: Damageable): Int {
|
||||
val ver = UpdateUtils.currentMinecraftVersion()
|
||||
if(ver.major <= 1 && ver.minor <= 20 && ver.patch < 5) return Integer.MAX_VALUE
|
||||
|
||||
return MaxDamageCheckerUtil.getMaxDamage(damageable)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this [ItemStack]s durability from a combination of the
|
||||
* [first] and [second] item's durability values
|
||||
|
|
@ -64,9 +54,7 @@ object ItemUtil {
|
|||
val secondDurability = durability - secondDamage
|
||||
val combinedDurability = firstDurability + secondDurability
|
||||
val newDurability = min(combinedDurability, durability)
|
||||
|
||||
val maxDamage = maxDamage(it)
|
||||
it.damage = min(durability - newDurability, maxDamage)
|
||||
it.damage = durability - newDurability
|
||||
itemMeta = it
|
||||
return true
|
||||
}
|
||||
|
|
@ -102,5 +90,5 @@ object ItemUtil {
|
|||
*/
|
||||
fun ItemStack.canMergeWith(
|
||||
other: ItemStack?
|
||||
) = (other != null) && (customType == other.customType || (other.isEnchantedBook()))
|
||||
) = (other != null) && (type == other.type || (other.isEnchantedBook()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,72 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.anvil
|
||||
|
||||
import io.delilaheve.util.ConfigOptions
|
||||
import java.math.BigDecimal
|
||||
import kotlin.math.min
|
||||
import io.delilaheve.util.ConfigOptions.getMonetaryMultiplier as moneyMultiplier
|
||||
|
||||
open class AnvilCost {
|
||||
private val isAlone: Boolean
|
||||
var valid = true // Get set as invalid if cost can be satisfied
|
||||
var isMonetary = false
|
||||
|
||||
var generic = 0
|
||||
var enchantment = 0
|
||||
var repair = 0
|
||||
var rename = 0
|
||||
var lore = 0
|
||||
var illegalPenalty = 0
|
||||
var workPenalty = 0
|
||||
var recipe = 0
|
||||
|
||||
constructor(generic: Int) {
|
||||
this.generic = generic
|
||||
isAlone = true
|
||||
}
|
||||
|
||||
constructor() {
|
||||
isAlone = false
|
||||
}
|
||||
|
||||
fun asXpCost(): Int {
|
||||
return generic + enchantment + repair + rename + lore + illegalPenalty + workPenalty + recipe
|
||||
}
|
||||
|
||||
fun filteredXpCost(ignoreRules: Boolean = false): Int {
|
||||
val original = asXpCost()
|
||||
|
||||
// Test repair cost limit
|
||||
return if (
|
||||
!ignoreRules &&
|
||||
!ConfigOptions.doRemoveCostLimit &&
|
||||
ConfigOptions.doCapCost
|
||||
) {
|
||||
min(original, ConfigOptions.maxAnvilCost)
|
||||
} else {
|
||||
original
|
||||
}
|
||||
}
|
||||
|
||||
open fun asMonetaryCost(): BigDecimal {
|
||||
// multiply by per use type multipliers
|
||||
return BigDecimal(generic)
|
||||
.add(BigDecimal(enchantment).multiply(moneyMultiplier("enchantment")))
|
||||
.add(BigDecimal(repair).multiply(moneyMultiplier("repair")))
|
||||
.add(BigDecimal(rename).multiply(moneyMultiplier("rename")))
|
||||
.add(BigDecimal(lore).multiply(moneyMultiplier("lore_edit")))
|
||||
.add(BigDecimal(enchantment).multiply(moneyMultiplier("enchantment")))
|
||||
.add(BigDecimal(illegalPenalty).multiply(moneyMultiplier("work_penalty")))
|
||||
.add(BigDecimal(workPenalty).multiply(moneyMultiplier("work_penalty")))
|
||||
.add(BigDecimal(recipe).multiply(moneyMultiplier("recipe")))
|
||||
.multiply(moneyMultiplier("global"))
|
||||
}
|
||||
}
|
||||
|
||||
class CustomCraftCost(val rawCost: Int): AnvilCost() {
|
||||
|
||||
override fun asMonetaryCost(): BigDecimal {
|
||||
return BigDecimal(rawCost)
|
||||
.multiply(moneyMultiplier("global"))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,331 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.anvil
|
||||
|
||||
import io.delilaheve.CustomAnvil
|
||||
import io.delilaheve.util.ConfigOptions
|
||||
import io.delilaheve.util.EnchantmentUtil.combineWith
|
||||
import io.delilaheve.util.ItemUtil.findEnchantments
|
||||
import io.delilaheve.util.ItemUtil.isEnchantedBook
|
||||
import io.delilaheve.util.ItemUtil.repairFrom
|
||||
import io.delilaheve.util.ItemUtil.setEnchantmentsUnsafe
|
||||
import io.delilaheve.util.ItemUtil.unitRepair
|
||||
import org.bukkit.ChatColor
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.entity.HumanEntity
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.AnvilInventory
|
||||
import org.bukkit.inventory.InventoryView
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.inventory.meta.ItemMeta
|
||||
import org.bukkit.persistence.PersistentDataType
|
||||
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
||||
import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialog
|
||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
|
||||
import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe
|
||||
import xyz.alexcrea.cuanvil.util.CasedStringUtil
|
||||
import xyz.alexcrea.cuanvil.util.CustomRecipeUtil
|
||||
import xyz.alexcrea.cuanvil.util.MaterialUtil.isAir
|
||||
import xyz.alexcrea.cuanvil.util.MiniMessageUtil
|
||||
import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair
|
||||
import xyz.alexcrea.cuanvil.util.anvil.AnvilColorUtil
|
||||
import xyz.alexcrea.cuanvil.util.anvil.AnvilLoreEditUtil
|
||||
import xyz.alexcrea.cuanvil.util.anvil.AnvilXpUtil
|
||||
import xyz.alexcrea.cuanvil.util.config.LoreEditType
|
||||
import xyz.alexcrea.cuanvil.util.dialog.AnvilRenameDialogUtil
|
||||
|
||||
object AnvilMergeLogic {
|
||||
|
||||
open class AnvilResult {
|
||||
companion object {
|
||||
val EMPTY = AnvilResult(null, AnvilCost())
|
||||
}
|
||||
|
||||
val item: ItemStack?
|
||||
val cost: AnvilCost
|
||||
val ignoreXpRules: Boolean
|
||||
|
||||
constructor(item: ItemStack?, cost: AnvilCost, ignoreXpRules: Boolean = false) {
|
||||
this.item = item
|
||||
this.cost = cost
|
||||
this.ignoreXpRules = ignoreXpRules
|
||||
}
|
||||
|
||||
fun isEmpty(): Boolean {
|
||||
return item == null
|
||||
}
|
||||
}
|
||||
|
||||
class UnitRepairResult : AnvilResult {
|
||||
companion object {
|
||||
val EMPTY = UnitRepairResult(null, AnvilCost(), 0)
|
||||
}
|
||||
|
||||
val repairAmount: Int
|
||||
|
||||
constructor(item: ItemStack?, cost: AnvilCost, repairAmount: Int) : super(item, cost) {
|
||||
this.repairAmount = repairAmount
|
||||
}
|
||||
}
|
||||
|
||||
class CustomCraftResult : AnvilResult {
|
||||
companion object {
|
||||
val EMPTY = CustomCraftResult(null, CustomCraftCost(0), 0, null)
|
||||
}
|
||||
|
||||
val customCraftCost: CustomCraftCost
|
||||
val amount: Int
|
||||
val recipe: AnvilCustomRecipe?
|
||||
|
||||
constructor(
|
||||
item: ItemStack?, cost: CustomCraftCost,
|
||||
amount: Int, recipe: AnvilCustomRecipe?
|
||||
) : super(item, cost, true) {
|
||||
this.customCraftCost = cost
|
||||
this.amount = amount
|
||||
this.recipe = recipe
|
||||
}
|
||||
}
|
||||
|
||||
class LoreEditResult : AnvilResult {
|
||||
companion object {
|
||||
val EMPTY = LoreEditResult(null, AnvilCost(), LoreEditType.APPEND_PAPER)
|
||||
}
|
||||
|
||||
val type: LoreEditType
|
||||
|
||||
constructor(item: ItemStack?, cost: AnvilCost, type: LoreEditType) : super(item, cost) {
|
||||
this.type = type
|
||||
}
|
||||
}
|
||||
|
||||
fun doRenaming(
|
||||
view: InventoryView, //TODO use anvil view
|
||||
inventory: AnvilInventory,
|
||||
player: Player, first: ItemStack
|
||||
): AnvilResult {
|
||||
val resultItem = DependencyManager.cloneItem(player, first)
|
||||
val cost = AnvilCost()
|
||||
cost.rename = handleRename(resultItem, inventory, player)
|
||||
|
||||
// Test/stop if nothing changed.
|
||||
if (first == resultItem) {
|
||||
CustomAnvil.log("no right item, But input is same as output")
|
||||
return AnvilResult.EMPTY
|
||||
}
|
||||
|
||||
cost.workPenalty = AnvilXpUtil.calculatePenalty(first, null, resultItem, AnvilUseType.RENAME_ONLY)
|
||||
val result =
|
||||
DependencyManager.tryTreatAnvilResult(view, inventory, player, resultItem, AnvilUseType.RENAME_ONLY, cost)
|
||||
|
||||
return AnvilResult(result, cost)
|
||||
}
|
||||
|
||||
private fun processDialogPCD(meta: ItemMeta, player: HumanEntity) {
|
||||
val text = AnvilRenameDialogUtil.anvilRenameDialog.currentText(player)
|
||||
return processPCD(meta, player, text)
|
||||
}
|
||||
|
||||
fun processPCD(meta: ItemMeta, player: HumanEntity, text: String?) {
|
||||
val keepDialog = ConfigOptions.canUseDialogRename(player) && ConfigOptions.shouldKeepRenameText
|
||||
|
||||
val pdc = meta.persistentDataContainer
|
||||
if (!keepDialog)
|
||||
pdc.remove(AnvilRenameDialog.PCD_KEEP_RENAME_TEXT_KEY)
|
||||
else {
|
||||
if (text == null || text.isBlank())
|
||||
pdc.remove(AnvilRenameDialog.PCD_KEEP_RENAME_TEXT_KEY)
|
||||
else pdc.set(AnvilRenameDialog.PCD_KEEP_RENAME_TEXT_KEY, PersistentDataType.STRING, text)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleRename(resultItem: ItemStack, inventory: AnvilInventory, player: HumanEntity): Int {
|
||||
// Can be null
|
||||
var renameText = ChatColor.stripColor(inventory.renameText)
|
||||
|
||||
var sumCost = 0
|
||||
var useColor = false
|
||||
if (ConfigOptions.renameColorPossible && renameText != null) {
|
||||
val component = AnvilColorUtil.handleColor(
|
||||
renameText,
|
||||
AnvilColorUtil.renamePermission(player)
|
||||
)
|
||||
|
||||
if (component != null) {
|
||||
renameText = MiniMessageUtil.legacy_mm.serialize(component)
|
||||
|
||||
sumCost += ConfigOptions.useOfColorCost
|
||||
useColor = true
|
||||
}
|
||||
}
|
||||
|
||||
// Rename item and add renaming cost
|
||||
resultItem.itemMeta?.let {
|
||||
val hasDisplayName = it.hasDisplayName()
|
||||
val displayName = if (!hasDisplayName) null
|
||||
else if (useColor) it.displayName
|
||||
else ChatColor.stripColor(it.displayName)
|
||||
|
||||
|
||||
if (!displayName.contentEquals(renameText) && !(displayName == null &&
|
||||
renameText == "" ||
|
||||
//TODO on recent paper check effective name instead
|
||||
renameText == CasedStringUtil.snakeToUpperSpacedCase(resultItem.type.name.lowercase())
|
||||
)
|
||||
) {
|
||||
it.setDisplayName(renameText)
|
||||
processDialogPCD(it, player)
|
||||
resultItem.itemMeta = it
|
||||
|
||||
sumCost += ConfigOptions.itemRenameCost
|
||||
}
|
||||
|
||||
return sumCost
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
fun doMerge(
|
||||
view: InventoryView, //TODO use anvil view instead
|
||||
inventory: AnvilInventory,
|
||||
player: Player,
|
||||
first: ItemStack, second: ItemStack
|
||||
): AnvilResult {
|
||||
val newEnchants = first.findEnchantments()
|
||||
.combineWith(second.findEnchantments(), first, player)
|
||||
var hasChanged = !isIdentical(first.findEnchantments(), newEnchants)
|
||||
|
||||
val resultItem = DependencyManager.cloneItem(player, first)
|
||||
val cost = AnvilCost()
|
||||
if (hasChanged) {
|
||||
resultItem.setEnchantmentsUnsafe(newEnchants)
|
||||
// Calculate enchantment cost
|
||||
AnvilXpUtil.getRightValues(second, resultItem, cost)
|
||||
}
|
||||
|
||||
// Calculate repair cost
|
||||
if (!first.isEnchantedBook() && !second.isEnchantedBook()) {
|
||||
// we only need to be concerned with repair when neither item is a book
|
||||
val repaired = resultItem.repairFrom(first, second)
|
||||
cost.repair = if (repaired) ConfigOptions.itemRepairCost else 0
|
||||
hasChanged = hasChanged || repaired
|
||||
}
|
||||
|
||||
// Test/stop if nothing changed.
|
||||
if (!hasChanged) {
|
||||
CustomAnvil.log("Mergeable with second, But input is same as output")
|
||||
return AnvilResult.EMPTY
|
||||
}
|
||||
// As calculatePenalty edit result, we need to calculate penalty after checking equality
|
||||
cost.workPenalty = AnvilXpUtil.calculatePenalty(first, second, resultItem, AnvilUseType.MERGE)
|
||||
// Calculate rename cost
|
||||
cost.rename = handleRename(resultItem, inventory, player)
|
||||
|
||||
val result =
|
||||
DependencyManager.tryTreatAnvilResult(view, inventory, player, resultItem, AnvilUseType.MERGE, cost)
|
||||
|
||||
return AnvilResult(result, cost)
|
||||
}
|
||||
|
||||
private fun isIdentical(
|
||||
firstEnchants: MutableMap<CAEnchantment, Int>,
|
||||
resultEnchants: MutableMap<CAEnchantment, Int>
|
||||
): Boolean {
|
||||
if (firstEnchants.size != resultEnchants.size) return false
|
||||
for (entry in resultEnchants) {
|
||||
if (firstEnchants.getOrDefault(entry.key, entry.value - 1) != entry.value) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// return true if a custom recipe exist with these ingredients
|
||||
fun testCustomRecipe(
|
||||
view: InventoryView, //TODO use anvil view instead
|
||||
inventory: AnvilInventory,
|
||||
player: Player,
|
||||
first: ItemStack, second: ItemStack?
|
||||
): CustomCraftResult {
|
||||
val recipe = CustomRecipeUtil.getCustomRecipe(first, second)
|
||||
CustomAnvil.verboseLog("custom recipe not null? ${recipe != null}")
|
||||
if (recipe == null) return CustomCraftResult.EMPTY
|
||||
|
||||
val amount = CustomRecipeUtil.getCustomRecipeAmount(recipe, first, second)
|
||||
|
||||
val resultItem: ItemStack = DependencyManager.cloneItem(player, recipe.resultItem!!)
|
||||
resultItem.amount *= amount
|
||||
|
||||
// Maybe add an option on custom craft to ignore/not ignore penalty ??
|
||||
val xpCost = recipe.determineCost(amount, first, resultItem)
|
||||
|
||||
val cost = CustomCraftCost(xpCost)
|
||||
// This is for displayed cost
|
||||
cost.recipe = if (recipe.removeExactLinearXp) AnvilXpUtil.calculateMinimumLevelForXp(xpCost)
|
||||
else AnvilXpUtil.calculateLevelForXp(xpCost)
|
||||
|
||||
val result =
|
||||
DependencyManager.tryTreatAnvilResult(view, inventory, player, resultItem, AnvilUseType.CUSTOM_CRAFT, cost)
|
||||
return CustomCraftResult(result, cost, amount, recipe)
|
||||
}
|
||||
|
||||
fun testUnitRepair(
|
||||
view: InventoryView, //TODO use anvil view
|
||||
inventory: AnvilInventory,
|
||||
player: Player,
|
||||
first: ItemStack, second: ItemStack
|
||||
): UnitRepairResult {
|
||||
val unitRepairAmount = first.getRepair(second) ?: return UnitRepairResult.EMPTY
|
||||
|
||||
return testUnitRepair(view, inventory, player, first, second, unitRepairAmount)
|
||||
}
|
||||
|
||||
fun testUnitRepair(
|
||||
view: InventoryView, //TODO use anvil view instead
|
||||
inventory: AnvilInventory,
|
||||
player: Player,
|
||||
first: ItemStack, second: ItemStack,
|
||||
unitRepairAmount: Double
|
||||
): UnitRepairResult {
|
||||
val resultItem = DependencyManager.cloneItem(player, first)
|
||||
val cost = AnvilCost()
|
||||
cost.rename = handleRename(resultItem, inventory, player)
|
||||
|
||||
val repairAmount = resultItem.unitRepair(second.amount, unitRepairAmount)
|
||||
if (repairAmount > 0)
|
||||
cost.repair = repairAmount * ConfigOptions.unitRepairCost
|
||||
|
||||
// We do not care about right item penalty for unit repair
|
||||
cost.workPenalty = AnvilXpUtil.calculatePenalty(first, null, resultItem, AnvilUseType.UNIT_REPAIR)
|
||||
|
||||
// Test/stop if nothing changed.
|
||||
if (first == resultItem) {
|
||||
CustomAnvil.log("unit repair, But input is same as output")
|
||||
return UnitRepairResult.EMPTY
|
||||
}
|
||||
|
||||
val result =
|
||||
DependencyManager.tryTreatAnvilResult(view, inventory, player, resultItem, AnvilUseType.UNIT_REPAIR, cost)
|
||||
return UnitRepairResult(result, cost, repairAmount)
|
||||
}
|
||||
|
||||
fun testLoreEdit(
|
||||
player: Player,
|
||||
first: ItemStack, second: ItemStack
|
||||
): LoreEditResult {
|
||||
val type = second.type
|
||||
|
||||
val result = if (Material.WRITABLE_BOOK == type)
|
||||
AnvilLoreEditUtil.tryLoreEditByBook(player, first, second)
|
||||
else if (Material.PAPER == type)
|
||||
AnvilLoreEditUtil.tryLoreEditByPaper(player, first, second)
|
||||
else LoreEditResult.EMPTY
|
||||
|
||||
if (result.isEmpty()) return result
|
||||
|
||||
if (result.item!!.isAir || first == result.item) {
|
||||
CustomAnvil.log("lore edit, But input is same as output")
|
||||
return LoreEditResult.EMPTY
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.command
|
||||
|
||||
import org.bukkit.ChatColor
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
|
||||
abstract class CASubCommand: CommandExecutor {
|
||||
|
||||
private var alreadySaid = false;
|
||||
override fun onCommand(
|
||||
sender: CommandSender,
|
||||
cmd: Command,
|
||||
cmdstr: String,
|
||||
args: Array<out String>
|
||||
): Boolean {
|
||||
if(!alreadySaid){
|
||||
sender.sendMessage(ChatColor.RED.toString() +
|
||||
"Please not that this command will be replaced as a subcommand of `/customanvil` or `/ca`")
|
||||
alreadySaid = true
|
||||
}
|
||||
|
||||
return executeCommand(sender, cmd, cmdstr, args)
|
||||
}
|
||||
|
||||
abstract fun executeCommand(
|
||||
sender: CommandSender,
|
||||
cmd: Command,
|
||||
cmdstr: String,
|
||||
args: Array<out String>): Boolean
|
||||
|
||||
open fun allowed(sender: CommandSender): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
open fun tabCompleter(
|
||||
sender: CommandSender,
|
||||
args: Array<out String>,
|
||||
list: MutableList<String>) {
|
||||
}
|
||||
|
||||
open fun description(): String {
|
||||
return "no description"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.command
|
||||
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import io.delilaheve.CustomAnvil
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.command.TabCompleter
|
||||
import xyz.alexcrea.cuanvil.util.MetricsUtil
|
||||
import java.util.ArrayList
|
||||
|
||||
class CustomAnvilCommand(plugin: CustomAnvil) : CommandExecutor, TabCompleter {
|
||||
|
||||
// Name of the generic command
|
||||
companion object {
|
||||
private const val genericCommandName = "customanvil"
|
||||
}
|
||||
|
||||
private val editConfigCommand = EditConfigExecutor()
|
||||
private val helpCommand = HelpExecutor()
|
||||
private val commands = ImmutableMap.of(
|
||||
"gui", editConfigCommand,
|
||||
"reload", ReloadExecutor(),
|
||||
"diagnostic", DiagnosticExecutor(),
|
||||
"help", helpCommand,
|
||||
)
|
||||
|
||||
init {
|
||||
val self = plugin.getCommand(genericCommandName)!!
|
||||
self.setExecutor(this)
|
||||
self.tabCompleter = this
|
||||
|
||||
helpCommand.commands = commands
|
||||
}
|
||||
|
||||
override fun onCommand(
|
||||
sender: CommandSender,
|
||||
cmd: Command,
|
||||
cmdstr: String,
|
||||
args: Array<out String>
|
||||
): Boolean {
|
||||
// Find sub command to execute based on the provided command name
|
||||
val subcmd: CASubCommand?
|
||||
val newargs: Array<out String>
|
||||
if(args.isEmpty()) {
|
||||
subcmd = editConfigCommand
|
||||
newargs = args
|
||||
}else {
|
||||
subcmd = commands[args[0].lowercase()]
|
||||
newargs = args.copyOfRange(1, args.size)
|
||||
}
|
||||
|
||||
if(subcmd == null || !subcmd.allowed(sender)) {
|
||||
sender.sendMessage("Invalid subcommand. run `$cmdstr help` to see available commands")
|
||||
return true
|
||||
}
|
||||
|
||||
try {
|
||||
return subcmd.executeCommand(sender, cmd, cmdstr, newargs)
|
||||
} catch (e: Throwable) {
|
||||
MetricsUtil.trackError(e)
|
||||
sender.sendMessage("§cError running this command")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTabComplete(
|
||||
sender: CommandSender,
|
||||
cmd: Command,
|
||||
cmdstr: String,
|
||||
args: Array<out String>
|
||||
): MutableList<String> {
|
||||
val result = ArrayList<String>()
|
||||
if(args.size < 2) {
|
||||
for ((key, cmd) in commands) {
|
||||
if(!cmd.allowed(sender)) continue
|
||||
result.add(key)
|
||||
}
|
||||
} else {
|
||||
val subcmd = commands[args[0].lowercase()]
|
||||
|
||||
if(subcmd != null) {
|
||||
val newArgs = args.copyOfRange(1, args.size)
|
||||
if(!subcmd.allowed(sender)) return result
|
||||
|
||||
subcmd.tabCompleter(sender, newArgs, result)
|
||||
}
|
||||
}
|
||||
|
||||
//assumed all provided tab completed string are lowercase
|
||||
return result.stream()
|
||||
.filter { it.startsWith(args[args.size - 1]) }
|
||||
.sorted()
|
||||
.toList()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,347 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.command
|
||||
|
||||
import com.github.stefvanschie.inventoryframework.inventoryview.interface_.InventoryViewUtil
|
||||
import io.delilaheve.CustomAnvil
|
||||
import net.md_5.bungee.api.chat.ClickEvent
|
||||
import net.md_5.bungee.api.chat.HoverEvent
|
||||
import net.md_5.bungee.api.chat.TextComponent
|
||||
import net.md_5.bungee.api.chat.hover.content.Text
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.ChatColor
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.enchantments.Enchantment
|
||||
import org.bukkit.entity.HumanEntity
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.inventory.InventoryType
|
||||
import org.bukkit.event.inventory.PrepareAnvilEvent
|
||||
import org.bukkit.inventory.AnvilInventory
|
||||
import org.bukkit.inventory.InventoryView
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.inventory.meta.Damageable
|
||||
import org.bukkit.inventory.meta.EnchantmentStorageMeta
|
||||
import org.bukkit.plugin.Plugin
|
||||
import org.bukkit.plugin.RegisteredListener
|
||||
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
||||
import xyz.alexcrea.cuanvil.dependency.packet.NoPacketManager
|
||||
import xyz.alexcrea.cuanvil.dependency.packet.ProtocoLibWrapper
|
||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry
|
||||
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener
|
||||
import xyz.alexcrea.cuanvil.util.MetricsUtil
|
||||
import java.util.*
|
||||
import java.util.stream.Collectors
|
||||
|
||||
|
||||
class DiagnosticExecutor: CASubCommand() {
|
||||
|
||||
companion object{
|
||||
private const val NO_DIAG_PERM = "You do not have permission to diagnostic this server"
|
||||
|
||||
fun fetchNMSType(): String {
|
||||
val packetManager = DependencyManager.packetManager
|
||||
val packetManagerClass = packetManager.javaClass
|
||||
|
||||
val className = packetManagerClass.name
|
||||
val result = if(className.contains("PaperPacket")) {
|
||||
"Paper"
|
||||
} else {
|
||||
when (packetManagerClass) {
|
||||
ProtocoLibWrapper::class.java -> "Protocolib"
|
||||
NoPacketManager::class.java -> "None"
|
||||
else -> "Version Specific"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return "$result ${if(packetManager.canSetInstantBuild) '✅' else '❌'}"
|
||||
}
|
||||
}
|
||||
|
||||
enum class DiagParams(val value: String) {
|
||||
OS_PRIVACY("os_privacy"),
|
||||
PLUGIN_PRIVACY("plugin_privacy"),
|
||||
NO_MERGE_TEST("no_merge_test"),
|
||||
FULL_ENCHANTMENT_DATA("full_enchantment_data"),
|
||||
INCLUDE_LAST_ERROR("include_last_error"),
|
||||
}
|
||||
|
||||
private fun fetchParameters(args: Array<out String>): EnumSet<DiagParams> {
|
||||
val result = EnumSet.noneOf(DiagParams::class.java)
|
||||
val argSet = HashSet<String>()
|
||||
|
||||
for (string in args) {
|
||||
argSet.add(string.lowercase())
|
||||
}
|
||||
|
||||
for (param in DiagParams.entries) {
|
||||
if(argSet.contains(param.value))
|
||||
result.add(param)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun tabCompleter(
|
||||
sender: CommandSender,
|
||||
args: Array<out String>,
|
||||
list: MutableList<String>) {
|
||||
if(!allowed(sender)) return
|
||||
|
||||
val map = fetchParameters(args)
|
||||
for (param in DiagParams.entries) {
|
||||
if(!map.contains(param))
|
||||
list.add(param.value)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun executeCommand(
|
||||
sender: CommandSender,
|
||||
cmd: Command,
|
||||
cmdstr: String,
|
||||
args: Array<out String>
|
||||
): Boolean {
|
||||
if (!allowed(sender)) {
|
||||
sender.sendMessage(NO_DIAG_PERM)
|
||||
return false
|
||||
}
|
||||
|
||||
val stb = StringBuilder("```\n")
|
||||
val params = fetchParameters(args)
|
||||
var hasError = false
|
||||
try {
|
||||
diagnostic(sender, stb, params)
|
||||
} catch(e: Throwable){
|
||||
stb.append("\n\nError happened trying to get diagnostic data:\n")
|
||||
.append(e.message).append("\n")
|
||||
.append(e.stackTrace.joinToString("\n"))
|
||||
hasError = true
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
stb.append("\n```")
|
||||
|
||||
if (sender is HumanEntity) {
|
||||
if(hasError)
|
||||
sender.spigot().sendMessage(TextComponent(ChatColor.RED.toString() + "There was an error running the diagnostic"))
|
||||
val message = TextComponent(ChatColor.GREEN.toString() + "Click to copy diagnostic data")
|
||||
|
||||
message.clickEvent = ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, stb.toString())
|
||||
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, Text("§7Click to copy"))
|
||||
|
||||
sender.spigot().sendMessage(message);
|
||||
} else {
|
||||
sender.sendMessage(stb.toString());
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun allowed(sender: CommandSender): Boolean {
|
||||
return sender.hasPermission(CustomAnvil.diagnosticPermission)
|
||||
}
|
||||
|
||||
fun diagnostic(sender: CommandSender, stb: StringBuilder, params: Set<DiagParams>){
|
||||
stb.append("Server Info\n")
|
||||
val version = CustomAnvil.instance.description.version
|
||||
stb.append("\nPlugin Version: ").append(version)
|
||||
if(version.contains("dev")) stb.append(" (alpha)")
|
||||
|
||||
stb.append("\nLatest Update: ").append(CustomAnvil.latestVer)
|
||||
stb.append("\nServer Version: ").append(Bukkit.getVersion()).append(" (").append(Bukkit.getName()).append(')')
|
||||
stb.append("\nPlugin Enabled: ").append(if(CustomAnvil.instance.isEnabled) "Yes" else "No")
|
||||
stb.append("\nNMS type: ").append(fetchNMSType())
|
||||
if(!params.contains(DiagParams.OS_PRIVACY)) {
|
||||
stb.append("\nJava Version: ").append(System.getProperty("java.version"))
|
||||
stb.append("\nOS: ").append(System.getProperty("os.name")).append(" ")
|
||||
.append(System.getProperty("os.version"))
|
||||
.append(System.getProperty("os.arch"))
|
||||
}
|
||||
|
||||
stb.append("\nHad detect error: ").append(if(MetricsUtil.lastError != null) "Yes" else "No")
|
||||
|
||||
if(!params.contains(DiagParams.PLUGIN_PRIVACY)) {
|
||||
pluginListDiag(sender, stb)
|
||||
}
|
||||
prepareAnvilListeners(stb)
|
||||
|
||||
if(!params.contains(DiagParams.NO_MERGE_TEST)){
|
||||
if(sender is Player) testMerge(sender, stb)
|
||||
}
|
||||
|
||||
stb.append("\n\nEnchantments data:")
|
||||
partialEnchantmentData(stb)
|
||||
if(params.contains(DiagParams.FULL_ENCHANTMENT_DATA)){
|
||||
fullEnchantmentData(stb)
|
||||
}
|
||||
|
||||
if(params.contains(DiagParams.INCLUDE_LAST_ERROR)){
|
||||
includeLastError(stb)
|
||||
}
|
||||
}
|
||||
|
||||
private fun testMerge(player: Player, stb: StringBuilder) {
|
||||
val sword = ItemStack(Material.DIAMOND_SWORD)
|
||||
val damagedSword = sword.clone()
|
||||
val enchantedSword = sword.clone()
|
||||
val enchantedBook = ItemStack(Material.ENCHANTED_BOOK)
|
||||
val unitForRepair = ItemStack(Material.DIAMOND)
|
||||
|
||||
var meta = damagedSword.itemMeta
|
||||
(meta as Damageable).damage = 5
|
||||
damagedSword.itemMeta = meta
|
||||
|
||||
meta = enchantedSword.itemMeta
|
||||
meta!!.addEnchant(Enchantment.DAMAGE_ALL, 1, true)
|
||||
enchantedSword.itemMeta = meta
|
||||
|
||||
meta = enchantedBook.itemMeta
|
||||
(meta as EnchantmentStorageMeta).addStoredEnchant(Enchantment.DAMAGE_ALL, 1, true)
|
||||
enchantedBook.itemMeta = meta
|
||||
|
||||
stb.append("\n\nItem to Item repair:")
|
||||
simulateAnvil(player, stb, damagedSword, damagedSword, sword)
|
||||
|
||||
stb.append("\n\nUnit repair:")
|
||||
simulateAnvil(player, stb, damagedSword, unitForRepair, sword)
|
||||
|
||||
stb.append("\n\nEnchanting an item:")
|
||||
simulateAnvil(player, stb, sword, enchantedBook, enchantedSword)
|
||||
}
|
||||
|
||||
private val Plugin.pluginNameDisplay: String
|
||||
get() {
|
||||
return this.name + " v" + this.description.version
|
||||
}
|
||||
|
||||
override fun description(): String {
|
||||
return "Basic diagnostic of this plugin"
|
||||
}
|
||||
|
||||
private fun pluginListDiag(sender: CommandSender, stb: StringBuilder) {
|
||||
val enabledPlugins: MutableList<Plugin?> = ArrayList<Plugin?>()
|
||||
val disabledPlugins: MutableList<Plugin?> = ArrayList<Plugin?>()
|
||||
for (plugin in Bukkit.getPluginManager().plugins) {
|
||||
if (plugin.isEnabled) {
|
||||
enabledPlugins.add(plugin)
|
||||
} else {
|
||||
disabledPlugins.add(plugin)
|
||||
}
|
||||
}
|
||||
|
||||
stb.append("\nEnabled Plugins: ").append(
|
||||
enabledPlugins.stream()
|
||||
.map { plugin -> plugin!!.pluginNameDisplay }
|
||||
.reduce { a: String?, b: String? -> "$a, $b" }.orElse("None")
|
||||
)
|
||||
|
||||
stb.append("\nDisabled Plugins: ").append(
|
||||
disabledPlugins.stream()
|
||||
.map { plugin -> plugin!!.pluginNameDisplay }
|
||||
.reduce { a: String?, b: String? -> "$a, $b" }.orElse("None")
|
||||
)
|
||||
}
|
||||
|
||||
fun prepareAnvilListeners(stb: StringBuilder) {
|
||||
val eventListeners: MutableSet<Plugin?> = Arrays
|
||||
.stream(
|
||||
PrepareAnvilEvent
|
||||
.getHandlerList()
|
||||
.getRegisteredListeners()
|
||||
)
|
||||
.map { obj: RegisteredListener? -> obj!!.plugin }
|
||||
.collect(Collectors.toSet())
|
||||
|
||||
eventListeners.remove(CustomAnvil.instance)
|
||||
stb.append("\nPrepare Anvil Listeners: ").append(
|
||||
if (eventListeners.isEmpty()) "None" else eventListeners.stream()
|
||||
.map { plugin -> plugin!!.pluginNameDisplay }
|
||||
.reduce { a: String?, b: String? -> "$a, $b" }.orElse("None")
|
||||
)
|
||||
}
|
||||
|
||||
fun simulateAnvil(player: Player, stb: StringBuilder, left: ItemStack?, right: ItemStack?, result: ItemStack?) {
|
||||
var invView: InventoryView
|
||||
var event: PrepareAnvilEvent
|
||||
try {
|
||||
val fakeInv = Bukkit.createInventory(player, InventoryType.ANVIL)
|
||||
invView = player.openInventory(fakeInv)!!
|
||||
event = PrepareAnvilEvent(invView, result)
|
||||
} catch (e: Throwable) {
|
||||
// Help
|
||||
val menuTypeClazz = Class.forName("org.bukkit.inventory.MenuType")
|
||||
val anvilTypeField = menuTypeClazz.getField("ANVIL")
|
||||
val anvilType = anvilTypeField.get(null)
|
||||
val createMethod = anvilType.javaClass.getMethod("create", HumanEntity::class.java)
|
||||
invView = createMethod.invoke(anvilType, player) as InventoryView
|
||||
|
||||
player.openInventory(invView)
|
||||
|
||||
val anvilViewClass = Class.forName("org.bukkit.inventory.view.AnvilView")
|
||||
val constructor = PrepareAnvilEvent::class.java.getConstructor(anvilViewClass, ItemStack::class.java)
|
||||
event = constructor.newInstance(invView, result)
|
||||
}
|
||||
|
||||
val fakeInv = InventoryViewUtil.getInstance().getTopInventory(invView) as AnvilInventory
|
||||
fakeInv.setItem(0, left)
|
||||
fakeInv.setItem(1, right)
|
||||
|
||||
val xp = fakeInv.repairCost
|
||||
val maxXp = fakeInv.maximumRepairCost
|
||||
val mergeResult = fakeInv.getItem(2)
|
||||
stb.append("\n${if(result == mergeResult) "E" else "Une"}xpected Result")
|
||||
|
||||
PrepareAnvilListener().anvilCombineCheck(event)
|
||||
// Now we check if item and xp same
|
||||
stb.append("\nXP/Max XP: ")
|
||||
.append(if(fakeInv.repairCost == xp) "Correct" else "Incorrect")
|
||||
.append("/")
|
||||
.append(if(fakeInv.maximumRepairCost == maxXp) "Correct" else "Incorrect")
|
||||
.append(" (${fakeInv.repairCost} $xp|${fakeInv.maximumRepairCost} $maxXp)")
|
||||
.append("\nMerge result: ")
|
||||
.append(if(fakeInv.getItem(2) == mergeResult) "Correct" else "Incorrect")
|
||||
|
||||
PrepareAnvilListener.IS_EMPTY_TEST = true
|
||||
Bukkit.getPluginManager().callEvent(event)
|
||||
stb.append("\nNull result test: ")
|
||||
.append(if(event.result == null) "Correct" else "Incorrect")
|
||||
|
||||
fakeInv.setItem(0, null)
|
||||
fakeInv.setItem(1, null)
|
||||
fakeInv.setItem(2, null)
|
||||
player.closeInventory()
|
||||
}
|
||||
|
||||
private fun fullEnchantmentData(stb: StringBuilder) {
|
||||
for (enchantment in CAEnchantmentRegistry.getInstance().values()) {
|
||||
stb.append("\n- ").append(enchantment.key.toString())
|
||||
.append(" ").append(enchantment.name)
|
||||
.append(" ").append(enchantment.defaultMaxLevel())
|
||||
}
|
||||
}
|
||||
|
||||
private fun partialEnchantmentData(stb: StringBuilder) {
|
||||
val map = HashMap<String, Int>()
|
||||
for (enchant in CAEnchantmentRegistry.getInstance().values()) {
|
||||
map[enchant.key.namespace] = map.getOrDefault(enchant.key.namespace, 0) + 1
|
||||
}
|
||||
|
||||
stb.append("\nNamespaces: ${
|
||||
map.entries.stream()
|
||||
.map { (key, value) -> "$key ($value)" }
|
||||
.reduce { a, b -> "$a, $b" }.get()
|
||||
}")
|
||||
|
||||
}
|
||||
|
||||
private fun includeLastError(stb: StringBuilder) {
|
||||
val e = MetricsUtil.lastError ?: return
|
||||
|
||||
stb.append("\n\nLast stack trace: ${e.stackTraceToString()}")
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,21 +2,17 @@ package xyz.alexcrea.cuanvil.command
|
|||
|
||||
import io.delilaheve.CustomAnvil
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.HumanEntity
|
||||
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil
|
||||
import xyz.alexcrea.cuanvil.gui.config.MainConfigGui
|
||||
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions
|
||||
|
||||
class EditConfigExecutor: CASubCommand() {
|
||||
class EditConfigExecutor : CommandExecutor {
|
||||
|
||||
override fun executeCommand(sender: CommandSender,
|
||||
cmd: Command,
|
||||
cmdstr: String,
|
||||
args: Array<out String>): Boolean {
|
||||
if (sender !is HumanEntity) return false
|
||||
|
||||
if (!allowed(sender)) {
|
||||
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
|
||||
if (!sender.hasPermission(CustomAnvil.editConfigPermission)) {
|
||||
sender.sendMessage(GuiGlobalActions.NO_EDIT_PERM)
|
||||
return false
|
||||
}
|
||||
|
|
@ -29,17 +25,10 @@ class EditConfigExecutor: CASubCommand() {
|
|||
return false
|
||||
}
|
||||
|
||||
if (sender !is HumanEntity) return false
|
||||
MainConfigGui.getInstance().show(sender)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun allowed(sender: CommandSender): Boolean {
|
||||
return sender.hasPermission(CustomAnvil.editConfigPermission)
|
||||
}
|
||||
|
||||
override fun description(): String {
|
||||
return "Gui to edit the plugin's config"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.command
|
||||
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandSender
|
||||
|
||||
class HelpExecutor: CASubCommand() {
|
||||
|
||||
lateinit var commands: ImmutableMap<String, CASubCommand>
|
||||
|
||||
override fun executeCommand(sender: CommandSender,
|
||||
cmd: Command,
|
||||
cmdstr: String,
|
||||
args: Array<out String>): Boolean {
|
||||
|
||||
val stb = StringBuilder("List of available commands:")
|
||||
for ((key, cmd) in commands) {
|
||||
if(!cmd.allowed(sender)) continue
|
||||
|
||||
stb.append("\n- $key: ").append(cmd.description())
|
||||
}
|
||||
|
||||
sender.sendMessage(stb.toString())
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun description(): String {
|
||||
return "Help command"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -11,13 +11,9 @@ import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
|||
import xyz.alexcrea.cuanvil.gui.config.global.*
|
||||
import xyz.alexcrea.cuanvil.update.UpdateHandler
|
||||
|
||||
class ReloadExecutor : CASubCommand() {
|
||||
|
||||
override fun executeCommand(sender: CommandSender,
|
||||
cmd: Command,
|
||||
cmdstr: String,
|
||||
args: Array<out String>): Boolean {
|
||||
if (!allowed(sender)) {
|
||||
class ReloadExecutor : CommandExecutor {
|
||||
override fun onCommand(sender: CommandSender, cmd: Command, cmdstr: String, args: Array<out String>): Boolean {
|
||||
if (!sender.hasPermission(CustomAnvil.commandReloadPermission)) {
|
||||
sender.sendMessage("§cYou do not have permission to reload the config")
|
||||
return false
|
||||
}
|
||||
|
|
@ -35,14 +31,6 @@ class ReloadExecutor : CASubCommand() {
|
|||
return commandSuccess
|
||||
}
|
||||
|
||||
override fun allowed(sender: CommandSender): Boolean {
|
||||
return sender.hasPermission(CustomAnvil.commandReloadPermission)
|
||||
}
|
||||
|
||||
override fun description(): String {
|
||||
return "Reload the configuration of this plugin"
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the command, return true if success or false otherwise
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,28 +1,23 @@
|
|||
package xyz.alexcrea.cuanvil.dependency
|
||||
|
||||
import com.maddoxh.superEnchants.SuperEnchants
|
||||
import com.willfp.eco.core.gui.player
|
||||
import io.delilaheve.CustomAnvil
|
||||
import net.kyori.adventure.text.Component
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.ChatColor
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.HumanEntity
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.inventory.InventoryClickEvent
|
||||
import org.bukkit.event.inventory.PrepareAnvilEvent
|
||||
import org.bukkit.inventory.AnvilInventory
|
||||
import org.bukkit.inventory.Inventory
|
||||
import org.bukkit.inventory.InventoryView
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import xyz.alexcrea.cuanvil.anvil.AnvilCost
|
||||
import xyz.alexcrea.cuanvil.anvil.AnvilUseType
|
||||
import xyz.alexcrea.cuanvil.api.event.listener.CAClickResultBypassEvent
|
||||
import xyz.alexcrea.cuanvil.api.event.listener.CAEarlyPreAnvilBypassEvent
|
||||
import xyz.alexcrea.cuanvil.api.event.listener.CAPreAnvilBypassEvent
|
||||
import xyz.alexcrea.cuanvil.api.event.listener.CATreatAnvilResult2Event
|
||||
import xyz.alexcrea.cuanvil.api.event.listener.CATreatAnvilResultEvent
|
||||
import xyz.alexcrea.cuanvil.config.ConfigHolder
|
||||
import xyz.alexcrea.cuanvil.dependency.datapack.DataPackDependency
|
||||
import xyz.alexcrea.cuanvil.dependency.gui.GenericExternGuiTester
|
||||
import xyz.alexcrea.cuanvil.dependency.gui.ExternGuiTester
|
||||
import xyz.alexcrea.cuanvil.dependency.gui.GuiTesterSelector
|
||||
import xyz.alexcrea.cuanvil.dependency.packet.PacketManager
|
||||
import xyz.alexcrea.cuanvil.dependency.packet.PacketManagerSelector
|
||||
import xyz.alexcrea.cuanvil.dependency.plugins.*
|
||||
|
|
@ -32,14 +27,14 @@ import xyz.alexcrea.cuanvil.dependency.scheduler.TaskScheduler
|
|||
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil
|
||||
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.componentLore
|
||||
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_OUTPUT_SLOT
|
||||
import xyz.alexcrea.cuanvil.util.MetricsUtil.trackError
|
||||
import xyz.alexcrea.cuanvil.util.AnvilUseType
|
||||
import java.util.logging.Level
|
||||
|
||||
object DependencyManager {
|
||||
|
||||
lateinit var scheduler: TaskScheduler
|
||||
lateinit var packetManager: PacketManager
|
||||
var externGuiTester: GenericExternGuiTester = GenericExternGuiTester()
|
||||
var externGuiTester: ExternGuiTester? = null
|
||||
|
||||
var enchantmentSquaredCompatibility: EnchantmentSquaredDependency? = null
|
||||
var ecoEnchantCompatibility: EcoEnchantDependency? = null
|
||||
|
|
@ -50,8 +45,6 @@ object DependencyManager {
|
|||
|
||||
var axPlayerWarpsCompatibility: AxPlayerWarpsDependency? = null
|
||||
|
||||
var itemsAdderCompatibility: ItemsAdderDependency? = null
|
||||
|
||||
val genericDependencies = ArrayList<GenericPluginDependency>()
|
||||
|
||||
fun loadDependency() {
|
||||
|
|
@ -67,6 +60,7 @@ object DependencyManager {
|
|||
// Packet Manager
|
||||
val forceProtocolib = ConfigHolder.DEFAULT_CONFIG.config.getBoolean("force_protocolib", false)
|
||||
packetManager = PacketManagerSelector.selectPacketManager(forceProtocolib)
|
||||
externGuiTester = GuiTesterSelector.selectGuiTester
|
||||
|
||||
// Enchantment Squared dependency
|
||||
if (pluginManager.isPluginEnabled("EnchantsSquared")) {
|
||||
|
|
@ -103,12 +97,6 @@ object DependencyManager {
|
|||
axPlayerWarpsCompatibility = AxPlayerWarpsDependency()
|
||||
}
|
||||
|
||||
if (pluginManager.isPluginEnabled("ItemsAdder")){
|
||||
val dependency = ItemsAdderDependency(pluginManager.getPlugin("ItemsAdder")!!)
|
||||
itemsAdderCompatibility = dependency
|
||||
genericDependencies.add(dependency)
|
||||
}
|
||||
|
||||
// "Generic" dependencies
|
||||
if (pluginManager.isPluginEnabled("ToolStats"))
|
||||
genericDependencies.add(ToolStatsDependency(pluginManager.getPlugin("ToolStats")!!))
|
||||
|
|
@ -116,12 +104,6 @@ object DependencyManager {
|
|||
if (pluginManager.isPluginEnabled("ItemsAdder"))
|
||||
genericDependencies.add(GenericPluginDependency(pluginManager.getPlugin("ItemsAdder")!!))
|
||||
|
||||
if (pluginManager.isPluginEnabled("SuperEnchants")){
|
||||
val compatibility = SuperEnchantDependency(pluginManager.getPlugin("SuperEnchants")!! as SuperEnchants)
|
||||
if(compatibility.registerEnchantments())
|
||||
genericDependencies.add(compatibility)
|
||||
}
|
||||
|
||||
for (dependency in genericDependencies)
|
||||
dependency.redirectListeners()
|
||||
|
||||
|
|
@ -149,35 +131,26 @@ object DependencyManager {
|
|||
ecoEnchantCompatibility?.handleConfigReload()
|
||||
}
|
||||
|
||||
private fun logException(target: CommandSender, e: Exception) {
|
||||
CustomAnvil.instance.logger.log(
|
||||
Level.SEVERE,
|
||||
"Error while trying to handle custom anvil supported plugin: ",
|
||||
e
|
||||
)
|
||||
trackError(e)
|
||||
|
||||
// Finally, warn the player
|
||||
target.sendMessage(
|
||||
"[" + ChatColor.YELLOW.toString() + "CustomAnvil" + ChatColor.WHITE.toString() + "] " +
|
||||
ChatColor.RED.toString() + "Error while handling the anvil."
|
||||
)
|
||||
}
|
||||
|
||||
private fun logExceptionAndClear(target: CommandSender, inventory: Inventory, e: Exception) {
|
||||
// Just in case to avoid illegal items
|
||||
inventory.setItem(ANVIL_OUTPUT_SLOT, null)
|
||||
|
||||
logException(target, e)
|
||||
}
|
||||
|
||||
// Return true if should bypass (either by a dependency or error)
|
||||
// called before immutability test
|
||||
fun earlyTryEventPreAnvilBypass(event: PrepareAnvilEvent, player: HumanEntity): Boolean {
|
||||
try {
|
||||
return earlyUnsafeTryEventPreAnvilBypass(event, player)
|
||||
} catch (e: Exception) {
|
||||
logExceptionAndClear(event.view.player, event.inventory, e)
|
||||
CustomAnvil.instance.logger.log(
|
||||
Level.SEVERE,
|
||||
"Error while trying to handle custom anvil supported plugin: ",
|
||||
e
|
||||
)
|
||||
|
||||
// Just in case to avoid illegal items
|
||||
event.inventory.setItem(ANVIL_OUTPUT_SLOT, null)
|
||||
|
||||
// Finally, warn the player, maybe a lot of time but better warn than do nothing
|
||||
event.view.player.sendMessage(
|
||||
"[" + ChatColor.YELLOW.toString() + "CustomAnvil" + ChatColor.WHITE.toString() + "] " +
|
||||
ChatColor.RED.toString() + "Error while handling the anvil."
|
||||
)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
@ -190,7 +163,7 @@ object DependencyManager {
|
|||
var bypass = bypassEvent.isCancelled
|
||||
|
||||
// Test if the inventory is a gui(version specific)
|
||||
if (!bypass && externGuiTester.testIfGui(event.view)) bypass = true
|
||||
if (!bypass && (externGuiTester?.testIfGui(event.view) == true)) bypass = true
|
||||
|
||||
// Test if in an ax player warp rating gui
|
||||
if (!bypass && (axPlayerWarpsCompatibility?.testIfGui(player) == true)) bypass = true
|
||||
|
|
@ -199,16 +172,29 @@ object DependencyManager {
|
|||
}
|
||||
|
||||
// Return true if should bypass (either by a dependency or error)
|
||||
fun tryEventPreAnvilBypass(event: PrepareAnvilEvent, player: Player): Boolean {
|
||||
fun tryEventPreAnvilBypass(event: PrepareAnvilEvent, player: HumanEntity): Boolean {
|
||||
try {
|
||||
return unsafeTryEventPreAnvilBypass(event, player)
|
||||
} catch (e: Exception) {
|
||||
logExceptionAndClear(event.view.player, event.inventory, e)
|
||||
CustomAnvil.instance.logger.log(
|
||||
Level.SEVERE,
|
||||
"Error while trying to handle custom anvil supported plugin: ",
|
||||
e
|
||||
)
|
||||
|
||||
// Just in case to avoid illegal items
|
||||
event.inventory.setItem(ANVIL_OUTPUT_SLOT, null)
|
||||
|
||||
// Finally, warn the player, maybe a lot of time but better warn than do nothing
|
||||
event.view.player.sendMessage(
|
||||
"[" + ChatColor.YELLOW.toString() + "CustomAnvil" + ChatColor.WHITE.toString() + "] " +
|
||||
ChatColor.RED.toString() + "Error while handling the anvil."
|
||||
)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
private fun unsafeTryEventPreAnvilBypass(event: PrepareAnvilEvent, player: Player): Boolean {
|
||||
private fun unsafeTryEventPreAnvilBypass(event: PrepareAnvilEvent, player: HumanEntity): Boolean {
|
||||
// Run the event
|
||||
val bypassEvent = CAPreAnvilBypassEvent(event)
|
||||
Bukkit.getPluginManager().callEvent(bypassEvent)
|
||||
|
|
@ -233,24 +219,35 @@ object DependencyManager {
|
|||
|
||||
// Return null if there was an issue
|
||||
fun tryTreatAnvilResult(
|
||||
view: InventoryView,
|
||||
inventory: Inventory, // TODO REMOVE, use view instead on legacy removal
|
||||
player: HumanEntity,
|
||||
event: PrepareAnvilEvent,
|
||||
result: ItemStack,
|
||||
useType: AnvilUseType,
|
||||
cost: AnvilCost
|
||||
): ItemStack? {
|
||||
val treatEvent = CATreatAnvilResult2Event(view, inventory, useType, result, cost)
|
||||
cost: Int
|
||||
): CATreatAnvilResultEvent? {
|
||||
val treatEvent = CATreatAnvilResultEvent(event, useType, result, cost)
|
||||
try {
|
||||
unsafeTryTreatAnvilResult(treatEvent)
|
||||
return treatEvent.result
|
||||
return treatEvent;
|
||||
} catch (e: Exception) {
|
||||
logExceptionAndClear(player, inventory, e)
|
||||
CustomAnvil.instance.logger.log(
|
||||
Level.SEVERE,
|
||||
"Error while trying to handle custom anvil supported plugin: ",
|
||||
e
|
||||
)
|
||||
|
||||
// Just in case to avoid illegal items
|
||||
event.inventory.setItem(ANVIL_OUTPUT_SLOT, null)
|
||||
|
||||
// Finally, warn the player, maybe a lot of time but better warn than do nothing
|
||||
event.view.player.sendMessage(
|
||||
"[" + ChatColor.YELLOW.toString() + "CustomAnvil" + ChatColor.WHITE.toString() + "] " +
|
||||
ChatColor.RED.toString() + "Error while handling the anvil."
|
||||
)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun unsafeTryTreatAnvilResult(event: CATreatAnvilResult2Event) {
|
||||
private fun unsafeTryTreatAnvilResult(event: CATreatAnvilResultEvent) {
|
||||
Bukkit.getPluginManager().callEvent(event)
|
||||
|
||||
excellentEnchantsCompatibility?.treatAnvilResult(event)
|
||||
|
|
@ -261,7 +258,20 @@ object DependencyManager {
|
|||
try {
|
||||
return unsafeTryClickAnvilResultBypass(event, inventory)
|
||||
} catch (e: Exception) {
|
||||
logExceptionAndClear(event.view.player, event.inventory, e)
|
||||
CustomAnvil.instance.logger.log(
|
||||
Level.SEVERE,
|
||||
"Error while trying to handle custom anvil supported plugin: ",
|
||||
e
|
||||
)
|
||||
|
||||
// Just in case to avoid illegal items
|
||||
event.inventory.setItem(ANVIL_OUTPUT_SLOT, null)
|
||||
|
||||
// Finally, warn the player, maybe a lot of time but better warn than do nothing
|
||||
event.whoClicked.sendMessage(
|
||||
"[" + ChatColor.YELLOW.toString() + "CustomAnvil" + ChatColor.WHITE.toString() + "] " +
|
||||
ChatColor.RED.toString() + "Error while handling the anvil."
|
||||
)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
@ -287,31 +297,14 @@ object DependencyManager {
|
|||
}
|
||||
|
||||
// Test if the inventory is a gui(version specific)
|
||||
if (!bypass && externGuiTester.testIfGui(event.view)) bypass = true
|
||||
if (!bypass && (externGuiTester?.testIfGui(event.view) == true)) bypass = true
|
||||
|
||||
// Test if in an ax player warp rating gui
|
||||
if (!bypass && (axPlayerWarpsCompatibility?.testIfGui(event.view.player) == true)) bypass = true
|
||||
if (!bypass && (axPlayerWarpsCompatibility?.testIfGui(event.player) == true)) bypass = true
|
||||
|
||||
return bypass
|
||||
}
|
||||
|
||||
// Clone item and use plugin specific clone if needed
|
||||
fun cloneItem(player: HumanEntity, item: ItemStack): ItemStack {
|
||||
try {
|
||||
return unsafeCloneItem(item)
|
||||
} catch (e: Exception) {
|
||||
logException(player, e)
|
||||
return item.clone()
|
||||
}
|
||||
}
|
||||
|
||||
private fun unsafeCloneItem(item: ItemStack): ItemStack {
|
||||
val cloned = itemsAdderCompatibility?.tryClone(item)
|
||||
if(cloned != null) return cloned
|
||||
|
||||
return item.clone()
|
||||
}
|
||||
|
||||
fun stripLore(item: ItemStack): MutableList<Component?> {
|
||||
val dummy = item.clone()
|
||||
|
||||
|
|
|
|||
|
|
@ -6,29 +6,29 @@ object MinecraftVersionUtil {
|
|||
|
||||
val craftbukkitVersion: String?
|
||||
get() {
|
||||
val version = UpdateUtils.currentMinecraftVersion()
|
||||
if (version.major != 1) return null
|
||||
val versionParts = UpdateUtils.currentMinecraftVersionArray()
|
||||
if (versionParts[0] != 1) return null
|
||||
|
||||
return when (version.minor) {
|
||||
17 -> when (version.patch) {
|
||||
return when (versionParts[1]) {
|
||||
17 -> when (versionParts[2]) {
|
||||
0, 1 -> "1_17R1"
|
||||
else -> null
|
||||
}
|
||||
|
||||
18 -> when (version.patch) {
|
||||
18 -> when (versionParts[2]) {
|
||||
0, 1 -> "1_18R1"
|
||||
2 -> "1_18R2"
|
||||
else -> null
|
||||
}
|
||||
|
||||
19 -> when (version.patch) {
|
||||
19 -> when (versionParts[2]) {
|
||||
0, 1, 2 -> "1_19R1"
|
||||
3 -> "1_19R2"
|
||||
4 -> "1_19R3"
|
||||
else -> null
|
||||
}
|
||||
|
||||
20 -> when (version.patch) {
|
||||
20 -> when (versionParts[2]) {
|
||||
0, 1 -> "1_20R1"
|
||||
2 -> "1_20R2"
|
||||
3, 4 -> "1_20R3"
|
||||
|
|
@ -36,7 +36,7 @@ object MinecraftVersionUtil {
|
|||
else -> null
|
||||
}
|
||||
|
||||
21 -> when (version.patch) {
|
||||
21 -> when (versionParts[2]) {
|
||||
0, 1 -> "1_21R1"
|
||||
2, 3 -> "1_21R2"
|
||||
4 -> "1_21R3"
|
||||
|
|
@ -51,8 +51,4 @@ object MinecraftVersionUtil {
|
|||
}
|
||||
}
|
||||
|
||||
val isTooNewForSpigot: Boolean get() {
|
||||
return UpdateUtils.currentMinecraftVersion().major != 1
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ import xyz.alexcrea.cuanvil.update.Version
|
|||
import java.io.InputStreamReader
|
||||
|
||||
object DataPackDependency {
|
||||
private val START_DETECT_VERSION = Version(1, 20, 5)
|
||||
private val START_DETECT_VERSION = Version(1, 19, 0)
|
||||
|
||||
/**
|
||||
* Map of the latest CustomAnvil update related to the pack
|
||||
|
|
@ -145,7 +145,7 @@ object DataPackDependency {
|
|||
CustomAnvil.instance.logger.warning("Could not find material $name for item group $groupName")
|
||||
continue
|
||||
}
|
||||
group.addToPolicy(mat.key)
|
||||
group.addToPolicy(mat)
|
||||
}
|
||||
for (name in section.getStringList("groups")) {
|
||||
val otherGroup = MaterialGroupApi.getGroup(name)
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.dependency.economy
|
||||
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.plugin.Plugin
|
||||
import java.math.BigDecimal
|
||||
|
||||
interface EconomyManager {
|
||||
|
||||
companion object {
|
||||
var economy: EconomyManager? = null
|
||||
|
||||
fun setupEconomy(plugin: Plugin) {
|
||||
if (plugin.server.pluginManager.getPlugin("Vault") == null)
|
||||
return
|
||||
if (UnlockedEconomyManager.unlockedAvailable())
|
||||
economy = UnlockedEconomyManager(plugin)
|
||||
|
||||
if (economy == null || !economy!!.initialized())
|
||||
economy = VaultEconomyManager(plugin)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun initialized(): Boolean
|
||||
|
||||
// We assume "initialized" got checked before these function get called
|
||||
fun has(player: Player, money: BigDecimal): Boolean
|
||||
fun remove(player: Player, money: BigDecimal): Boolean
|
||||
|
||||
fun format(money: BigDecimal): String;
|
||||
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.dependency.economy
|
||||
|
||||
import io.delilaheve.util.ConfigOptions
|
||||
import net.milkbowl.vault2.economy.Economy
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.plugin.Plugin
|
||||
import java.math.BigDecimal
|
||||
|
||||
class UnlockedEconomyManager : EconomyManager {
|
||||
|
||||
val plugin: String
|
||||
val economy: Economy?
|
||||
|
||||
companion object {
|
||||
fun unlockedAvailable(): Boolean {
|
||||
try {
|
||||
Class.forName("net.milkbowl.vault2.economy.Economy")
|
||||
return true
|
||||
} catch (_: ClassNotFoundException) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(plugin: Plugin) {
|
||||
this.plugin = plugin.name
|
||||
|
||||
val rsp = plugin.server.servicesManager.getRegistration(Economy::class.java)
|
||||
economy = rsp?.getProvider()
|
||||
}
|
||||
|
||||
override fun initialized(): Boolean {
|
||||
return economy != null
|
||||
}
|
||||
|
||||
private fun currency(): String {
|
||||
val configured = ConfigOptions.usedCurrency
|
||||
|
||||
return if ("default".equals(configured, true))
|
||||
economy!!.getDefaultCurrency(plugin)
|
||||
else configured
|
||||
}
|
||||
|
||||
override fun has(player: Player, money: BigDecimal): Boolean {
|
||||
if (money.signum() <= 0) return true
|
||||
|
||||
return economy!!.has(
|
||||
plugin,
|
||||
player.uniqueId,
|
||||
player.world.name,
|
||||
currency(),
|
||||
money
|
||||
)
|
||||
}
|
||||
|
||||
override fun remove(player: Player, money: BigDecimal): Boolean {
|
||||
if (money.signum() <= 0) return true
|
||||
|
||||
return economy!!.withdraw(
|
||||
plugin,
|
||||
player.uniqueId,
|
||||
player.world.name,
|
||||
currency(),
|
||||
money
|
||||
)
|
||||
.transactionSuccess()
|
||||
}
|
||||
|
||||
override fun format(money: BigDecimal): String {
|
||||
return economy!!.format(plugin, money, currency())
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.dependency.economy
|
||||
|
||||
import net.milkbowl.vault.economy.Economy
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.plugin.Plugin
|
||||
import java.math.BigDecimal
|
||||
|
||||
class VaultEconomyManager : EconomyManager {
|
||||
|
||||
val economy: Economy?
|
||||
|
||||
constructor(plugin: Plugin) {
|
||||
val rsp = plugin.server.servicesManager.getRegistration(Economy::class.java)
|
||||
economy = rsp?.getProvider()
|
||||
}
|
||||
|
||||
override fun initialized(): Boolean {
|
||||
return economy != null
|
||||
}
|
||||
|
||||
override fun has(player: Player, money: BigDecimal): Boolean {
|
||||
if (money.signum() <= 0) return true
|
||||
|
||||
return economy!!.has(player, money.toDouble())
|
||||
}
|
||||
|
||||
override fun remove(player: Player, money: BigDecimal): Boolean {
|
||||
if (money.signum() <= 0) return true
|
||||
|
||||
return economy!!.withdrawPlayer(player, money.toDouble()).transactionSuccess()
|
||||
}
|
||||
|
||||
override fun format(money: BigDecimal): String {
|
||||
return economy!!.format(money.toDouble())
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue