Compare commits
99 Commits
Author | SHA1 | Date | |
---|---|---|---|
d4feda78ae | |||
81e65810e1 | |||
0dab832bfd | |||
1510960089 | |||
cdb0f267a3 | |||
81c15b6600 | |||
5efba6687c | |||
d0df4800f0 | |||
d73fcfd778 | |||
0993fbe15f | |||
f3372a13a5 | |||
cf702c0e48 | |||
afb608b609 | |||
523e4cb47a | |||
384893b01a | |||
904adf46f0 | |||
81dda85405 | |||
92c1b96fba | |||
62e58ba291 | |||
21b860b5c8 | |||
51d79c21c2 | |||
ce518ef338 | |||
4993c972e9 | |||
75744ccdd0 | |||
cb477cafb5 | |||
33ef557771 | |||
1d7e8a0732 | |||
e6047f3866 | |||
3ed3c99c15 | |||
3dd8467a58 | |||
d28d67f1bc | |||
d405c0dcff | |||
d7bac6d08f | |||
21d55563b7 | |||
c71d664a79 | |||
2612f4f7d8 | |||
e956c7dda7 | |||
757fcdf139 | |||
8b8890c408 | |||
f9463f58d1 | |||
7e5525bd00 | |||
44f8bb36b0 | |||
4012e532da | |||
455db78988 | |||
c532160fb5 | |||
dfae68050e | |||
6872dadca8 | |||
11d8c74a26 | |||
4282cd8a2f | |||
ac6fc430ff | |||
72d33ed7a2 | |||
4f885135e3 | |||
f3f3f66c38 | |||
1938a690c6 | |||
e39e70b690 | |||
f0b9a82d7e | |||
92585c4dee | |||
3e3a35d02a | |||
72ea5600fe | |||
191f548f5a | |||
be0b16e80a | |||
cb70874093 | |||
faff982585 | |||
c84c2cf30e | |||
a79f2e273a | |||
347b69b2a8 | |||
e5cb3b4a30 | |||
7d468115e0 | |||
bbb93bb0eb | |||
7cc2aef9d4 | |||
8e5d4c7a61 | |||
89cebb85c3 | |||
0d077ccdbb | |||
1bc03d7670 | |||
f192a5a2b5 | |||
bd00a59d08 | |||
8423eabc57 | |||
488d4c7589 | |||
753c7c6275 | |||
a856aa03e0 | |||
913cc5736e | |||
a5ae3cb295 | |||
7d940ee334 | |||
ea54492ccf | |||
30b8507b9f | |||
c5ffa2b0c4 | |||
a9cfea2d32 | |||
1bab972c13 | |||
d1c549fd20 | |||
c9ff3af6ac | |||
5089a721a0 | |||
a036c39dc3 | |||
a501a3cbb4 | |||
7875e9a705 | |||
ac5f032ce9 | |||
7784ee46a5 | |||
3c805ee284 | |||
3c4394d6fa | |||
d0f4ff11b7 |
33
Jenkinsfile
vendored
Normal file
33
Jenkinsfile
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
tools {
|
||||||
|
jdk 'JDK17'
|
||||||
|
}
|
||||||
|
stages {
|
||||||
|
stage('Build') {
|
||||||
|
steps {
|
||||||
|
echo 'Building...'
|
||||||
|
sh 'mvn clean & mvn validate & mvn compile'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Test') {
|
||||||
|
steps {
|
||||||
|
echo 'Testing...'
|
||||||
|
sh 'mvn test'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Verify') {
|
||||||
|
steps {
|
||||||
|
echo 'Verifying...'
|
||||||
|
sh 'mvn verify -Dmaven.test.skip=true'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Deploy') {
|
||||||
|
steps {
|
||||||
|
echo 'Deploying...'
|
||||||
|
sh 'mvn deploy -Dmaven.install.skip=true -Dmaven.test.skip=true'
|
||||||
|
archiveArtifacts artifacts: '**/target/*.jar', fingerprint: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
313
README.md
313
README.md
@ -1,7 +1,8 @@
|
|||||||
# Blacksmith
|
# Blacksmith
|
||||||
|
|
||||||
The blacksmith plugin adds a new blacksmith trait to Citizens NPCs. NPCs are able to repair a player's held item for a
|
The blacksmith plugin adds a blacksmith trait and a scrapper to Citizens NPCs. Blacksmith NPCs are able to repair a
|
||||||
fee. Costs are highly customizable.
|
player's held item for a fee. Costs are highly customizable. Scrapper NPCs can break down items into their crafting
|
||||||
|
recipe.
|
||||||
|
|
||||||
### Important changes from the original fork
|
### Important changes from the original fork
|
||||||
|
|
||||||
@ -10,12 +11,12 @@ fee. Costs are highly customizable.
|
|||||||
- By default, natural cost is used. The original fork made it cheaper the more damaged an item is, but natural cost
|
- By default, natural cost is used. The original fork made it cheaper the more damaged an item is, but natural cost
|
||||||
makes the cost increase the more damaged the item is.
|
makes the cost increase the more damaged the item is.
|
||||||
- EnchantmentTarget is used instead of a hard-coded list of repairable items
|
- EnchantmentTarget is used instead of a hard-coded list of repairable items
|
||||||
- All settings (except default reforge-able-items), both global and for each blacksmith, can be changed using commands,
|
- All settings, both global and for each blacksmith / scrapper, can be changed using commands,
|
||||||
and support tab-completion.
|
and support tab-completion.
|
||||||
- This plugin is not directly compatible with the original. If you are using the old one, you will need to set it up
|
- This plugin is not directly compatible with the original. If you are using the old one, you will need to set it up
|
||||||
again!
|
again!
|
||||||
|
|
||||||
### Dependencies
|
### Required dependencies
|
||||||
|
|
||||||
- Citizens2
|
- Citizens2
|
||||||
- Vault
|
- Vault
|
||||||
@ -23,42 +24,86 @@ fee. Costs are highly customizable.
|
|||||||
|
|
||||||
## Basic usage
|
## Basic usage
|
||||||
|
|
||||||
To create a new blacksmith, simply add the blacksmith trait to an NPC. Right-clicking the NPC will tell you if the
|
To create a new blacksmith, simply add the blacksmith trait to an NPC by selecting it with `/npc select`, and then using
|
||||||
currently held item is repairable by the blacksmith. If it is, the blacksmith should give a price quote. Right-clicking
|
`/trait add Blacksmith` (See Citizens' documentation for more details).
|
||||||
again starts the repair. The item should be given back or dropped after a random delay according to the set limits.
|
|
||||||
|
|
||||||
While costs are always set globally (no blacksmith can do the same job for cheaper), the blacksmith's messages,
|
To create a new scrapper, simply add the scrapper trait to an NPC by selecting it with `/npc select`, and then using
|
||||||
cool-down between each reforge, whether the item is dropped or given, the chance of failing or adding an enchantment,
|
`/trait add Scrapper` (See Citizens' documentation for more details).
|
||||||
the maximum number of added enchantments, max and min delays, the length of the cool-down and which items the blacksmith
|
|
||||||
is able to reforge can be changed individually.
|
Right-clicking the NPC will tell you if the currently held item is repairable by the blacksmith / salvageable by the
|
||||||
|
scrapper. If it is, the blacksmith / scrapper should give a price quote. Right-clicking again starts the repair /
|
||||||
|
salvage. The item should be given back or dropped after a random delay according to the set limits.
|
||||||
|
|
||||||
|
While costs are always set globally (no blacksmith or scrapper can do the same job for cheaper), the blacksmith /
|
||||||
|
scrapper's messages, cool-down between each reforge / salvage, whether the item is dropped or given, the chance of
|
||||||
|
failing or adding an enchantment, the maximum number of added enchantments, max and min delays, the length of the
|
||||||
|
cool-down and which items the blacksmith is able to reforge / salvage can be changed individually.
|
||||||
|
|
||||||
Also note: As a change from the original plugin, unless a value for an NPC has been explicitly set for that NPC, it will
|
Also note: As a change from the original plugin, unless a value for an NPC has been explicitly set for that NPC, it will
|
||||||
mirror the values set in config.yml. This also means that configuration values aren't populated automatically in
|
mirror the values set in config.yml. This also means that configuration values aren't populated automatically in
|
||||||
citizen's NPC save file. While you can manually set the values using the same keys as in config.yml, you should use the
|
citizen's NPC save file. While you can manually set the values using the same keys as in config.yml, you should use the
|
||||||
/blacksmith command when possible.
|
`/blacksmith` or `/scrapper` command when possible.
|
||||||
|
|
||||||
|
### Non-standard functionality
|
||||||
|
|
||||||
|
There is some non-standard optional functionality for blacksmiths and scrappers that goes beyond repairing things with
|
||||||
|
durability. They can all be enabled or disabled using configuration values.
|
||||||
|
|
||||||
|
- Blacksmiths can repair anvils if the option `reforgeAnvils` is enabled
|
||||||
|
- Scrappers can remove armor trim from items if `salvageArmorTrims` is enabled. This will always be done before
|
||||||
|
salvaging the item itself. If not enabled, the item is considered un-salvageable.
|
||||||
|
- Scrappers can remove netherite from items if `salvageNetherite` is enabled. This will be done if no armor trim exists,
|
||||||
|
before normal salvage. If not enabled, the item is considered un-salvageable.
|
||||||
|
- Scrappers can salvage enchanted items, and return some XP based on the enchantment set if `salvageEnchanted` is
|
||||||
|
enabled. If not enabled, the item is considered un-salvageable.
|
||||||
|
- Scrappers can salvage just about anything with a crafting table recipe if `extendedSalvageEnabled` is enabled. As long
|
||||||
|
as you have the amount of items produced by a crafting recipe, you can undo the recipe. Four planks can be salvaged
|
||||||
|
into a log as an example.
|
||||||
|
|
||||||
### Special behavior
|
### Special behavior
|
||||||
|
|
||||||
In addition to just being able to repair items, blacksmiths have some random features which can be cool or annoying:
|
In addition to just being able to repair items, blacksmiths / scrappers have some random features which can be cool or
|
||||||
|
annoying:
|
||||||
|
|
||||||
- There is a chance that blacksmiths fail to repair an item, leaving it at about the same durability as before. Use
|
- There is a chance that blacksmiths / scrappers fail to repair an item, leaving it at about the same durability as
|
||||||
|
before (scrappers with `extendedSalvageEnabled` turned on might cause items in a stack to be lost). Use
|
||||||
failReforgeChance to control the chance. Set it to 0 to remove the feature.
|
failReforgeChance to control the chance. Set it to 0 to remove the feature.
|
||||||
- There is a chance a blacksmith may add an enchantment to a reforged item. You can control the probability using
|
- There is a chance a blacksmith may add an enchantment to a reforged item. You can control the probability using
|
||||||
extraEnchantmentChance, and set the maximum number of enchantments using maxEnchantments
|
extraEnchantmentChance, and set the maximum number of enchantments using maxEnchantments. EnchantmentBlockList can be
|
||||||
|
used to block any enchantments you don't want to randomly grant.
|
||||||
|
|
||||||
|
### Scrapper basics
|
||||||
|
|
||||||
|
A scrapper will produce salvage for a damage-able item by calculating the amount of items returned based on items in the
|
||||||
|
recipe, and the percentage of durability left on the item. To avoid returning relatively worthless items instead of
|
||||||
|
valuable items, `trashSalvage` can be configured. Trash salvage will only be returned if all non-trash items are
|
||||||
|
returned as well. A scrapper will by default only salvage damage-able items (same as blacksmiths), but enabling
|
||||||
|
`extendedSalvageEnabled` for a scrapper will allow it to salvage any crafting table recipe. Note that to salvage for
|
||||||
|
example planks into wood, four wood will be taken.
|
||||||
|
|
||||||
|
When an item is salvaged, EXP will be returned based on enchantments on the item.
|
||||||
|
|
||||||
|
Note that sticks are valid items to be handled by Scrappers if extended salvage is enabled. The item is also the default
|
||||||
|
item for selecting NPCs in Citizens. If you find the NPC selection message annoying, and don't normally use sticks for
|
||||||
|
selection, you can change the item in Citizens' config and replace it with STRUCTURE_VOID or some other unobtainable
|
||||||
|
item.
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
| Command | Arguments | Description |
|
| Command | Arguments | Description |
|
||||||
| --- | --- | --- |
|
|-------------------|-------------------------------|----------------------------------------------------------------------------------------------|
|
||||||
| /blacksmith | \<option> \[new-value] | Changes a configuration option for the selected blacksmith (use Citizens' /npc select first) |
|
| /blacksmith | \<option> \[new-value] | Changes a configuration option for the selected blacksmith (use Citizens' /npc select first) |
|
||||||
| /blacksmithconfig | \<reload/option> \[new-value] | Changes a default/global configuration value |
|
| /blacksmithConfig | \<reload/option> \[new-value] | Changes a default/global blacksmith configuration value |
|
||||||
|
| /scrapper | \<option> \[new-value] | Changes a configuration option for the selected scrapper (use Citizens' /npc select first) |
|
||||||
|
| /scrapperConfig | \<reload/option> \[new-value] | Changes a default/global scrapper configuration value |
|
||||||
| /preset | \<preset>\[:filter] | Displays all materials included in the given preset, after applying the filter if set |
|
| /preset | \<preset>\[:filter] | Displays all materials included in the given preset, after applying the filter if set |
|
||||||
|
|
||||||
For /blacksmith and /blacksmithconfig, if a new value isn't specified, the current value is displayed instead.
|
For /blacksmith, /blacksmithConfig, /scrapper and /scrapperConfig, if a new value isn't specified, a description of the
|
||||||
|
configuration option, and the current value, is displayed instead.
|
||||||
|
|
||||||
For /blacksmith, using -1 or null as the value will clear a custom value, making the NPC use the default value set in
|
For /blacksmith or /scrapper, using -1 or null as the value will clear a custom value, making the NPC use the default
|
||||||
the config instead. Additionally, every value overridden for an NPC will display a marker (default: \[NPC]) when
|
value set in the config instead. Additionally, every value overridden for an NPC will display a marker (default: \[NPC])
|
||||||
displaying the current value.
|
when displaying the current value.
|
||||||
|
|
||||||
Note: basePrice, pricePerDurabilityPoint and enchantmentCost can be set like: `/blacksmithconfig option 4` or
|
Note: basePrice, pricePerDurabilityPoint and enchantmentCost can be set like: `/blacksmithconfig option 4` or
|
||||||
like `/blacksmithconfig option material/enchantment 4` depending on whether you are setting the default or an override
|
like `/blacksmithconfig option material/enchantment 4` depending on whether you are setting the default or an override
|
||||||
@ -66,108 +111,186 @@ for a specific material/enchantment. For /blacksmithconfig <basePrice/pricePerDu
|
|||||||
material/enchantment>, using -1 or null as the value will clear the cost for the specified material/enchantment, using
|
material/enchantment>, using -1 or null as the value will clear the cost for the specified material/enchantment, using
|
||||||
the default one instead.
|
the default one instead.
|
||||||
|
|
||||||
|
basePrice and pricePerDurabilityPoint support using a wildcard "*" to set the price for multiple groups of materials at
|
||||||
|
once. `/blacksmithconfig basePrice golden* 43` would set the price of any material starting with "GOLDEN" to 43. You can
|
||||||
|
also set `netherite*: 34` directly in the config file to set the price of all netherite materials to 34.
|
||||||
|
|
||||||
### Presets and filters:
|
### Presets and filters:
|
||||||
|
|
||||||
Note: All of these can be used when specifying reforge-able items, such as
|
**Presets are a nice way to make specialized blacksmiths / scrappers by specifying categories of materials, instead of
|
||||||
|
manually listing every material manually. They can only be used for the `reforgeAbleItems` and `salvageAbleItems`
|
||||||
|
options.**
|
||||||
|
|
||||||
|
Note: All of these can be used when specifying reforge-able and salvage-able items, such as
|
||||||
"preset:weapon-smith:bow,preset:armor_smith:gold,PRESET:TOOL_SMITH,shield"
|
"preset:weapon-smith:bow,preset:armor_smith:gold,PRESET:TOOL_SMITH,shield"
|
||||||
|
|
||||||
The format of reforge-able items requires each preset/material to be separated by a comma. If specifying a preset
|
The format of reforge-able items requires each preset/material to be separated by a comma. If specifying a preset
|
||||||
instead of a material, start by typing "preset:". Then you can type WEAPON_SMITH, ARMOR_SMITH or TOOL_SMITH. If you
|
instead of a material, start by typing "preset:". Then you can type BLACKSMITH, WEAPON_SMITH, ARMOR_SMITH or TOOL_SMITH.
|
||||||
want, you can add another colon and one of the filters supported by the preset. For example: "preset:WEAPON_SMITH:BOW"
|
If you want, you can add another colon and one of the filters supported by the preset.
|
||||||
to make the blacksmith only repair bows. You can use the same preset several times with different filters. For
|
For example: "preset:WEAPON_SMITH:BOW" to make the blacksmith only repair bows and crossbows. You can use the same
|
||||||
example: "preset:ARMOR_SMITH:DIAMOND,preset:ARMOR_SMITH:NETHERITE" would allow the blacksmith to repair all diamond and
|
preset several times with different filters. For example: "preset:ARMOR_SMITH:DIAMOND,preset:ARMOR_SMITH:NETHERITE"
|
||||||
netherite armor.
|
would allow the blacksmith to repair all diamond and netherite armor.
|
||||||
|
|
||||||
|
Presets and filters can also be negated by applying a "-" character in front of the material name. For example,
|
||||||
|
"-SHIELD" would make shields unrepairable, even if included in a listed preset. "preset:WEAPON_SMITH,-SHIELD"
|
||||||
|
would allow the blacksmith to repair any weapon included in the WEAPON_SMITH preset except shields.
|
||||||
|
"preset:BLACKSMITH,-ELYTRA"would allow the blacksmith to repair any repairable item, except elytra. You can also negate
|
||||||
|
entire presets or filters. For example: "preset:blacksmith,-preset:armor-smith:diamond" would allow a blacksmith to
|
||||||
|
repair all items, except diamond armor.
|
||||||
|
|
||||||
All currently supported presets, and available filters for each preset:
|
All currently supported presets, and available filters for each preset:
|
||||||
|
|
||||||
- WEAPON_SMITH:
|
- BLACKSMITH (WEAPON_SMITH + ARMOR_SMITH + TOOL_SMITH)
|
||||||
- BOW
|
- GOLD (all gold armor, tools and weapons)
|
||||||
- SWORD
|
- IRON (all iron armor, tools and weapons)
|
||||||
- RANGED
|
- DIAMOND (all diamond armor, tools and weapons)
|
||||||
- ARMOR_SMITH:
|
- NETHERITE (all netherite armor, tools and weapons)
|
||||||
- LEATHER
|
- WEAPON_SMITH: (RANGED + SWORD + SHIELD)
|
||||||
- IRON
|
- BOW (bows and crossbows)
|
||||||
- CHAINMAIL
|
- SWORD (swords)
|
||||||
- GOLD
|
- RANGED (bows, crossbows and tridents)
|
||||||
- DIAMOND
|
- ARMOR_SMITH: (HELMET + BOOTS + LEGGINGS + CHESTPLATE + ELYTRA)
|
||||||
- NETHERITE
|
- LEATHER (all pieces of leather armor)
|
||||||
- HELMET
|
- IRON (all pieces of iron armor)
|
||||||
- BOOTS
|
- CHAINMAIL (all pieces of chainmail armor)
|
||||||
- LEGGINGS
|
- GOLD (all pieces of gold armor)
|
||||||
- CHESTPLATE
|
- DIAMOND (all pieces of diamond armor)
|
||||||
- TOOL_SMITH
|
- NETHERITE (all pieces of netherite armor)
|
||||||
- WOOD
|
- HELMET (all helmets)
|
||||||
- STONE
|
- BOOTS (all boots)
|
||||||
- IRON
|
- LEGGINGS (all leggings)
|
||||||
- GOLD
|
- CHESTPLATE (all chest-plates)
|
||||||
- DIAMOND
|
- TOOL_SMITH: (PICKAXE + AXE + HOE + SHOVEL + MISC)
|
||||||
- NETHERITE
|
- WOOD (all wood tools)
|
||||||
- PICKAXE
|
- STONE (all stone tools)
|
||||||
- AXE
|
- IRON (all iron tools)
|
||||||
- HOE
|
- GOLD (all gold tools)
|
||||||
- SHOVEL
|
- DIAMOND (all diamond tools)
|
||||||
- MISC
|
- NETHERITE (all netherite tools)
|
||||||
|
- PICKAXE (all pickaxes)
|
||||||
|
- AXE (all axes)
|
||||||
|
- HOE (all hoes)
|
||||||
|
- SHOVEL (all shovels)
|
||||||
|
- MISC (FISHING_ROD + SHEARS + FLINT_AND_STEEL)
|
||||||
|
|
||||||
## Permissions
|
## Permissions
|
||||||
|
|
||||||
| Permission node | Description |
|
| Permission node | Description |
|
||||||
| --- | --- |
|
|------------------|----------------------------------------------------------------------------------------|
|
||||||
| blacksmith.admin | Allows overall blacksmith configuration |
|
| blacksmith.admin | Allows overall blacksmith and scrapper configuration. |
|
||||||
| blacksmith.edit | Allows changing settings for the selected blacksmith NPC |
|
| blacksmith.edit | Allows changing settings for the selected blacksmith or scrapper NPC. |
|
||||||
| blacksmith.use | Allows the player to repair items using blacksmiths |
|
| blacksmith.use | Allows the player to repair items using blacksmiths and salvage items using scrappers. |
|
||||||
|
|
||||||
## Configuration options
|
## Configuration options
|
||||||
|
|
||||||
### Plugin Options
|
### Plugin Options
|
||||||
|
|
||||||
| Key | Value type | Description |
|
| Key | Value type | Description |
|
||||||
| --- | --- | --- |
|
|----------|------------|----------------------------------------------------------------------------------------------|
|
||||||
| language | string | The language used for this plugin. Only "en" is supported, unless you add a custom language. |
|
| language | string | The language used for this plugin. Only "en" is supported, unless you add a custom language. |
|
||||||
|
|
||||||
### Global-only options
|
### Blacksmith global-only options
|
||||||
|
|
||||||
| Key | Value type | Description |
|
| Key | Value type | Default | Description |
|
||||||
| --- | --- | --- |
|
|---------------------------|-------------------------|----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| basePrice | positive decimal number | The base price which has to be paid regardless of the durability remaining for an item. Setting this without specifying a material sets the basePrice for any item the basePrice has not been set for. |
|
| basePrice | positive decimal number | default: 10.0 | The base price which has to be paid regardless of the durability remaining for an item. Setting this without specifying a material sets the basePrice for any item the basePrice has not been set for. You can use for example "netherite*: 10" to set the value for any material beginning with "netherite". |
|
||||||
| pricePerDurabilityPoint | positive decimal number | The price added for each durability point present/missing (depends on whether natural cost is set to true or false). Setting this without specifying a material sets the pricePerDurabilityPoint for any item the pricePerDurabilityPoint has not been set for. |
|
| pricePerDurabilityPoint | positive decimal number | default: 0.005 | The price added for each durability point present/missing (depends on whether natural cost is set to true or false). Setting this without specifying a material sets the pricePerDurabilityPoint for any item the pricePerDurabilityPoint has not been set for. You can use for example "netherite*: 10" to set the value for any material beginning with "netherite". |
|
||||||
| enchantmentCost | positive decimal number | The added cost for each level of an enchantment present on the item. The cost can be set for specific enchantments. Not specifying an enchantment sets the value for all enchantments without a set value.
|
| enchantmentCost | positive decimal number | default: 5 | The added cost for each level of an enchantment present on the item. The cost can be set for specific enchantments. Not specifying an enchantment sets the value for all enchantments without a set value. |
|
||||||
| useNaturalCost | true/false | If true, each missing durability will add to the cost (price = basePrice + missingDurability * pricePerDurabilityPoint + enchantmentCost). If false, durability will be used to calculate the cost instead of missingDurability (this was the behavior before natural cost was added). |
|
| useNaturalCost | true/false | true | If true, each missing durability will add to the cost (price = basePrice + missingDurability * pricePerDurabilityPoint + enchantmentCost). If false, durability will be used to calculate the cost instead of missingDurability (this was the behavior before natural cost was added). |
|
||||||
| showExactTime | true/false | If true, blacksmiths will display exact time remaining in minutes and seconds, instead of vague expressions |
|
| showExactTime | true/false | false | If true, blacksmiths will display exact time remaining in minutes and seconds, instead of vague expressions. |
|
||||||
|
| chippedAnvilReforgingCost | positive decimal number | 10.0 | The price for reforging a chipped anvil (slightly damaged). No other costs apply! |
|
||||||
|
| damagedAnvilReforgingCost | positive decimal number | 20.0 | The price for reforging a damaged anvil (very damaged). No other costs apply! |
|
||||||
|
|
||||||
### Per-npc (with default values set in config.yml)
|
### Blacksmith per-npc (with default values set in config.yml)
|
||||||
|
|
||||||
#### Configuration values
|
#### Configuration values
|
||||||
|
|
||||||
| Key | Value type | Description |
|
| Key | Value type | Default | Description |
|
||||||
| --- | --- | --- |
|
|--------------------------------|-----------------------------------------|---------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| dropItem | true/false | Whether the blacksmith should drop the repaired item on the ground (instead of putting it into the player's inventory). |
|
| dropItem | true/false | true | Whether the blacksmith should drop the repaired item on the ground (instead of putting it into the player's inventory). |
|
||||||
| disableCoolDown | true/false | Whether to completely disable the cool-down between repairs. |
|
| failReforgeChance | 0-100 | 10 | The chance of the blacksmith failing to repair an item (further damaging it, or just repairing it a bit), and either removing or downgrading all enchantments (if failReforgeRemovesEnchantments is true). |
|
||||||
| disableDelay | true/false | Whether to completely disable the delay required to reforge an item. |
|
| failReforgeRemovesEnchantments | true/false | false | Whether a failed reforge should remove or downgrade all enchantments on the item. |
|
||||||
| failReforgeChance | 0-100 | The chance of the blacksmith failing to repair an item. |
|
| extraEnchantmentChance | 0-100 | 5 | The chance of the blacksmith adding an enchantment to an item. |
|
||||||
| extraEnchantmentChance | 0-100 | The chance of the blacksmith adding an enchantment to an item. |
|
| maxEnchantments | 0-10 | 3 | The maximum number of different enchantments a blacksmith can add. |
|
||||||
| maxEnchantments | 0-10 | The maximum number of different enchantments a blacksmith can add. |
|
| maxReforgeWaitTimeSeconds | 0-3600 | 30 | The maximum number of seconds a player needs to wait for an item to be repaired. |
|
||||||
| maxReforgeDelay | 0-3600 | The maximum number of seconds a player needs to wait for an item to be repaired. |
|
| minReforgeWaitTimeSeconds | 0-3600 | 5 | The minimum number of seconds a player needs to wait for an item to be repaired. |
|
||||||
| minReforgeDelay | 0-3600 | The minimum number of seconds a player needs to wait for an item to be repaired. |
|
| reforgeCoolDownSeconds | 0-3600 | 60 | The cool-down, in seconds, a player has to wait between each time they use one specific blacksmith. |
|
||||||
| reforgeCoolDown | 0-3600 | The cool-down, in seconds, a player has to wait between each time they use one specific blacksmith. |
|
| reforgeAbleItems | DIAMOND_LEGGINGS,GOLD-pickaxe,bow, etc. | [ ] | Specifies which items this blacksmith is able to reforge. If set to "" or null, all normally repairable items can be repaired. If set to a list of items, only the items specified can be repaired. Some presets have been included for ease of use. Use a preset by specifying "preset:sword-smith" instead of a material such as "gold-pickaxe". |
|
||||||
| reforgeAbleItems | DIAMOND_LEGGINGS,GOLD-pickaxe,bow, etc. | Specifies which items this blacksmith is able to reforge. If set to "" or null, all normally repairable items can be repaired. If set to a list of items, only the items specified can be repaired. Some presets have been included for ease of use. Use a preset by specifying "preset:sword-smith" instead of a material such as "gold-pickaxe". |
|
| blacksmithTitle | text string | blacksmith | The title displayed as part of the message explaining that a blacksmith doesn't recognize a player's held item |
|
||||||
| blacksmithTitle | text string | The title displayed as part of the message explaining that a blacksmith doesn't recognize a player's held item |
|
| enchantmentBlockList | string list | binding_curse,mending,vanishing_curse | A string list of all enchantments a blacksmith should not be allowed to add to items. |
|
||||||
| enchantmentBlocklist | string list | A string list of all enchantments a blacksmith should not be allowed to add to items. |
|
| reforgeAnvils | true/false | false | Whether to allow the blacksmith to reforge anvils. If enabled, chipped and damaged anvils will be replaced with a normal anvil. |
|
||||||
|
|
||||||
#### Messages
|
#### Messages
|
||||||
|
|
||||||
| Message Key | Explanation |
|
| Message Key | Default | Explanation |
|
||||||
| --- | --- |
|
|--------------------------|-------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|
|
||||||
| busyPlayerMessage | The message displayed when the blacksmith is serving another player |
|
| busyPlayerMessage | &cI'm busy at the moment. Come back later! | The message displayed when the blacksmith is serving another player. |
|
||||||
| busyReforgeMessage | The message displayed when the blacksmith is busy reforging an item |
|
| busyReforgeMessage | &cI'm working on it. Be patient! I'll finish {time}! | The message displayed when the blacksmith is busy reforging an item. |
|
||||||
| coolDownUnexpiredMessage | The message displayed when the player has to wait for the cool-down to expire before using the blacksmith again |
|
| coolDownUnexpiredMessage | &cYou've already had your chance! Give me a break! I'll be ready {time}! | The message displayed when the player has to wait for the cool-down to expire before using the blacksmith again. |
|
||||||
| costMessage | The message displayed when telling a player about the cost of repairing an item |
|
| costMessage | &eIt will cost &a{cost}&e to reforge that &a{item}&e! Click again to reforge! | The message displayed when telling a player about the cost of repairing an item. |
|
||||||
| failReforgeMessage | The message displayed when a blacksmith fails to reforge an item |
|
| failReforgeMessage | &cWhoops! Didn't mean to do that! Maybe next time? | The message displayed when a blacksmith fails to reforge an item. |
|
||||||
| insufficientFundsMessage | The message displayed when a player is unable to pay for reforging an item |
|
| insufficientFundsMessage | &cYou don't have enough money to reforge that item! | The message displayed when a player is unable to pay for reforging an item. |
|
||||||
| invalidItemMessage | The message displayed when a blacksmith is presented an item which it cannot repair |
|
| invalidItemMessage | &cI'm sorry, but I'm a/an {title}, I don't know how to reforge that! | The message displayed when a blacksmith is presented an item which it cannot repair. |
|
||||||
| itemChangedMessage | The message displayed when a player changes their item after being shown the repair cost |
|
| itemChangedMessage | &cThat's not the item you wanted to reforge before! | The message displayed when a player changes their item after being shown the repair cost. |
|
||||||
| startReforgeMessage | The message displayed when a blacksmith starts reforging an item |
|
| startReforgeMessage | &eOk, let's see what I can do... | The message displayed when a blacksmith starts reforging an item. |
|
||||||
| successMessage | The message displayed when a blacksmith successfully repairs an item |
|
| successMessage | There you go! All better! | The message displayed when a blacksmith successfully repairs an item. |
|
||||||
| notDamagedMessage | The message displayed if a player tries to reforge an item with full durability |
|
| notDamagedMessage | &cThat item is not in need of repair | The message displayed if a player tries to reforge an item with full durability. |
|
||||||
|
| noItemMessage | Please present the item you want to reforge | The message displayed when a blacksmith is clicked with an empty hand |
|
||||||
|
|
||||||
|
### Scrapper global-only options
|
||||||
|
|
||||||
|
| Key | Value type | Default | Description |
|
||||||
|
|-----------------------|------------------------------------------------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| salvagePrice | positive decimal number | 0 | The cost of using a scrapper to salvage an item. |
|
||||||
|
| armorTrimSalvagePrice | positive decimal number | 5 | The cost of using a scrapper to remove armor trim from an item. |
|
||||||
|
| netheriteSalvagePrice | positive decimal number | 15 | The cost of using a scrapper to remove netherite from an item. |
|
||||||
|
| showExactTime | true/false | false | If true, scrappers will display exact time remaining in minutes and seconds, instead of vague expressions. |
|
||||||
|
| giveExperience | true/false | true | If true, each enchantment level on the salvaged item will give one EXP level as salvage. |
|
||||||
|
| trashSalvage | TARGET_MATERIAL:IGNORED_MATERIAL\[,\*_TARGET2:\*_IGNORED2] | `"*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD;SHIELD;*_BOW:STICK"` | The items that should be deferred when calculating partial salvage. Because receiving just the sticks when salvaging a diamond pickaxe is kind of sad, this allows specifying for example: `*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD;SHIELD;*_BOW:STICK` (the default) for deferring sticks in salvage for shovels, pickaxes, axes, hoes and swords. A `:` character splits selected items and the trash salvage. Different item specifications are split by a `;` character. Use `,` to split separate trash salvages when using commands, like: `SHIELD:STICK,BOW_STRING`. |
|
||||||
|
|
||||||
|
### Scrapper per-npc (with default values set in config.yml)
|
||||||
|
|
||||||
|
#### Configuration values
|
||||||
|
|
||||||
|
| Key | Value type | Default | Description |
|
||||||
|
|---------------------------|-----------------------------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| dropItem | true/false | true | Whether the scrapper should drop the repaired item on the ground (instead of putting it into the player's inventory). |
|
||||||
|
| failSalvageChance | 0-100 | 0 | The chance of the scrapper failing to salvage an item, either further damaging the item, partly repairing the item or causing some items to disappear. |
|
||||||
|
| salvageAbleItems | DIAMOND_LEGGINGS,GOLD-pickaxe,bow, etc. | [] | Specifies which items this scrapper is able to salvage. If set to "" or null, all normally repairable items can be salvaged. If set to a list of items, only the items specified can be salvaged. Some presets have been included for ease of use. Use a preset by specifying "preset:sword-smith" instead of a material such as "gold-pickaxe". |
|
||||||
|
| maxSalvageWaitTimeSeconds | 0-3600 | 5 | The maximum number of seconds a player needs to wait for an item to be salvaged. |
|
||||||
|
| minSalvageWaitTimeSeconds | 0-3600 | 30 | The minimum number of seconds a player needs to wait for an item to be salvaged. |
|
||||||
|
| salvageCoolDownSeconds | 0-3600 | 60 | The cool-down, in seconds, a player has to wait between each time they use one specific scrapper. |
|
||||||
|
| scrapperTitle | text string | scrapper | The title displayed as part of the message explaining that a scrapper doesn't recognize a player's held item. |
|
||||||
|
| extendedSalvageEnabled | true/false | false | Whether to enable the extended salvage behavior for this scrapper. As long as it is allowed by salvageAbleItems and it can be crafted in a crafting table, it can be salvaged. This includes things like four planks salvaged into wood. |
|
||||||
|
| salvageEnchanted | true/false | false | Whether the scrapper is able to salvage enchanted items. This is disabled by default as it's very easy to accidentally salvage heavily enchanted items if one is not careful. |
|
||||||
|
| salvageArmorTrims | true/false | true | Whether the scrapper is able to salvage armor trims from items. |
|
||||||
|
| salvageNetherite | true/false | true | Whether the scrapper is able to salvage netherite items into diamond items. |
|
||||||
|
|
||||||
|
#### Messages
|
||||||
|
|
||||||
|
| Message Key | Default | Explanation |
|
||||||
|
|---------------------------------|-----------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| busyPlayerMessage | &cI'm busy at the moment. Come back later! | The message displayed when the scrapper is serving another player. |
|
||||||
|
| busySalvageMessage | &cI'm working on it. Be patient! I'll finish {time}! | The message displayed when the scrapper is busy salvaging an item. |
|
||||||
|
| coolDownUnexpiredMessage | &cYou've already had your chance! Give me a break! I'll be ready {time}! | The message displayed when the player has to wait for the cool-down to expire before using the scrapper again. |
|
||||||
|
| invalidItemMessage | &cI'm sorry, but I'm a/an {title}, I don't know how to salvage that! | The message displayed when a scrapper is presented an item which it cannot salvage. |
|
||||||
|
| tooDamagedForSalvageMessage | &cThat item is too damaged to be salvaged into anything useful | The message displayed when a scrapper is presented with an item too damaged to produce salvage. |
|
||||||
|
| successSalvagedMessage | There you go! | The message displayed when a scrapper successfully repairs an item. |
|
||||||
|
| failSalvageMessage | &cWhoops! The item broke! Maybe next time? | The message displayed when a scrapper fails to salvage an item. |
|
||||||
|
| failExtendedSalvageMessage | &cWhoops! I was unable to extract much, if any, salvage! Maybe next time? | The message displayed when a scrapper fails to salvage an item without durability (only relevant is extended salvage is enabled). |
|
||||||
|
| itemChangedMessage | &cThat's not the item you wanted to salvage before! | The message displayed when a player changes their item after being shown the salvage cost. |
|
||||||
|
| startSalvageMessage | &eOk, let's see what I can do... | The message displayed when a scrapper starts salvaging an item. |
|
||||||
|
| insufficientFundsMessage | &cYou don't have enough money to salvage an item! | The message displayed when a player is unable to pay for salvaging an item. |
|
||||||
|
| costMessage | &eIt will cost &a{cost}&e to salvage that &a{item}&e! {yield} &eClick again to salvage! | The message displayed when telling a player about the cost of salvaging an item. |
|
||||||
|
| costMessageArmorTrim | &eIt will cost &a{cost}&e to salvage that &a{item}&e's armor trim! | The message displayed when telling a player about the cost of salvaging an item's armor trim. |
|
||||||
|
| costMessageNetherite | &eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond! | The message displayed when telling a player about the cost of salvaging a netherite item into a diamond item. |
|
||||||
|
| fullSalvageMessage | &aI should be able to extract all components from that pristine item.&r | The message displayed as part of costMessage's yield placeholder if all components will be returned. |
|
||||||
|
| partialSalvageMessage | &cI cannot extract all components from that damaged item.&r | The message displayed as part of costMessage's yield placeholder if only some components will be returned. |
|
||||||
|
| cannotSalvageEnchantedMessage | &cI'm sorry, but I'm unable to salvage enchanted items! | The message displayed when telling a player that the scrapper cannot salvage enchanted items. |
|
||||||
|
| cannotSalvageArmorTrimMessage | &cI'm sorry, but I'm unable to salvage armor trims! | The message displayed when telling a player that the scrapper cannot salvage items with armor trim. |
|
||||||
|
| armorTrimSalvageNotFoundMessage | &cI'm sorry, but I don't know how to salvage that armor trim! | The message displayed when telling a player that the scrapper cannot find the correct items to return as armor trim salvage. This will happen if more armor trim materials are added, or the Spigot API is changed. |
|
||||||
|
| cannotSalvageNetheriteMessage | &cI'm sorry, but I'm unable to salvage netherite items! | The message displayed when telling a player that the scrapper cannot salvage netherite items. |
|
||||||
|
| noItemMessage | Please present the item you want to salvage | The message displayed when a scrapper is clicked with an empty hand |
|
||||||
|
|
||||||
## Language customization
|
## Language customization
|
||||||
|
|
||||||
|
111
pom.xml
111
pom.xml
@ -6,12 +6,13 @@
|
|||||||
|
|
||||||
<groupId>net.knarcraft</groupId>
|
<groupId>net.knarcraft</groupId>
|
||||||
<artifactId>blacksmith</artifactId>
|
<artifactId>blacksmith</artifactId>
|
||||||
<version>1.0.2-SNAPSHOT</version>
|
<version>1.1.3-SNAPSHOT</version>
|
||||||
<name>Blacksmith</name>
|
<name>Blacksmith</name>
|
||||||
<description>Blacksmith Character for the CitizensAPI</description>
|
<description>Blacksmith NPC for the Citizens API</description>
|
||||||
|
|
||||||
<!-- Properties -->
|
<!-- Properties -->
|
||||||
<properties>
|
<properties>
|
||||||
|
<java.version>16</java.version>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<build.number>Unknown</build.number>
|
<build.number>Unknown</build.number>
|
||||||
</properties>
|
</properties>
|
||||||
@ -24,20 +25,34 @@
|
|||||||
</repository>
|
</repository>
|
||||||
<repository>
|
<repository>
|
||||||
<id>citizens-repo</id>
|
<id>citizens-repo</id>
|
||||||
<url>http://repo.citizensnpcs.co/</url>
|
<url>https://repo.citizensnpcs.co/</url>
|
||||||
</repository>
|
</repository>
|
||||||
<repository>
|
<repository>
|
||||||
<id>vault-repo</id>
|
<id>jitpack.io</id>
|
||||||
<url>http://nexus.hc.to/content/repositories/pub_releases</url>
|
<url>https://jitpack.io</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>knarcraft-repo</id>
|
||||||
|
<url>https://git.knarcraft.net/api/packages/EpicKnarvik97/maven</url>
|
||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>knarcraft-repo</id>
|
||||||
|
<url>https://git.knarcraft.net/api/packages/EpicKnarvik97/maven</url>
|
||||||
|
</repository>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>knarcraft-repo</id>
|
||||||
|
<url>https://git.knarcraft.net/api/packages/EpicKnarvik97/maven</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
<!-- Dependencies -->
|
<!-- Dependencies -->
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.citizensnpcs</groupId>
|
<groupId>net.citizensnpcs</groupId>
|
||||||
<artifactId>citizens-main</artifactId>
|
<artifactId>citizens-main</artifactId>
|
||||||
<version>2.0.30-SNAPSHOT</version>
|
<version>2.0.33-SNAPSHOT</version>
|
||||||
<type>jar</type>
|
<type>jar</type>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
@ -50,46 +65,94 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spigotmc</groupId>
|
<groupId>org.spigotmc</groupId>
|
||||||
<artifactId>spigot-api</artifactId>
|
<artifactId>spigot-api</artifactId>
|
||||||
<version>1.19.2-R0.1-SNAPSHOT</version>
|
<version>1.20.6-R0.1-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.milkbowl.vault</groupId>
|
<groupId>com.github.MilkBowl</groupId>
|
||||||
<artifactId>Vault</artifactId>
|
<artifactId>VaultAPI</artifactId>
|
||||||
<version>1.7.3</version>
|
<version>1.7.1</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jetbrains</groupId>
|
<groupId>org.jetbrains</groupId>
|
||||||
<artifactId>annotations</artifactId>
|
<artifactId>annotations</artifactId>
|
||||||
<version>23.0.0</version>
|
<version>24.0.1</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.knarcraft</groupId>
|
||||||
|
<artifactId>knarlib</artifactId>
|
||||||
|
<version>1.2.7</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter</artifactId>
|
||||||
|
<version>5.10.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<!-- Build information -->
|
<!-- Build information -->
|
||||||
<build>
|
<build>
|
||||||
<defaultGoal>clean package install</defaultGoal>
|
|
||||||
<resources>
|
|
||||||
<resource>
|
|
||||||
<filtering>true</filtering>
|
|
||||||
<directory>${basedir}/src/main/resources</directory>
|
|
||||||
<includes>
|
|
||||||
<include>*.yml</include>
|
|
||||||
</includes>
|
|
||||||
</resource>
|
|
||||||
</resources>
|
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.8.1</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>16</source>
|
<source>${java.version}</source>
|
||||||
<target>16</target>
|
<target>${java.version}</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.3.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||||
|
<relocations>
|
||||||
|
<relocation>
|
||||||
|
<pattern>net.knarcraft.knarlib</pattern>
|
||||||
|
<shadedPattern>net.knarcraft.blacksmith.lib.knarlib</shadedPattern>
|
||||||
|
</relocation>
|
||||||
|
<relocation>
|
||||||
|
<pattern>org.jetbrains.annotations</pattern>
|
||||||
|
<shadedPattern>net.knarcraft.blacksmith.lib.annotations</shadedPattern>
|
||||||
|
</relocation>
|
||||||
|
</relocations>
|
||||||
|
<filters>
|
||||||
|
<filter>
|
||||||
|
<artifact>net.knarcraft:knarlib</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>net/knarcraft/knarlib/**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>org.jetbrains:annotations</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>org/jetbrains/annotations/**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -1,23 +1,47 @@
|
|||||||
package net.knarcraft.blacksmith;
|
package net.knarcraft.blacksmith;
|
||||||
|
|
||||||
import net.citizensnpcs.api.CitizensAPI;
|
import net.citizensnpcs.api.CitizensAPI;
|
||||||
import net.knarcraft.blacksmith.command.BlackSmithConfigCommand;
|
import net.citizensnpcs.api.trait.TraitFactory;
|
||||||
import net.knarcraft.blacksmith.command.BlackSmithConfigTabCompleter;
|
import net.citizensnpcs.api.trait.TraitInfo;
|
||||||
import net.knarcraft.blacksmith.command.BlackSmithEditCommand;
|
|
||||||
import net.knarcraft.blacksmith.command.BlackSmithEditTabCompleter;
|
|
||||||
import net.knarcraft.blacksmith.command.PresetCommand;
|
import net.knarcraft.blacksmith.command.PresetCommand;
|
||||||
import net.knarcraft.blacksmith.command.PresetTabCompleter;
|
import net.knarcraft.blacksmith.command.PresetTabCompleter;
|
||||||
import net.knarcraft.blacksmith.config.GlobalSettings;
|
import net.knarcraft.blacksmith.command.blacksmith.BlackSmithConfigCommand;
|
||||||
import net.knarcraft.blacksmith.formatting.Translator;
|
import net.knarcraft.blacksmith.command.blacksmith.BlackSmithConfigTabCompleter;
|
||||||
|
import net.knarcraft.blacksmith.command.blacksmith.BlackSmithEditCommand;
|
||||||
|
import net.knarcraft.blacksmith.command.blacksmith.BlackSmithEditTabCompleter;
|
||||||
|
import net.knarcraft.blacksmith.command.scrapper.ScrapperConfigCommand;
|
||||||
|
import net.knarcraft.blacksmith.command.scrapper.ScrapperConfigTabCompleter;
|
||||||
|
import net.knarcraft.blacksmith.command.scrapper.ScrapperEditCommand;
|
||||||
|
import net.knarcraft.blacksmith.command.scrapper.ScrapperEditTabCompleter;
|
||||||
|
import net.knarcraft.blacksmith.config.StargateYamlConfiguration;
|
||||||
|
import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSettings;
|
||||||
|
import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings;
|
||||||
|
import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
|
||||||
import net.knarcraft.blacksmith.listener.NPCClickListener;
|
import net.knarcraft.blacksmith.listener.NPCClickListener;
|
||||||
import net.knarcraft.blacksmith.listener.PlayerListener;
|
import net.knarcraft.blacksmith.listener.PlayerListener;
|
||||||
import net.knarcraft.blacksmith.manager.EconomyManager;
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
||||||
import net.knarcraft.blacksmith.trait.BlacksmithTrait;
|
import net.knarcraft.blacksmith.trait.BlacksmithTrait;
|
||||||
|
import net.knarcraft.blacksmith.trait.ScrapperTrait;
|
||||||
|
import net.knarcraft.blacksmith.util.ConfigHelper;
|
||||||
|
import net.knarcraft.knarlib.formatting.StringFormatter;
|
||||||
|
import net.knarcraft.knarlib.formatting.TranslatableTimeUnit;
|
||||||
|
import net.knarcraft.knarlib.formatting.Translator;
|
||||||
|
import net.knarcraft.knarlib.util.UpdateChecker;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
import org.bukkit.command.PluginCommand;
|
import org.bukkit.command.PluginCommand;
|
||||||
|
import org.bukkit.command.TabCompleter;
|
||||||
|
import org.bukkit.configuration.InvalidConfigurationException;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.plugin.PluginDescriptionFile;
|
||||||
import org.bukkit.plugin.PluginManager;
|
import org.bukkit.plugin.PluginManager;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,57 +49,119 @@ import java.util.logging.Level;
|
|||||||
*/
|
*/
|
||||||
public class BlacksmithPlugin extends JavaPlugin {
|
public class BlacksmithPlugin extends JavaPlugin {
|
||||||
|
|
||||||
|
private static final String CONFIG_FILE_NAME = "config.yml";
|
||||||
private static BlacksmithPlugin instance;
|
private static BlacksmithPlugin instance;
|
||||||
private GlobalSettings config;
|
private GlobalBlacksmithSettings blacksmithConfig;
|
||||||
|
private GlobalScrapperSettings scrapperConfig;
|
||||||
|
private static Translator translator;
|
||||||
|
private static StringFormatter stringFormatter;
|
||||||
|
private FileConfiguration configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor required for MockBukkit
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public BlacksmithPlugin() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor required for MockBukkit
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
protected BlacksmithPlugin(@NotNull JavaPluginLoader loader, @NotNull PluginDescriptionFile descriptionFile,
|
||||||
|
@NotNull File dataFolder, @NotNull File file) {
|
||||||
|
super(loader, descriptionFile, dataFolder, file);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an instance of the Blacksmith plugin
|
* Gets an instance of the Blacksmith plugin
|
||||||
*
|
*
|
||||||
* @return <p>An instance of the blacksmith plugin</p>
|
* @return <p>An instance of the blacksmith plugin</p>
|
||||||
*/
|
*/
|
||||||
public static BlacksmithPlugin getInstance() {
|
public static @NotNull BlacksmithPlugin getInstance() {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets settings for the blacksmith plugin
|
* Gets settings for the blacksmith plugin's blacksmiths
|
||||||
*
|
*
|
||||||
* @return <p>Settings for the blacksmith plugin</p>
|
* @return <p>Settings for the blacksmith plugin's blacksmith</p>
|
||||||
*/
|
*/
|
||||||
public GlobalSettings getSettings() {
|
public @NotNull GlobalBlacksmithSettings getGlobalBlacksmithSettings() {
|
||||||
return config;
|
return blacksmithConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets settings for the blacksmith plugin's scrapper
|
||||||
|
*
|
||||||
|
* @return <p>Settings for the blacksmith plugin's scrapper</p>
|
||||||
|
*/
|
||||||
|
public @NotNull GlobalScrapperSettings getGlobalScrapperSettings() {
|
||||||
|
return scrapperConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reloads the configuration file from disk
|
* Reloads the configuration file from disk
|
||||||
*/
|
*/
|
||||||
public void reload() {
|
public void reload() {
|
||||||
config.load();
|
|
||||||
this.reloadConfig();
|
this.reloadConfig();
|
||||||
Translator.loadLanguages(this.getConfig().getString("language", "en"));
|
blacksmithConfig.load();
|
||||||
|
scrapperConfig.load();
|
||||||
|
translator.loadLanguages(this.getDataFolder(), "en", this.getConfiguration().getString(
|
||||||
|
"language", "en"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the raw configuration
|
||||||
|
*
|
||||||
|
* @return <p>The raw configuration</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public FileConfiguration getConfiguration() {
|
||||||
|
return this.configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the string formatter to use for formatting
|
||||||
|
*
|
||||||
|
* @return <p>The string formatter to use</p>
|
||||||
|
*/
|
||||||
|
public static @NotNull StringFormatter getStringFormatter() {
|
||||||
|
return BlacksmithPlugin.stringFormatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the translator to use for translation
|
||||||
|
*
|
||||||
|
* @return <p>The translator to use</p>
|
||||||
|
*/
|
||||||
|
public static @NotNull Translator getTranslator() {
|
||||||
|
return BlacksmithPlugin.translator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
getLogger().log(Level.INFO, " v" + getDescription().getVersion() + " disabled.");
|
log(" v" + getDescription().getVersion() + " disabled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
instance = this;
|
instance = this;
|
||||||
|
|
||||||
//Copy default config to disk
|
//Copy default config to disk, and add missing configuration values
|
||||||
FileConfiguration fileConfiguration = this.getConfig();
|
|
||||||
this.saveDefaultConfig();
|
this.saveDefaultConfig();
|
||||||
|
this.getConfig().options().copyDefaults(true);
|
||||||
this.reloadConfig();
|
this.reloadConfig();
|
||||||
fileConfiguration.options().copyDefaults(true);
|
|
||||||
this.saveConfig();
|
this.saveConfig();
|
||||||
|
|
||||||
//Load settings
|
//Migrate from an earlier configuration file syntax if necessary
|
||||||
config = new GlobalSettings(this);
|
if (getConfiguration().getString("scrapper.defaults.dropItem") == null) {
|
||||||
config.load();
|
ConfigHelper.migrateConfig(this.getDataFolder().getPath().replaceAll("\\\\", "/"),
|
||||||
|
getConfiguration());
|
||||||
Translator.loadLanguages(fileConfiguration.getString("language", "en"));
|
this.reloadConfig();
|
||||||
|
}
|
||||||
|
initializeConfigurations(getConfiguration());
|
||||||
|
|
||||||
//Set up Vault integration
|
//Set up Vault integration
|
||||||
if (!setUpVault()) {
|
if (!setUpVault()) {
|
||||||
@ -83,15 +169,118 @@ public class BlacksmithPlugin extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Register the blacksmith trait with Citizens
|
//Register the blacksmith trait with Citizens
|
||||||
CitizensAPI.getTraitFactory().registerTrait(
|
TraitFactory traitFactory = CitizensAPI.getTraitFactory();
|
||||||
net.citizensnpcs.api.trait.TraitInfo.create(BlacksmithTrait.class).withName("blacksmith"));
|
traitFactory.registerTrait(TraitInfo.create(BlacksmithTrait.class).withName("blacksmith"));
|
||||||
|
traitFactory.registerTrait(TraitInfo.create(ScrapperTrait.class).withName("scrapper"));
|
||||||
|
|
||||||
//Register all commands
|
//Register all commands
|
||||||
registerCommands();
|
registerCommands();
|
||||||
//Register all listeners
|
//Register all listeners
|
||||||
registerListeners();
|
registerListeners();
|
||||||
|
|
||||||
getLogger().log(Level.INFO, " v" + getDescription().getVersion() + " enabled.");
|
log(" v" + getDescription().getVersion() + " enabled.");
|
||||||
|
|
||||||
|
//Alert about an update in the console
|
||||||
|
UpdateChecker.checkForUpdate(this, "https://api.spigotmc.org/legacy/update.php?resource=105938",
|
||||||
|
() -> this.getDescription().getVersion(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reloadConfig() {
|
||||||
|
super.reloadConfig();
|
||||||
|
this.configuration = new StargateYamlConfiguration();
|
||||||
|
this.configuration.options().copyDefaults(true);
|
||||||
|
try {
|
||||||
|
this.configuration.load(new File(getDataFolder(), CONFIG_FILE_NAME));
|
||||||
|
} catch (IOException | InvalidConfigurationException exception) {
|
||||||
|
error("Unable to load the configuration! Message: " + exception.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveConfig() {
|
||||||
|
super.saveConfig();
|
||||||
|
try {
|
||||||
|
this.configuration.save(new File(getDataFolder(), CONFIG_FILE_NAME));
|
||||||
|
} catch (IOException exception) {
|
||||||
|
error("Unable to save the configuration! Message: " + exception.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls an event
|
||||||
|
*
|
||||||
|
* @param event <p>The event to call</p>
|
||||||
|
*/
|
||||||
|
public void callEvent(@NotNull Event event) {
|
||||||
|
this.getServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints an info message to the console
|
||||||
|
*
|
||||||
|
* @param message <p>The message to print</p>
|
||||||
|
*/
|
||||||
|
public static void log(@NotNull String message) {
|
||||||
|
BlacksmithPlugin.getInstance().getLogger().log(Level.INFO, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a warning message to the console
|
||||||
|
*
|
||||||
|
* @param message <p>The message to print</p>
|
||||||
|
*/
|
||||||
|
public static void warn(@NotNull String message) {
|
||||||
|
BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints an error message to the console
|
||||||
|
*
|
||||||
|
* @param message <p>The message to print</p>
|
||||||
|
*/
|
||||||
|
public static void error(@NotNull String message) {
|
||||||
|
BlacksmithPlugin.getInstance().getLogger().log(Level.SEVERE, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a debug message to the console
|
||||||
|
*
|
||||||
|
* @param message <p>The message to print</p>
|
||||||
|
*/
|
||||||
|
public static void debug(@NotNull String message) {
|
||||||
|
BlacksmithPlugin.getInstance().getLogger().log(Level.FINE, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes custom configuration and translation
|
||||||
|
*
|
||||||
|
* @param fileConfiguration <p>The configuration file to get values from</p>
|
||||||
|
*/
|
||||||
|
private void initializeConfigurations(@NotNull FileConfiguration fileConfiguration) {
|
||||||
|
//Load settings
|
||||||
|
blacksmithConfig = new GlobalBlacksmithSettings(this);
|
||||||
|
blacksmithConfig.load();
|
||||||
|
scrapperConfig = new GlobalScrapperSettings(this);
|
||||||
|
scrapperConfig.load();
|
||||||
|
|
||||||
|
//Prepare the translator
|
||||||
|
translator = new Translator();
|
||||||
|
translator.registerMessageCategory(TranslatableTimeUnit.UNIT_SECOND);
|
||||||
|
translator.registerMessageCategory(BlacksmithTranslatableMessage.ITEM_TYPE_ENCHANTMENT);
|
||||||
|
translator.loadLanguages(this.getDataFolder(), "en",
|
||||||
|
fileConfiguration.getString("language", "en"));
|
||||||
|
PluginDescriptionFile description = this.getDescription();
|
||||||
|
String prefix;
|
||||||
|
if (description.getPrefix() == null) {
|
||||||
|
prefix = "Blacksmith";
|
||||||
|
} else {
|
||||||
|
prefix = description.getPrefix();
|
||||||
|
}
|
||||||
|
BlacksmithPlugin.stringFormatter = new StringFormatter(prefix, translator);
|
||||||
|
|
||||||
|
// This reload is necessary to get values just added to the configuration for some reason
|
||||||
|
this.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,10 +289,10 @@ public class BlacksmithPlugin extends JavaPlugin {
|
|||||||
* @return <p>True if Vault setup/integration succeeded</p>
|
* @return <p>True if Vault setup/integration succeeded</p>
|
||||||
*/
|
*/
|
||||||
private boolean setUpVault() {
|
private boolean setUpVault() {
|
||||||
getLogger().log(Level.INFO, "Setting Up Vault now....");
|
log("Setting Up Vault now....");
|
||||||
boolean canLoad = EconomyManager.setUp(getServer().getServicesManager(), getLogger());
|
boolean canLoad = EconomyManager.setUp(getServer().getServicesManager());
|
||||||
if (!canLoad) {
|
if (!canLoad) {
|
||||||
getLogger().log(Level.SEVERE, "Vault Integration Failed....");
|
error("Vault Integration Failed....");
|
||||||
getServer().getPluginManager().disablePlugin(this);
|
getServer().getPluginManager().disablePlugin(this);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -123,24 +312,28 @@ public class BlacksmithPlugin extends JavaPlugin {
|
|||||||
* Registers all commands used by this plugin
|
* Registers all commands used by this plugin
|
||||||
*/
|
*/
|
||||||
private void registerCommands() {
|
private void registerCommands() {
|
||||||
//Register the blacksmith NPC edit main-command
|
registerCommand("blacksmith", new BlackSmithEditCommand(), new BlackSmithEditTabCompleter());
|
||||||
PluginCommand blacksmithCommand = this.getCommand("blacksmith");
|
registerCommand("blacksmithConfig", new BlackSmithConfigCommand(), new BlackSmithConfigTabCompleter());
|
||||||
if (blacksmithCommand != null) {
|
registerCommand("scrapper", new ScrapperEditCommand(), new ScrapperEditTabCompleter());
|
||||||
blacksmithCommand.setExecutor(new BlackSmithEditCommand());
|
registerCommand("scrapperConfig", new ScrapperConfigCommand(), new ScrapperConfigTabCompleter());
|
||||||
blacksmithCommand.setTabCompleter(new BlackSmithEditTabCompleter());
|
registerCommand("preset", new PresetCommand(), new PresetTabCompleter());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Register the global config edit command
|
/**
|
||||||
PluginCommand blacksmithConfigCommand = this.getCommand("blacksmithConfig");
|
* Registers a command
|
||||||
if (blacksmithConfigCommand != null) {
|
*
|
||||||
blacksmithConfigCommand.setExecutor(new BlackSmithConfigCommand());
|
* @param commandName <p>The name of the command</p>
|
||||||
blacksmithConfigCommand.setTabCompleter(new BlackSmithConfigTabCompleter());
|
* @param executor <p>The executor to bind to the command</p>
|
||||||
|
* @param tabCompleter <p>The tab completer to bind to the command, or null</p>
|
||||||
|
*/
|
||||||
|
private void registerCommand(@NotNull String commandName, @NotNull CommandExecutor executor,
|
||||||
|
@Nullable TabCompleter tabCompleter) {
|
||||||
|
PluginCommand command = this.getCommand(commandName);
|
||||||
|
if (command != null) {
|
||||||
|
command.setExecutor(executor);
|
||||||
|
if (tabCompleter != null) {
|
||||||
|
command.setTabCompleter(tabCompleter);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginCommand presetCommand = this.getCommand("preset");
|
|
||||||
if (presetCommand != null) {
|
|
||||||
presetCommand.setExecutor(new PresetCommand());
|
|
||||||
presetCommand.setTabCompleter(new PresetTabCompleter());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,265 +0,0 @@
|
|||||||
package net.knarcraft.blacksmith.command;
|
|
||||||
|
|
||||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
|
||||||
import net.knarcraft.blacksmith.config.GlobalSetting;
|
|
||||||
import net.knarcraft.blacksmith.config.GlobalSettings;
|
|
||||||
import net.knarcraft.blacksmith.config.NPCSetting;
|
|
||||||
import net.knarcraft.blacksmith.config.SettingValueType;
|
|
||||||
import net.knarcraft.blacksmith.formatting.ItemType;
|
|
||||||
import net.knarcraft.blacksmith.formatting.TranslatableMessage;
|
|
||||||
import net.knarcraft.blacksmith.util.InputParsingHelper;
|
|
||||||
import net.knarcraft.blacksmith.util.TypeValidationHelper;
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.enchantments.Enchantment;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import static net.knarcraft.blacksmith.formatting.StringFormatter.displayErrorMessage;
|
|
||||||
import static net.knarcraft.blacksmith.formatting.StringFormatter.displaySuccessMessage;
|
|
||||||
import static net.knarcraft.blacksmith.formatting.TranslatableMessage.getValueChangedMessage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The command used for changing global configuration options
|
|
||||||
*/
|
|
||||||
public class BlackSmithConfigCommand implements CommandExecutor {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
|
||||||
@NotNull String[] args) {
|
|
||||||
if (args.length == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String commandName = args[0];
|
|
||||||
if (commandName.equalsIgnoreCase("reload")) {
|
|
||||||
return new ReloadCommand().onCommand(sender, command, label, args);
|
|
||||||
}
|
|
||||||
GlobalSettings settings = BlacksmithPlugin.getInstance().getSettings();
|
|
||||||
|
|
||||||
//Changing reforge-able items' default isn't recommended
|
|
||||||
if (commandName.equalsIgnoreCase(NPCSetting.REFORGE_ABLE_ITEMS.getCommandName())) {
|
|
||||||
displayErrorMessage(sender, TranslatableMessage.DEFAULT_REFORGE_ABLE_ITEMS_UNCHANGEABLE);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Find which global setting the user has specified, if any
|
|
||||||
GlobalSetting detectedGlobalSetting = null;
|
|
||||||
for (GlobalSetting globalSetting : GlobalSetting.values()) {
|
|
||||||
if (commandName.equalsIgnoreCase(globalSetting.getCommandName())) {
|
|
||||||
detectedGlobalSetting = globalSetting;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Find which npc setting the user has specified, if any
|
|
||||||
NPCSetting detectedNPCSetting = null;
|
|
||||||
for (NPCSetting npcSetting : NPCSetting.values()) {
|
|
||||||
if (commandName.equalsIgnoreCase(npcSetting.getCommandName())) {
|
|
||||||
detectedNPCSetting = npcSetting;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Display the current value of a setting
|
|
||||||
if (args.length == 1) {
|
|
||||||
return displayCurrentValue(detectedGlobalSetting, detectedNPCSetting, settings, sender);
|
|
||||||
} else if (args.length == 2 && isSpecialCase(commandName)) {
|
|
||||||
if (displaySpecialCaseValue(args[1], sender, detectedGlobalSetting, settings)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Update the value of a special-case setting
|
|
||||||
if (args.length == 3 && updateSpecialCase(settings, detectedGlobalSetting, args, sender)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Change the value of the specified setting
|
|
||||||
if ((detectedGlobalSetting != null &&
|
|
||||||
TypeValidationHelper.isValid(detectedGlobalSetting.getValueType(), args[1], sender)) ||
|
|
||||||
(detectedNPCSetting != null &&
|
|
||||||
TypeValidationHelper.isValid(detectedNPCSetting.getValueType(), args[1], sender))) {
|
|
||||||
return changeValue(args, detectedGlobalSetting, detectedNPCSetting, settings, sender);
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the value of the setting defined in the user's input
|
|
||||||
*
|
|
||||||
* @param args <p>The arguments given by the user</p>
|
|
||||||
* @param detectedGlobalSetting <p>The global setting recognized from the input, if any</p>
|
|
||||||
* @param detectedNPCSetting <p>The NPC setting recognized from the input, if any</p>
|
|
||||||
* @param settings <p>The global settings object to get settings from</p>
|
|
||||||
* @param sender <p>The command sender to display any output to</p>
|
|
||||||
* @return <p>True if the value was successfully changed</p>
|
|
||||||
*/
|
|
||||||
private boolean changeValue(String[] args, GlobalSetting detectedGlobalSetting, NPCSetting detectedNPCSetting,
|
|
||||||
GlobalSettings settings, CommandSender sender) {
|
|
||||||
String newValue = args[1];
|
|
||||||
if (detectedGlobalSetting != null) {
|
|
||||||
settings.changeValue(detectedGlobalSetting, newValue);
|
|
||||||
displaySuccessMessage(sender, getValueChangedMessage(detectedGlobalSetting.getCommandName(), newValue));
|
|
||||||
return true;
|
|
||||||
} else if (detectedNPCSetting != null) {
|
|
||||||
//This makes sure all arguments are treated as a sentence
|
|
||||||
if (detectedNPCSetting.getValueType() == SettingValueType.STRING) {
|
|
||||||
newValue = String.join(" ", Arrays.asList(args).subList(1, args.length));
|
|
||||||
}
|
|
||||||
settings.changeValue(detectedNPCSetting, newValue);
|
|
||||||
displaySuccessMessage(sender, getValueChangedMessage(detectedNPCSetting.getCommandName(), newValue));
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays the current value of the selected setting
|
|
||||||
*
|
|
||||||
* @param detectedGlobalSetting <p>The global setting recognized from the input, if any</p>
|
|
||||||
* @param detectedNPCSetting <p>The NPC setting recognized from the input, if any</p>
|
|
||||||
* @param settings <p>The global settings object to get settings from</p>
|
|
||||||
* @param sender <p>The command sender to display any output to</p>
|
|
||||||
* @return <p>True if a settings was successfully displayed</p>
|
|
||||||
*/
|
|
||||||
private boolean displayCurrentValue(GlobalSetting detectedGlobalSetting, NPCSetting detectedNPCSetting,
|
|
||||||
GlobalSettings settings, CommandSender sender) {
|
|
||||||
String settingValue;
|
|
||||||
String correctCommandName;
|
|
||||||
boolean printRawValue = false;
|
|
||||||
|
|
||||||
//Find the value of the specified setting
|
|
||||||
//TODO: See if there's a way to remove this duplication
|
|
||||||
if (detectedGlobalSetting != null) {
|
|
||||||
settingValue = String.valueOf(settings.getRawValue(detectedGlobalSetting));
|
|
||||||
correctCommandName = detectedGlobalSetting.getCommandName();
|
|
||||||
} else if (detectedNPCSetting != null) {
|
|
||||||
settingValue = String.valueOf(settings.getRawValue(detectedNPCSetting));
|
|
||||||
correctCommandName = detectedNPCSetting.getCommandName();
|
|
||||||
//For messages, print an additional raw value showing which color codes are used
|
|
||||||
if (detectedNPCSetting.getPath().startsWith("defaults.messages")) {
|
|
||||||
printRawValue = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//Display the current value of the setting
|
|
||||||
displaySuccessMessage(sender, TranslatableMessage.getCurrentValueMessage(correctCommandName, settingValue));
|
|
||||||
//Print the value with any colors displayed as &a-f0-9
|
|
||||||
if (printRawValue) {
|
|
||||||
sender.sendMessage(TranslatableMessage.getRawValueMessage(
|
|
||||||
settingValue.replace(ChatColor.COLOR_CHAR, '&')));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays the current value of a special-case configuration value
|
|
||||||
*
|
|
||||||
* @param selector <p>The selector specifying which material/enchantment to display information about</p>
|
|
||||||
* @param sender <p>The sender to display the value to</p>
|
|
||||||
* @param setting <p>The setting to display</p>
|
|
||||||
* @param settings <p>The settings object to query</p>
|
|
||||||
* @return <p>True if the value was successfully displayed</p>
|
|
||||||
*/
|
|
||||||
private boolean displaySpecialCaseValue(String selector, CommandSender sender, GlobalSetting setting,
|
|
||||||
GlobalSettings settings) {
|
|
||||||
if (setting == GlobalSetting.BASE_PRICE || setting == GlobalSetting.PRICE_PER_DURABILITY_POINT) {
|
|
||||||
Material material = InputParsingHelper.matchMaterial(selector);
|
|
||||||
if (material == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String currentValue;
|
|
||||||
if (setting == GlobalSetting.BASE_PRICE) {
|
|
||||||
currentValue = String.valueOf(settings.getBasePrice(material));
|
|
||||||
} else {
|
|
||||||
currentValue = String.valueOf(settings.getPricePerDurabilityPoint(material));
|
|
||||||
}
|
|
||||||
displaySuccessMessage(sender, TranslatableMessage.getItemCurrentValueMessage(setting.getCommandName(),
|
|
||||||
ItemType.MATERIAL, material.name(), currentValue));
|
|
||||||
return true;
|
|
||||||
} else if (setting == GlobalSetting.ENCHANTMENT_COST) {
|
|
||||||
Enchantment enchantment = InputParsingHelper.matchEnchantment(selector);
|
|
||||||
if (enchantment == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
displaySuccessMessage(sender, TranslatableMessage.getItemCurrentValueMessage(setting.getCommandName(),
|
|
||||||
ItemType.ENCHANTMENT, enchantment.getKey().getKey(),
|
|
||||||
String.valueOf(settings.getEnchantmentCost(enchantment))));
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether a command name matches a special case command
|
|
||||||
*
|
|
||||||
* @param commandName <p>The command specified</p>
|
|
||||||
* @return <p>True if the command is a special case</p>
|
|
||||||
*/
|
|
||||||
private boolean isSpecialCase(String commandName) {
|
|
||||||
return commandName.equalsIgnoreCase(GlobalSetting.BASE_PRICE.getCommandName()) ||
|
|
||||||
commandName.equalsIgnoreCase(GlobalSetting.PRICE_PER_DURABILITY_POINT.getCommandName()) ||
|
|
||||||
commandName.equalsIgnoreCase(GlobalSetting.ENCHANTMENT_COST.getCommandName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates a special-case configuration value if a special-case is encountered
|
|
||||||
*
|
|
||||||
* @param settings <p>The settings to modify</p>
|
|
||||||
* @param detectedGlobalSetting <p>The global setting specified</p>
|
|
||||||
* @param args <p>All arguments given</p>
|
|
||||||
* @param sender <p>The command sender to notify if successful</p>
|
|
||||||
* @return <p>True if already handled as a special case</p>
|
|
||||||
*/
|
|
||||||
private boolean updateSpecialCase(GlobalSettings settings, GlobalSetting detectedGlobalSetting, String[] args,
|
|
||||||
CommandSender sender) {
|
|
||||||
if (InputParsingHelper.isEmpty(args[2])) {
|
|
||||||
args[2] = "-1";
|
|
||||||
} else if (!TypeValidationHelper.isValid(SettingValueType.POSITIVE_DOUBLE, args[2], sender)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
double newPrice = Double.parseDouble(args[2]);
|
|
||||||
String itemChanged;
|
|
||||||
ItemType itemType;
|
|
||||||
String newValue = String.valueOf(newPrice);
|
|
||||||
|
|
||||||
if (detectedGlobalSetting == GlobalSetting.BASE_PRICE ||
|
|
||||||
detectedGlobalSetting == GlobalSetting.PRICE_PER_DURABILITY_POINT) {
|
|
||||||
Material material = InputParsingHelper.matchMaterial(args[1]);
|
|
||||||
if (material == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
itemType = ItemType.MATERIAL;
|
|
||||||
itemChanged = material.name();
|
|
||||||
if (detectedGlobalSetting == GlobalSetting.BASE_PRICE) {
|
|
||||||
settings.setBasePrice(material, newPrice);
|
|
||||||
} else {
|
|
||||||
settings.setPricePerDurabilityPoint(material, newPrice);
|
|
||||||
}
|
|
||||||
} else if (detectedGlobalSetting == GlobalSetting.ENCHANTMENT_COST) {
|
|
||||||
Enchantment enchantment = InputParsingHelper.matchEnchantment(args[1]);
|
|
||||||
if (enchantment == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
itemType = ItemType.ENCHANTMENT;
|
|
||||||
itemChanged = enchantment.getKey().getKey();
|
|
||||||
settings.setEnchantmentCost(enchantment, newPrice);
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
displaySuccessMessage(sender, TranslatableMessage.getItemValueChangedMessage(detectedGlobalSetting.getCommandName(),
|
|
||||||
itemType, itemChanged, newValue));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,119 +0,0 @@
|
|||||||
package net.knarcraft.blacksmith.command;
|
|
||||||
|
|
||||||
import net.citizensnpcs.api.CitizensAPI;
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
|
||||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
|
||||||
import net.knarcraft.blacksmith.config.NPCSetting;
|
|
||||||
import net.knarcraft.blacksmith.config.SettingValueType;
|
|
||||||
import net.knarcraft.blacksmith.formatting.StringFormatter;
|
|
||||||
import net.knarcraft.blacksmith.formatting.TranslatableMessage;
|
|
||||||
import net.knarcraft.blacksmith.formatting.Translator;
|
|
||||||
import net.knarcraft.blacksmith.trait.BlacksmithTrait;
|
|
||||||
import net.knarcraft.blacksmith.util.InputParsingHelper;
|
|
||||||
import net.knarcraft.blacksmith.util.TypeValidationHelper;
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import static net.knarcraft.blacksmith.formatting.StringFormatter.displaySuccessMessage;
|
|
||||||
import static net.knarcraft.blacksmith.formatting.TranslatableMessage.getCurrentValueMessage;
|
|
||||||
import static net.knarcraft.blacksmith.formatting.TranslatableMessage.getValueChangedMessage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The main command used for blacksmith editing
|
|
||||||
*/
|
|
||||||
public class BlackSmithEditCommand implements CommandExecutor {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
|
||||||
@NotNull String[] args) {
|
|
||||||
NPC npc = CitizensAPI.getDefaultNPCSelector().getSelected(sender);
|
|
||||||
if (npc == null || !npc.hasTrait(BlacksmithTrait.class)) {
|
|
||||||
StringFormatter.displayErrorMessage(sender, TranslatableMessage.NO_NPC_SELECTED);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.length < 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BlacksmithTrait blacksmithTrait = npc.getTraitNullable(BlacksmithTrait.class);
|
|
||||||
|
|
||||||
for (NPCSetting npcSetting : NPCSetting.values()) {
|
|
||||||
String commandName = npcSetting.getCommandName();
|
|
||||||
if (commandName.equalsIgnoreCase(args[0])) {
|
|
||||||
String newValue = args.length < 2 ? null : args[1];
|
|
||||||
//This makes sure all arguments are treated as a sentence
|
|
||||||
if (npcSetting.getValueType() == SettingValueType.STRING && args.length > 2) {
|
|
||||||
newValue = String.join(" ", Arrays.asList(args).subList(1, args.length));
|
|
||||||
}
|
|
||||||
return displayOrChangeNPCSetting(blacksmithTrait, npcSetting, newValue, sender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the given NPC setting, or displays the current value if a new value isn't specified
|
|
||||||
*
|
|
||||||
* @param blacksmithTrait <p>The blacksmith trait belonging to the selected NPC</p>
|
|
||||||
* @param npcSetting <p>The NPC setting to change</p>
|
|
||||||
* @param newValue <p>The value to change the setting to</p>
|
|
||||||
* @param sender <p>The command sender to notify about results</p>
|
|
||||||
* @return <p>True if everything went successfully</p>
|
|
||||||
*/
|
|
||||||
private boolean displayOrChangeNPCSetting(BlacksmithTrait blacksmithTrait, NPCSetting npcSetting, String newValue,
|
|
||||||
CommandSender sender) {
|
|
||||||
if (newValue == null) {
|
|
||||||
//Display the current value of the setting
|
|
||||||
displayNPCSetting(blacksmithTrait, npcSetting, sender);
|
|
||||||
} else {
|
|
||||||
//If an empty value or null, clear the value instead of changing it
|
|
||||||
if (InputParsingHelper.isEmpty(newValue)) {
|
|
||||||
newValue = null;
|
|
||||||
} else {
|
|
||||||
//Abort if an invalid value is given
|
|
||||||
boolean isValidType = TypeValidationHelper.isValid(npcSetting.getValueType(), newValue, sender);
|
|
||||||
if (!isValidType) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
newValue = ChatColor.translateAlternateColorCodes('&', newValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Change the setting
|
|
||||||
blacksmithTrait.getSettings().changeSetting(npcSetting, newValue);
|
|
||||||
displaySuccessMessage(sender, getValueChangedMessage(npcSetting.getCommandName(), String.valueOf(newValue)));
|
|
||||||
//Save the changes immediately to prevent data loss on server crash
|
|
||||||
CitizensAPI.getNPCRegistry().saveToStore();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays the current value of the given NPC setting
|
|
||||||
*
|
|
||||||
* @param blacksmithTrait <p>The blacksmith trait of the NPC to get the value from</p>
|
|
||||||
* @param npcSetting <p>The NPC setting to see the value of</p>
|
|
||||||
* @param sender <p>The command sender to display the value to</p>
|
|
||||||
*/
|
|
||||||
private void displayNPCSetting(BlacksmithTrait blacksmithTrait, NPCSetting npcSetting, CommandSender sender) {
|
|
||||||
String rawValue = String.valueOf(blacksmithTrait.getSettings().getRawValue(npcSetting));
|
|
||||||
if (InputParsingHelper.isEmpty(rawValue)) {
|
|
||||||
//Display the default value, if no custom value has been specified
|
|
||||||
rawValue = String.valueOf(BlacksmithPlugin.getInstance().getSettings().getRawValue(npcSetting));
|
|
||||||
displaySuccessMessage(sender, getCurrentValueMessage(npcSetting.getCommandName(), rawValue));
|
|
||||||
} else {
|
|
||||||
//Add a marker if the value has been customized
|
|
||||||
String marker = Translator.getTranslatedMessage(TranslatableMessage.SETTING_OVERRIDDEN_MARKER);
|
|
||||||
displaySuccessMessage(sender, getCurrentValueMessage(npcSetting.getCommandName(), rawValue) + marker);
|
|
||||||
}
|
|
||||||
if (npcSetting.getPath().startsWith("defaults.messages")) {
|
|
||||||
sender.sendMessage(TranslatableMessage.getRawValueMessage(rawValue.replace(ChatColor.COLOR_CHAR, '&')));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
191
src/main/java/net/knarcraft/blacksmith/command/EditCommand.java
Normal file
191
src/main/java/net/knarcraft/blacksmith/command/EditCommand.java
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
package net.knarcraft.blacksmith.command;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.CitizensAPI;
|
||||||
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.config.Setting;
|
||||||
|
import net.knarcraft.blacksmith.config.SettingValueType;
|
||||||
|
import net.knarcraft.blacksmith.config.Settings;
|
||||||
|
import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
|
||||||
|
import net.knarcraft.blacksmith.trait.CustomTrait;
|
||||||
|
import net.knarcraft.blacksmith.util.ConfigCommandHelper;
|
||||||
|
import net.knarcraft.blacksmith.util.InputParsingHelper;
|
||||||
|
import net.knarcraft.blacksmith.util.TypeValidationHelper;
|
||||||
|
import net.knarcraft.knarlib.formatting.StringFormatter;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage.getCurrentValueMessage;
|
||||||
|
import static net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage.getDefaultValueMessage;
|
||||||
|
import static net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage.getValueChangedMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic implementation of the edit command
|
||||||
|
*
|
||||||
|
* @param <K> <p>The type of trait to edit</p>
|
||||||
|
* @param <L> <p>The type of setting the trait uses</p>
|
||||||
|
*/
|
||||||
|
public abstract class EditCommand<K extends CustomTrait<L>, L extends Setting> implements CommandExecutor {
|
||||||
|
|
||||||
|
protected final Class<K> traitClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new edit command
|
||||||
|
*
|
||||||
|
* @param traitClass <p>The type of trait this command edits</p>
|
||||||
|
*/
|
||||||
|
public EditCommand(Class<K> traitClass) {
|
||||||
|
this.traitClass = traitClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the setting corresponding to the given input
|
||||||
|
*
|
||||||
|
* @param input <p>The input given by the user</p>
|
||||||
|
* @return <p>The corresponding setting, or null if not recognized</p>
|
||||||
|
*/
|
||||||
|
public abstract L getSetting(String input);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the global settings to use
|
||||||
|
*
|
||||||
|
* @return <p>The global settings</p>
|
||||||
|
*/
|
||||||
|
public abstract @NotNull Settings<L> getGlobalSettings();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String s,
|
||||||
|
@NotNull String[] args) {
|
||||||
|
NPC npc = CitizensAPI.getDefaultNPCSelector().getSelected(sender);
|
||||||
|
if (npc == null || !npc.hasTrait(traitClass)) {
|
||||||
|
BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender,
|
||||||
|
BlacksmithTranslatableMessage.NO_NPC_SELECTED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
K trait = npc.getTraitNullable(traitClass);
|
||||||
|
if (trait == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
L setting = getSetting(args[0]);
|
||||||
|
if (setting != null) {
|
||||||
|
String newValue = args.length < 2 ? null : args[1];
|
||||||
|
//This makes sure all arguments are treated as a sentence
|
||||||
|
if (setting.getValueType() == SettingValueType.STRING && args.length > 2) {
|
||||||
|
newValue = String.join(" ", Arrays.asList(args).subList(1, args.length));
|
||||||
|
}
|
||||||
|
Settings<L> settings = getGlobalSettings();
|
||||||
|
return displayOrChangeNPCSetting(trait, setting, settings, newValue, sender);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the given NPC setting, or displays the current value if a new value isn't specified
|
||||||
|
*
|
||||||
|
* @param trait <p>The trait belonging to the selected NPC</p>
|
||||||
|
* @param setting <p>The NPC setting to change</p>
|
||||||
|
* @param globalSettings <p>The global settings to get default values from</p>
|
||||||
|
* @param newValue <p>The value to change the setting to</p>
|
||||||
|
* @param sender <p>The command sender to notify about results</p>
|
||||||
|
* @return <p>True if everything went successfully</p>
|
||||||
|
*/
|
||||||
|
private boolean displayOrChangeNPCSetting(@NotNull CustomTrait<L> trait,
|
||||||
|
@NotNull L setting,
|
||||||
|
@NotNull Settings<L> globalSettings,
|
||||||
|
@Nullable String newValue,
|
||||||
|
@NotNull CommandSender sender) {
|
||||||
|
if (newValue == null) {
|
||||||
|
//Display the current value of the setting
|
||||||
|
displayNPCSetting(trait, setting, globalSettings, sender);
|
||||||
|
} else {
|
||||||
|
//If an empty value or null, clear the value instead of changing it
|
||||||
|
if (InputParsingHelper.isEmpty(newValue)) {
|
||||||
|
newValue = null;
|
||||||
|
} else {
|
||||||
|
//Abort if an invalid value is given
|
||||||
|
boolean isValidType = TypeValidationHelper.isValid(setting.getValueType(), newValue, sender);
|
||||||
|
if (!isValidType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
newValue = ChatColor.translateAlternateColorCodes('&', newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Change the setting
|
||||||
|
Settings<L> settings = trait.getTraitSettings();
|
||||||
|
if (settings == null) {
|
||||||
|
BlacksmithPlugin.error("Settings for a CustomTrait has not been initialized! Please inform the developer!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
settings.changeValue(setting, newValue);
|
||||||
|
BlacksmithPlugin.getStringFormatter().displaySuccessMessage(sender,
|
||||||
|
getValueChangedMessage(setting.getCommandName(), String.valueOf(newValue)));
|
||||||
|
//Save the changes immediately to prevent data loss on server crash
|
||||||
|
CitizensAPI.getNPCRegistry().saveToStore();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the current value of the given NPC setting
|
||||||
|
*
|
||||||
|
* @param trait <p>The trait of the NPC to get the value from</p>
|
||||||
|
* @param setting <p>The NPC setting to see the value of</p>
|
||||||
|
* @param globalSettings <p>The global settings to get default values from</p>
|
||||||
|
* @param sender <p>The command sender to display the value to</p>
|
||||||
|
*/
|
||||||
|
private void displayNPCSetting(@NotNull CustomTrait<L> trait,
|
||||||
|
@NotNull L setting,
|
||||||
|
@NotNull Settings<L> globalSettings,
|
||||||
|
@NotNull CommandSender sender) {
|
||||||
|
Settings<L> settings = trait.getTraitSettings();
|
||||||
|
if (settings == null) {
|
||||||
|
BlacksmithPlugin.error("Settings for a CustomTrait has not been initialized! Please inform the developer!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringFormatter formatter = BlacksmithPlugin.getStringFormatter();
|
||||||
|
|
||||||
|
//Find the value of the specified setting
|
||||||
|
String commandName = setting.getCommandName();
|
||||||
|
String currentValue = String.valueOf(settings.getRawValue(setting));
|
||||||
|
String defaultValue = String.valueOf(setting.getDefaultValue());
|
||||||
|
String marker = formatter.getUnFormattedMessage(BlacksmithTranslatableMessage.SETTING_OVERRIDDEN_MARKER);
|
||||||
|
boolean isMessage = setting.isMessage();
|
||||||
|
boolean isSet = !InputParsingHelper.isEmpty(currentValue);
|
||||||
|
|
||||||
|
// Display the description for how this setting is used
|
||||||
|
formatter.displaySuccessMessage(sender, setting.getDescription());
|
||||||
|
|
||||||
|
// Display the default value
|
||||||
|
formatter.displayNeutralMessage(sender, getDefaultValueMessage(commandName, defaultValue));
|
||||||
|
if (isMessage) {
|
||||||
|
ConfigCommandHelper.displayRaw(sender, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSet) {
|
||||||
|
//Display the global value, if no custom value has been specified
|
||||||
|
currentValue = String.valueOf(globalSettings.getRawValue(setting));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the value with a marker if it's customized
|
||||||
|
formatter.displayNeutralMessage(sender, getCurrentValueMessage(commandName, currentValue) + (isSet ? marker : ""));
|
||||||
|
|
||||||
|
if (isMessage) {
|
||||||
|
ConfigCommandHelper.displayRaw(sender, currentValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,10 +1,9 @@
|
|||||||
package net.knarcraft.blacksmith.command;
|
package net.knarcraft.blacksmith.command;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
import net.knarcraft.blacksmith.config.SmithPreset;
|
import net.knarcraft.blacksmith.config.SmithPreset;
|
||||||
import net.knarcraft.blacksmith.config.SmithPresetFilter;
|
import net.knarcraft.blacksmith.config.SmithPresetFilter;
|
||||||
import net.knarcraft.blacksmith.formatting.StringFormatter;
|
import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
|
||||||
import net.knarcraft.blacksmith.formatting.TranslatableMessage;
|
|
||||||
import net.knarcraft.blacksmith.formatting.Translator;
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandExecutor;
|
import org.bukkit.command.CommandExecutor;
|
||||||
@ -13,9 +12,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import static net.knarcraft.blacksmith.formatting.StringFormatter.displayErrorMessage;
|
|
||||||
import static net.knarcraft.blacksmith.formatting.StringFormatter.displaySuccessMessage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The command for displaying which materials are contained in a preset
|
* The command for displaying which materials are contained in a preset
|
||||||
@ -30,7 +27,7 @@ public class PresetCommand implements CommandExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String presetName = args[0].toUpperCase().replace('-', '_');
|
String presetName = args[0].toUpperCase().replace('-', '_');
|
||||||
List<Material> includedMaterials;
|
Set<Material> includedMaterials;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//Display the preset with the filter applied
|
//Display the preset with the filter applied
|
||||||
@ -40,7 +37,8 @@ public class PresetCommand implements CommandExecutor {
|
|||||||
SmithPresetFilter filter = SmithPresetFilter.valueOf(parts[1]);
|
SmithPresetFilter filter = SmithPresetFilter.valueOf(parts[1]);
|
||||||
|
|
||||||
if (!smithPreset.supportsFilter(filter)) {
|
if (!smithPreset.supportsFilter(filter)) {
|
||||||
displayErrorMessage(sender, TranslatableMessage.INVALID_FILTER_FOR_PRESET);
|
BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender,
|
||||||
|
BlacksmithTranslatableMessage.INVALID_FILTER_FOR_PRESET);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
includedMaterials = smithPreset.getFilteredMaterials(filter);
|
includedMaterials = smithPreset.getFilteredMaterials(filter);
|
||||||
@ -48,7 +46,8 @@ public class PresetCommand implements CommandExecutor {
|
|||||||
includedMaterials = SmithPreset.valueOf(presetName).getMaterials();
|
includedMaterials = SmithPreset.valueOf(presetName).getMaterials();
|
||||||
}
|
}
|
||||||
} catch (IllegalArgumentException exception) {
|
} catch (IllegalArgumentException exception) {
|
||||||
displayErrorMessage(sender, TranslatableMessage.INVALID_PRESET_OR_FILTER);
|
BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender,
|
||||||
|
BlacksmithTranslatableMessage.INVALID_PRESET_OR_FILTER);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,8 +56,9 @@ public class PresetCommand implements CommandExecutor {
|
|||||||
for (Material material : includedMaterials) {
|
for (Material material : includedMaterials) {
|
||||||
materialNames.add(material.name());
|
materialNames.add(material.name());
|
||||||
}
|
}
|
||||||
displaySuccessMessage(sender, StringFormatter.replacePlaceholder(Translator.getTranslatedMessage(
|
BlacksmithPlugin.getStringFormatter().displaySuccessMessage(sender,
|
||||||
TranslatableMessage.PRESET_MATERIALS), "{materials}", String.join(", ", materialNames)));
|
BlacksmithPlugin.getStringFormatter().replacePlaceholder(BlacksmithTranslatableMessage.PRESET_MATERIALS,
|
||||||
|
"{materials}", String.join(", ", materialNames)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ package net.knarcraft.blacksmith.command;
|
|||||||
|
|
||||||
import net.knarcraft.blacksmith.config.SmithPreset;
|
import net.knarcraft.blacksmith.config.SmithPreset;
|
||||||
import net.knarcraft.blacksmith.config.SmithPresetFilter;
|
import net.knarcraft.blacksmith.config.SmithPresetFilter;
|
||||||
import net.knarcraft.blacksmith.util.TabCompletionHelper;
|
import net.knarcraft.knarlib.util.TabCompletionHelper;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.command.TabCompleter;
|
import org.bukkit.command.TabCompleter;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.knarcraft.blacksmith.command;
|
package net.knarcraft.blacksmith.command;
|
||||||
|
|
||||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
import net.knarcraft.blacksmith.formatting.TranslatableMessage;
|
import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.command.TabExecutor;
|
import org.bukkit.command.TabExecutor;
|
||||||
@ -11,8 +11,6 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static net.knarcraft.blacksmith.formatting.StringFormatter.displaySuccessMessage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The command for re-loading the plugin
|
* The command for re-loading the plugin
|
||||||
*/
|
*/
|
||||||
@ -22,14 +20,13 @@ public class ReloadCommand implements TabExecutor {
|
|||||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
||||||
@NotNull String[] args) {
|
@NotNull String[] args) {
|
||||||
BlacksmithPlugin.getInstance().reload();
|
BlacksmithPlugin.getInstance().reload();
|
||||||
displaySuccessMessage(sender, TranslatableMessage.PLUGIN_RELOADED);
|
BlacksmithPlugin.getStringFormatter().displaySuccessMessage(sender, BlacksmithTranslatableMessage.PLUGIN_RELOADED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
|
||||||
@NotNull String[] args) {
|
@NotNull String label, @NotNull String[] args) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,228 @@
|
|||||||
|
package net.knarcraft.blacksmith.command.blacksmith;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.command.ReloadCommand;
|
||||||
|
import net.knarcraft.blacksmith.config.SettingValueType;
|
||||||
|
import net.knarcraft.blacksmith.config.blacksmith.BlacksmithSetting;
|
||||||
|
import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSettings;
|
||||||
|
import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
|
||||||
|
import net.knarcraft.blacksmith.formatting.ItemType;
|
||||||
|
import net.knarcraft.blacksmith.util.ConfigCommandHelper;
|
||||||
|
import net.knarcraft.blacksmith.util.InputParsingHelper;
|
||||||
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
|
import net.knarcraft.blacksmith.util.TypeValidationHelper;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The command used for changing global blacksmith configuration options
|
||||||
|
*/
|
||||||
|
public class BlackSmithConfigCommand implements CommandExecutor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
||||||
|
@NotNull String[] args) {
|
||||||
|
if (args.length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String commandName = args[0];
|
||||||
|
if (commandName.equalsIgnoreCase("reload")) {
|
||||||
|
return new ReloadCommand().onCommand(sender, command, label, args);
|
||||||
|
}
|
||||||
|
GlobalBlacksmithSettings settings = BlacksmithPlugin.getInstance().getGlobalBlacksmithSettings();
|
||||||
|
|
||||||
|
//Find which setting the user has specified, if any
|
||||||
|
BlacksmithSetting detectedSetting = BlacksmithSetting.getSetting(commandName);
|
||||||
|
if (detectedSetting == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Display the current value of a setting
|
||||||
|
if (args.length == 1) {
|
||||||
|
ConfigCommandHelper.displayCurrentValue(detectedSetting, settings, sender);
|
||||||
|
return true;
|
||||||
|
} else if (args.length == 2 && isSpecialCase(commandName)) {
|
||||||
|
if (displaySpecialCaseValue(args[1], sender, detectedSetting, settings)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update the value of a special-case setting
|
||||||
|
if (args.length == 3 && updateSpecialCase(settings, detectedSetting, args, sender)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Change the value of the specified setting
|
||||||
|
if (TypeValidationHelper.isValid(detectedSetting.getValueType(), args[1], sender)) {
|
||||||
|
ConfigCommandHelper.changeValue(args, detectedSetting, settings, sender);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the current value of a special-case configuration value
|
||||||
|
*
|
||||||
|
* @param selector <p>The selector specifying which material/enchantment to display information about</p>
|
||||||
|
* @param sender <p>The sender to display the value to</p>
|
||||||
|
* @param setting <p>The setting to display</p>
|
||||||
|
* @param settings <p>The settings object to query</p>
|
||||||
|
* @return <p>True if the value was successfully displayed</p>
|
||||||
|
*/
|
||||||
|
private boolean displaySpecialCaseValue(@NotNull String selector, @NotNull CommandSender sender,
|
||||||
|
@Nullable BlacksmithSetting setting,
|
||||||
|
@NotNull GlobalBlacksmithSettings settings) {
|
||||||
|
if (setting == BlacksmithSetting.BASE_PRICE || setting == BlacksmithSetting.PRICE_PER_DURABILITY_POINT) {
|
||||||
|
Material material = InputParsingHelper.matchMaterial(selector);
|
||||||
|
if (material == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String currentValue;
|
||||||
|
if (setting == BlacksmithSetting.BASE_PRICE) {
|
||||||
|
currentValue = String.valueOf(settings.getBasePrice(material));
|
||||||
|
} else {
|
||||||
|
currentValue = String.valueOf(settings.getPricePerDurabilityPoint(material));
|
||||||
|
}
|
||||||
|
BlacksmithPlugin.getStringFormatter().displaySuccessMessage(sender,
|
||||||
|
BlacksmithTranslatableMessage.getItemCurrentValueMessage(setting.getCommandName(),
|
||||||
|
ItemType.MATERIAL, material.name(), currentValue));
|
||||||
|
return true;
|
||||||
|
} else if (setting == BlacksmithSetting.ENCHANTMENT_COST) {
|
||||||
|
Enchantment enchantment = InputParsingHelper.matchEnchantment(selector);
|
||||||
|
if (enchantment == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
BlacksmithPlugin.getStringFormatter().displaySuccessMessage(sender,
|
||||||
|
BlacksmithTranslatableMessage.getItemCurrentValueMessage(setting.getCommandName(),
|
||||||
|
ItemType.ENCHANTMENT, enchantment.getKey().getKey(),
|
||||||
|
String.valueOf(settings.getEnchantmentCost(enchantment))));
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether a command name matches a special case command
|
||||||
|
*
|
||||||
|
* @param commandName <p>The command specified</p>
|
||||||
|
* @return <p>True if the command is a special case</p>
|
||||||
|
*/
|
||||||
|
private boolean isSpecialCase(@NotNull String commandName) {
|
||||||
|
return commandName.equalsIgnoreCase(BlacksmithSetting.BASE_PRICE.getCommandName()) ||
|
||||||
|
commandName.equalsIgnoreCase(BlacksmithSetting.PRICE_PER_DURABILITY_POINT.getCommandName()) ||
|
||||||
|
commandName.equalsIgnoreCase(BlacksmithSetting.ENCHANTMENT_COST.getCommandName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a special-case configuration value if a special-case is encountered
|
||||||
|
*
|
||||||
|
* @param settings <p>The settings to modify</p>
|
||||||
|
* @param blacksmithSetting <p>The setting specified</p>
|
||||||
|
* @param args <p>All arguments given</p>
|
||||||
|
* @param sender <p>The command sender to notify if successful</p>
|
||||||
|
* @return <p>True if already handled as a special case</p>
|
||||||
|
*/
|
||||||
|
private boolean updateSpecialCase(@NotNull GlobalBlacksmithSettings settings,
|
||||||
|
@Nullable BlacksmithSetting blacksmithSetting,
|
||||||
|
@NotNull String[] args,
|
||||||
|
CommandSender sender) {
|
||||||
|
if (InputParsingHelper.isEmpty(args[2])) {
|
||||||
|
args[2] = "-1";
|
||||||
|
} else if (!TypeValidationHelper.isValid(SettingValueType.POSITIVE_DOUBLE, args[2], sender)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
double newPrice = Double.parseDouble(args[2]);
|
||||||
|
String newValue = String.valueOf(newPrice);
|
||||||
|
|
||||||
|
if (blacksmithSetting == BlacksmithSetting.BASE_PRICE ||
|
||||||
|
blacksmithSetting == BlacksmithSetting.PRICE_PER_DURABILITY_POINT) {
|
||||||
|
return updatePriceSpecialCase(settings, blacksmithSetting, args[1], newPrice, sender);
|
||||||
|
} else if (blacksmithSetting == BlacksmithSetting.ENCHANTMENT_COST) {
|
||||||
|
//Update enchantment cost for an item
|
||||||
|
Enchantment enchantment = InputParsingHelper.matchEnchantment(args[1]);
|
||||||
|
if (enchantment == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ItemType itemType = ItemType.ENCHANTMENT;
|
||||||
|
String itemChanged = enchantment.getKey().getKey();
|
||||||
|
settings.setEnchantmentCost(enchantment, newPrice);
|
||||||
|
BlacksmithPlugin.getStringFormatter().displaySuccessMessage(sender,
|
||||||
|
BlacksmithTranslatableMessage.getItemValueChangedMessage(blacksmithSetting.getCommandName(),
|
||||||
|
itemType, itemChanged, newValue));
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a special case price configuration value if a special case is encountered
|
||||||
|
*
|
||||||
|
* @param settings <p>The settings to modify</p>
|
||||||
|
* @param blacksmithSetting <p>The setting specified</p>
|
||||||
|
* @param materialName <p>The material name to update the price for</p>
|
||||||
|
* @param newPrice <p>The new price to update to</p>
|
||||||
|
* @param sender <p>The command sender to respond to</p>
|
||||||
|
* @return <p>True if the input was valid, and the item(s) was/were updated</p>
|
||||||
|
*/
|
||||||
|
private boolean updatePriceSpecialCase(@NotNull GlobalBlacksmithSettings settings,
|
||||||
|
@NotNull BlacksmithSetting blacksmithSetting,
|
||||||
|
@NotNull String materialName, double newPrice,
|
||||||
|
@NotNull CommandSender sender) {
|
||||||
|
ItemType itemType = ItemType.MATERIAL;
|
||||||
|
String itemChanged;
|
||||||
|
//Update base price or price per durability point for an item
|
||||||
|
if (materialName.contains("*")) {
|
||||||
|
itemChanged = materialName;
|
||||||
|
updateAllMatchedPrices(settings, blacksmithSetting, materialName, newPrice);
|
||||||
|
} else {
|
||||||
|
Material material = InputParsingHelper.matchMaterial(materialName);
|
||||||
|
if (material == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
itemChanged = material.name();
|
||||||
|
if (blacksmithSetting == BlacksmithSetting.BASE_PRICE) {
|
||||||
|
settings.setBasePrice(material, newPrice);
|
||||||
|
} else {
|
||||||
|
settings.setPricePerDurabilityPoint(material, newPrice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BlacksmithPlugin.getStringFormatter().displaySuccessMessage(sender,
|
||||||
|
BlacksmithTranslatableMessage.getItemValueChangedMessage(blacksmithSetting.getCommandName(),
|
||||||
|
itemType, itemChanged, String.valueOf(newPrice)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates all materials matching the material name wildcard
|
||||||
|
*
|
||||||
|
* @param settings <p>The settings to modify</p>
|
||||||
|
* @param blacksmithSetting <p>The setting specified</p>
|
||||||
|
* @param materialName <p>The wildcard material name to update cost for</p>
|
||||||
|
* @param newPrice <p>The new cost for the matched items</p>
|
||||||
|
*/
|
||||||
|
private void updateAllMatchedPrices(@NotNull GlobalBlacksmithSettings settings,
|
||||||
|
@NotNull BlacksmithSetting blacksmithSetting,
|
||||||
|
@NotNull String materialName, double newPrice) {
|
||||||
|
Set<Material> materials = ItemHelper.getWildcardMatch(materialName, false);
|
||||||
|
for (Material material : materials) {
|
||||||
|
if (blacksmithSetting == BlacksmithSetting.BASE_PRICE) {
|
||||||
|
settings.setBasePrice(material, newPrice);
|
||||||
|
} else {
|
||||||
|
settings.setPricePerDurabilityPoint(material, newPrice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
package net.knarcraft.blacksmith.command;
|
package net.knarcraft.blacksmith.command.blacksmith;
|
||||||
|
|
||||||
import net.knarcraft.blacksmith.config.GlobalSetting;
|
|
||||||
import net.knarcraft.blacksmith.config.NPCSetting;
|
|
||||||
import net.knarcraft.blacksmith.config.SettingValueType;
|
import net.knarcraft.blacksmith.config.SettingValueType;
|
||||||
|
import net.knarcraft.blacksmith.config.blacksmith.BlacksmithSetting;
|
||||||
import net.knarcraft.blacksmith.util.InputParsingHelper;
|
import net.knarcraft.blacksmith.util.InputParsingHelper;
|
||||||
|
import net.knarcraft.knarlib.util.TabCompletionHelper;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.command.TabCompleter;
|
import org.bukkit.command.TabCompleter;
|
||||||
@ -14,10 +14,10 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static net.knarcraft.blacksmith.util.TabCompleteValuesHelper.getTabCompletions;
|
import static net.knarcraft.blacksmith.util.TabCompleteValuesHelper.getTabCompletions;
|
||||||
import static net.knarcraft.blacksmith.util.TabCompletionHelper.filterMatchingContains;
|
import static net.knarcraft.knarlib.util.TabCompletionHelper.filterMatchingContains;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The tab completer for the command used for changing global configuration options
|
* The tab completer for the command used for changing global blacksmith configuration options
|
||||||
*/
|
*/
|
||||||
public class BlackSmithConfigTabCompleter implements TabCompleter {
|
public class BlackSmithConfigTabCompleter implements TabCompleter {
|
||||||
|
|
||||||
@ -32,71 +32,61 @@ public class BlackSmithConfigTabCompleter implements TabCompleter {
|
|||||||
//Arguments: <setting> [new value/material or enchantment] []
|
//Arguments: <setting> [new value/material or enchantment] []
|
||||||
|
|
||||||
//Prevent tab-completion when typing messages with spaces
|
//Prevent tab-completion when typing messages with spaces
|
||||||
if (skipCompletionForSpacedMessage(args) != null) {
|
if (args.length > 2 && skipCompletionForSpacedMessage(args[0]) != null) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length == 1) {
|
if (args.length == 1) {
|
||||||
List<String> availableCommands = new ArrayList<>();
|
List<String> availableCommands = new ArrayList<>();
|
||||||
availableCommands.add("reload");
|
availableCommands.add("reload");
|
||||||
for (NPCSetting setting : NPCSetting.values()) {
|
for (BlacksmithSetting setting : BlacksmithSetting.values()) {
|
||||||
availableCommands.add(setting.getCommandName());
|
availableCommands.add(setting.getCommandName());
|
||||||
}
|
}
|
||||||
for (GlobalSetting globalSetting : GlobalSetting.values()) {
|
|
||||||
availableCommands.add(globalSetting.getCommandName());
|
|
||||||
}
|
|
||||||
return filterMatchingContains(availableCommands, args[0]);
|
return filterMatchingContains(availableCommands, args[0]);
|
||||||
} else if (args.length == 2) {
|
} else if (args.length == 2) {
|
||||||
return tabCompleteCommandValues(args[0], args[1]);
|
return tabCompleteCommandValues(args[0], args[1]);
|
||||||
} else if (args.length == 3) {
|
} else if (args.length == 3) {
|
||||||
//Get per-material tab completions, or return nothing if an invalid setting was specified
|
//Get per-material tab completions, or return nothing if an invalid setting was specified
|
||||||
for (GlobalSetting globalSetting : GlobalSetting.values()) {
|
BlacksmithSetting blacksmithSetting = BlacksmithSetting.getSetting(args[0]);
|
||||||
if (globalSetting.getCommandName().equalsIgnoreCase(args[0])) {
|
if (blacksmithSetting != null) {
|
||||||
return getPerTypeTabCompletions(globalSetting, args);
|
return getPerTypeTabCompletions(blacksmithSetting, args);
|
||||||
|
} else {
|
||||||
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether to tab-complete nothing because a message containing spaces is being written
|
* Checks whether to tab-complete nothing because a message containing spaces is being written
|
||||||
*
|
*
|
||||||
* @param args <p>The arguments given by the user</p>
|
* @param command <p>The command specified by the user</p>
|
||||||
* @return <p>Null if not writing a spaced message</p>
|
* @return <p>Null if not writing a spaced message</p>
|
||||||
*/
|
*/
|
||||||
private List<String> skipCompletionForSpacedMessage(String[] args) {
|
private List<String> skipCompletionForSpacedMessage(@NotNull String command) {
|
||||||
if (args.length > 2) {
|
BlacksmithSetting blacksmithSetting = BlacksmithSetting.getSetting(command);
|
||||||
NPCSetting npcSetting = null;
|
if (blacksmithSetting != null && blacksmithSetting.isMessage()) {
|
||||||
for (NPCSetting setting : NPCSetting.values()) {
|
|
||||||
if (setting.getCommandName().equalsIgnoreCase(args[0])) {
|
|
||||||
npcSetting = setting;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (npcSetting != null && npcSetting.getPath().startsWith("defaults.messages")) {
|
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets tab-completions for a selected material or enchantment
|
* Gets tab-completions for a selected material or enchantment
|
||||||
*
|
*
|
||||||
* @param globalSetting <p>The global setting to get tab-completions for</p>
|
* @param blacksmithSetting <p>The global setting to get tab-completions for</p>
|
||||||
* @param args <p>The arguments given by the user</p>
|
* @param args <p>The arguments given by the user</p>
|
||||||
* @return <p>The tab-completions to show to the user</p>
|
* @return <p>The tab-completions to show to the user</p>
|
||||||
*/
|
*/
|
||||||
private List<String> getPerTypeTabCompletions(GlobalSetting globalSetting, String[] args) {
|
private List<String> getPerTypeTabCompletions(@NotNull BlacksmithSetting blacksmithSetting,
|
||||||
|
@NotNull String[] args) {
|
||||||
//Display possible tab-completions only if a valid enchantment or material is provided
|
//Display possible tab-completions only if a valid enchantment or material is provided
|
||||||
if (((globalSetting == GlobalSetting.BASE_PRICE ||
|
if (((blacksmithSetting == BlacksmithSetting.BASE_PRICE ||
|
||||||
globalSetting == GlobalSetting.PRICE_PER_DURABILITY_POINT) &&
|
blacksmithSetting == BlacksmithSetting.PRICE_PER_DURABILITY_POINT) &&
|
||||||
InputParsingHelper.matchMaterial(args[1]) != null) ||
|
InputParsingHelper.matchMaterial(args[1]) != null) ||
|
||||||
(globalSetting == GlobalSetting.ENCHANTMENT_COST &&
|
(blacksmithSetting == BlacksmithSetting.ENCHANTMENT_COST &&
|
||||||
InputParsingHelper.matchEnchantment(args[1]) != null)) {
|
InputParsingHelper.matchEnchantment(args[1]) != null)) {
|
||||||
return filterMatchingContains(getTabCompletions(globalSetting.getValueType()), args[2]);
|
return filterMatchingContains(getTabCompletions(blacksmithSetting.getValueType()), args[2]);
|
||||||
} else {
|
} else {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
@ -109,36 +99,39 @@ public class BlackSmithConfigTabCompleter implements TabCompleter {
|
|||||||
* @param commandValue <p>The command value used to filter tab-completions</p>
|
* @param commandValue <p>The command value used to filter tab-completions</p>
|
||||||
* @return <p>Some valid options for the command's argument</p>
|
* @return <p>Some valid options for the command's argument</p>
|
||||||
*/
|
*/
|
||||||
private List<String> tabCompleteCommandValues(String commandName, String commandValue) {
|
private List<String> tabCompleteCommandValues(@NotNull String commandName, @NotNull String commandValue) {
|
||||||
if (commandName.equalsIgnoreCase("reload")) {
|
if (commandName.equalsIgnoreCase("reload")) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
for (GlobalSetting globalSetting : GlobalSetting.values()) {
|
BlacksmithSetting setting = BlacksmithSetting.getSetting(commandName);
|
||||||
if (globalSetting.getCommandName().equalsIgnoreCase(commandName)) {
|
if (setting != null) {
|
||||||
return getCompletions(globalSetting, commandValue);
|
return getCompletions(setting, commandValue);
|
||||||
}
|
} else {
|
||||||
}
|
|
||||||
for (NPCSetting npcSetting : NPCSetting.values()) {
|
|
||||||
if (npcSetting.getCommandName().equalsIgnoreCase(commandName)) {
|
|
||||||
return filterMatchingContains(getTabCompletions(
|
|
||||||
npcSetting.getValueType()), commandValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets tab-completions for the given global setting and filters on the command value
|
* Gets tab-completions for the given global setting and filters on the command value
|
||||||
*
|
*
|
||||||
* @param globalSetting <p>The global setting to get tab-completions for</p>
|
* @param blacksmithSetting <p>The global setting to get tab-completions for</p>
|
||||||
* @param commandValue <p>The command value used to filter between available tab-completions</p>
|
* @param commandValue <p>The command value used to filter between available tab-completions</p>
|
||||||
* @return <p>The available tab-completions</p>
|
* @return <p>The available tab-completions</p>
|
||||||
*/
|
*/
|
||||||
private List<String> getCompletions(GlobalSetting globalSetting, String commandValue) {
|
private List<String> getCompletions(@NotNull BlacksmithSetting blacksmithSetting,
|
||||||
List<String> returnValues = filterMatchingContains(getTabCompletions(globalSetting.getValueType()), commandValue);
|
@NotNull String commandValue) {
|
||||||
if (globalSetting == GlobalSetting.BASE_PRICE || globalSetting == GlobalSetting.PRICE_PER_DURABILITY_POINT) {
|
if (blacksmithSetting == BlacksmithSetting.ENCHANTMENT_BLOCK_LIST ||
|
||||||
|
blacksmithSetting == BlacksmithSetting.REFORGE_ABLE_ITEMS) {
|
||||||
|
return TabCompletionHelper.getStringList(getTabCompletions(blacksmithSetting.getValueType()),
|
||||||
|
commandValue, TabCompletionHelper::filterMatchingContains);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> returnValues = filterMatchingContains(
|
||||||
|
getTabCompletions(blacksmithSetting.getValueType()), commandValue);
|
||||||
|
if (blacksmithSetting == BlacksmithSetting.BASE_PRICE ||
|
||||||
|
blacksmithSetting == BlacksmithSetting.PRICE_PER_DURABILITY_POINT) {
|
||||||
returnValues.addAll(filterMatchingContains(getTabCompletions(SettingValueType.MATERIAL), commandValue));
|
returnValues.addAll(filterMatchingContains(getTabCompletions(SettingValueType.MATERIAL), commandValue));
|
||||||
} else if (globalSetting == GlobalSetting.ENCHANTMENT_COST) {
|
} else if (blacksmithSetting == BlacksmithSetting.ENCHANTMENT_COST) {
|
||||||
returnValues.addAll(filterMatchingContains(getTabCompletions(SettingValueType.ENCHANTMENT), commandValue));
|
returnValues.addAll(filterMatchingContains(getTabCompletions(SettingValueType.ENCHANTMENT), commandValue));
|
||||||
}
|
}
|
||||||
return returnValues;
|
return returnValues;
|
@ -0,0 +1,32 @@
|
|||||||
|
package net.knarcraft.blacksmith.command.blacksmith;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.command.EditCommand;
|
||||||
|
import net.knarcraft.blacksmith.config.Settings;
|
||||||
|
import net.knarcraft.blacksmith.config.blacksmith.BlacksmithSetting;
|
||||||
|
import net.knarcraft.blacksmith.trait.BlacksmithTrait;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main command used for blacksmith editing
|
||||||
|
*/
|
||||||
|
public class BlackSmithEditCommand extends EditCommand<BlacksmithTrait, BlacksmithSetting> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new blacksmith edit command
|
||||||
|
*/
|
||||||
|
public BlackSmithEditCommand() {
|
||||||
|
super(BlacksmithTrait.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlacksmithSetting getSetting(String input) {
|
||||||
|
return BlacksmithSetting.getSetting(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Settings<BlacksmithSetting> getGlobalSettings() {
|
||||||
|
return BlacksmithPlugin.getInstance().getGlobalBlacksmithSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package net.knarcraft.blacksmith.command;
|
package net.knarcraft.blacksmith.command.blacksmith;
|
||||||
|
|
||||||
import net.knarcraft.blacksmith.config.NPCSetting;
|
import net.knarcraft.blacksmith.config.blacksmith.BlacksmithSetting;
|
||||||
import net.knarcraft.blacksmith.util.TabCompleteValuesHelper;
|
import net.knarcraft.blacksmith.util.TabCompleteValuesHelper;
|
||||||
import net.knarcraft.blacksmith.util.TabCompletionHelper;
|
import net.knarcraft.knarlib.util.TabCompletionHelper;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.command.TabCompleter;
|
import org.bukkit.command.TabCompleter;
|
||||||
@ -17,23 +17,24 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class BlackSmithEditTabCompleter implements TabCompleter {
|
public class BlackSmithEditTabCompleter implements TabCompleter {
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
|
||||||
@NotNull String[] args) {
|
@NotNull String label, @NotNull String[] args) {
|
||||||
if (!sender.hasPermission("blacksmith.edit")) {
|
if (!sender.hasPermission("blacksmith.edit")) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> npcSettings = new ArrayList<>();
|
List<String> npcSettings = new ArrayList<>();
|
||||||
for (NPCSetting setting : NPCSetting.values()) {
|
for (BlacksmithSetting setting : BlacksmithSetting.values()) {
|
||||||
|
if (setting.isPerNPC()) {
|
||||||
npcSettings.add(setting.getCommandName());
|
npcSettings.add(setting.getCommandName());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (args.length == 1) {
|
if (args.length == 1) {
|
||||||
return TabCompletionHelper.filterMatchingContains(npcSettings, args[0]);
|
return TabCompletionHelper.filterMatchingContains(npcSettings, args[0]);
|
||||||
} else {
|
} else {
|
||||||
if (npcSettings.contains(args[0]) && args.length <= 2) {
|
if (npcSettings.contains(args[0]) && args.length == 2) {
|
||||||
return tabCompleteCommandValues(args[0], args[1]);
|
return tabCompleteCommandValues(args[0], args[1]);
|
||||||
} else {
|
} else {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
@ -48,14 +49,14 @@ public class BlackSmithEditTabCompleter implements TabCompleter {
|
|||||||
* @param commandValue <p>The command value used to filter tab-completions</p>
|
* @param commandValue <p>The command value used to filter tab-completions</p>
|
||||||
* @return <p>Some valid options for the command's argument</p>
|
* @return <p>Some valid options for the command's argument</p>
|
||||||
*/
|
*/
|
||||||
private List<String> tabCompleteCommandValues(String commandName, String commandValue) {
|
private @Nullable List<String> tabCompleteCommandValues(@NotNull String commandName, @NotNull String commandValue) {
|
||||||
for (NPCSetting npcSetting : NPCSetting.values()) {
|
BlacksmithSetting setting = BlacksmithSetting.getSetting(commandName);
|
||||||
if (npcSetting.getCommandName().equalsIgnoreCase(commandName)) {
|
if (setting != null) {
|
||||||
return TabCompletionHelper.filterMatchingContains(TabCompleteValuesHelper.getTabCompletions(
|
return TabCompletionHelper.filterMatchingContains(TabCompleteValuesHelper.getTabCompletions(
|
||||||
npcSetting.getValueType()), commandValue);
|
setting.getValueType()), commandValue);
|
||||||
}
|
} else {
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package net.knarcraft.blacksmith.command.scrapper;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.command.ReloadCommand;
|
||||||
|
import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings;
|
||||||
|
import net.knarcraft.blacksmith.config.scrapper.ScrapperSetting;
|
||||||
|
import net.knarcraft.blacksmith.util.ConfigCommandHelper;
|
||||||
|
import net.knarcraft.blacksmith.util.TypeValidationHelper;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The command used for changing global scrapper configuration options
|
||||||
|
*/
|
||||||
|
public class ScrapperConfigCommand implements CommandExecutor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
||||||
|
@NotNull String[] args) {
|
||||||
|
if (args.length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String commandName = args[0];
|
||||||
|
if (commandName.equalsIgnoreCase("reload")) {
|
||||||
|
return new ReloadCommand().onCommand(sender, command, label, args);
|
||||||
|
}
|
||||||
|
GlobalScrapperSettings settings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings();
|
||||||
|
|
||||||
|
//Find which setting the user has specified, if any
|
||||||
|
ScrapperSetting detectedSetting = ScrapperSetting.getSetting(commandName);
|
||||||
|
if (detectedSetting == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Display the current value of a setting
|
||||||
|
if (args.length == 1) {
|
||||||
|
ConfigCommandHelper.displayCurrentValue(detectedSetting, settings, sender);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Change the value of the specified setting
|
||||||
|
if (TypeValidationHelper.isValid(detectedSetting.getValueType(), args[1], sender)) {
|
||||||
|
ConfigCommandHelper.changeValue(args, detectedSetting, settings, sender);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
package net.knarcraft.blacksmith.command.scrapper;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.config.Setting;
|
||||||
|
import net.knarcraft.blacksmith.config.scrapper.ScrapperSetting;
|
||||||
|
import net.knarcraft.knarlib.util.TabCompletionHelper;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.TabCompleter;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static net.knarcraft.blacksmith.util.TabCompleteValuesHelper.getTabCompletions;
|
||||||
|
import static net.knarcraft.knarlib.util.TabCompletionHelper.filterMatchingContains;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The tab completer for the command used for changing global scrapper configuration options
|
||||||
|
*/
|
||||||
|
public class ScrapperConfigTabCompleter implements TabCompleter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
|
||||||
|
@NotNull String s, @NotNull String[] args) {
|
||||||
|
if (!sender.hasPermission("blacksmith.admin")) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Arguments: <setting> [new value/material or enchantment] []
|
||||||
|
|
||||||
|
//Prevent tab-completion when typing messages with spaces
|
||||||
|
if (args.length > 2 && skipCompletionForSpacedMessage(args[0])) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length == 1) {
|
||||||
|
List<String> availableCommands = new ArrayList<>();
|
||||||
|
availableCommands.add("reload");
|
||||||
|
for (Setting setting : ScrapperSetting.values()) {
|
||||||
|
availableCommands.add(setting.getCommandName());
|
||||||
|
}
|
||||||
|
return filterMatchingContains(availableCommands, args[0]);
|
||||||
|
} else if (args.length == 2) {
|
||||||
|
return tabCompleteCommandValues(args[0], args[1]);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether to tab-complete nothing because a message containing spaces is being written
|
||||||
|
*
|
||||||
|
* @param command <p>The command specified by the user</p>
|
||||||
|
* @return <p>Null if not writing a spaced message</p>
|
||||||
|
*/
|
||||||
|
private boolean skipCompletionForSpacedMessage(@NotNull String command) {
|
||||||
|
Setting scrapperSetting = ScrapperSetting.getSetting(command);
|
||||||
|
return scrapperSetting != null && scrapperSetting.isMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tab completes the values available for the given command
|
||||||
|
*
|
||||||
|
* @param commandName <p>The name of the used command</p>
|
||||||
|
* @param commandValue <p>The command value used to filter tab-completions</p>
|
||||||
|
* @return <p>Some valid options for the command's argument</p>
|
||||||
|
*/
|
||||||
|
private List<String> tabCompleteCommandValues(@NotNull String commandName, @NotNull String commandValue) {
|
||||||
|
if (commandName.equalsIgnoreCase("reload")) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
Setting scrapperSetting = ScrapperSetting.getSetting(commandName);
|
||||||
|
if (scrapperSetting != null) {
|
||||||
|
if (scrapperSetting == ScrapperSetting.SALVAGE_ABLE_ITEMS) {
|
||||||
|
return TabCompletionHelper.getStringList(getTabCompletions(scrapperSetting.getValueType()),
|
||||||
|
commandValue, TabCompletionHelper::filterMatchingContains);
|
||||||
|
}
|
||||||
|
|
||||||
|
return filterMatchingContains(getTabCompletions(scrapperSetting.getValueType()), commandValue);
|
||||||
|
} else {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package net.knarcraft.blacksmith.command.scrapper;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.command.EditCommand;
|
||||||
|
import net.knarcraft.blacksmith.config.Settings;
|
||||||
|
import net.knarcraft.blacksmith.config.scrapper.ScrapperSetting;
|
||||||
|
import net.knarcraft.blacksmith.trait.ScrapperTrait;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main command used for scrapper editing
|
||||||
|
*/
|
||||||
|
public class ScrapperEditCommand extends EditCommand<ScrapperTrait, ScrapperSetting> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new scrapper edit command
|
||||||
|
*/
|
||||||
|
public ScrapperEditCommand() {
|
||||||
|
super(ScrapperTrait.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScrapperSetting getSetting(String input) {
|
||||||
|
return ScrapperSetting.getSetting(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Settings<ScrapperSetting> getGlobalSettings() {
|
||||||
|
return BlacksmithPlugin.getInstance().getGlobalScrapperSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
package net.knarcraft.blacksmith.command.scrapper;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.config.scrapper.ScrapperSetting;
|
||||||
|
import net.knarcraft.blacksmith.util.TabCompleteValuesHelper;
|
||||||
|
import net.knarcraft.knarlib.util.TabCompletionHelper;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.TabCompleter;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The tab completer for the scrapper editing command
|
||||||
|
*/
|
||||||
|
public class ScrapperEditTabCompleter implements TabCompleter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
|
||||||
|
@NotNull String s, @NotNull String[] args) {
|
||||||
|
if (!sender.hasPermission("blacksmith.edit")) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> npcSettings = new ArrayList<>();
|
||||||
|
for (ScrapperSetting setting : ScrapperSetting.values()) {
|
||||||
|
if (setting.isPerNPC()) {
|
||||||
|
npcSettings.add(setting.getCommandName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length == 1) {
|
||||||
|
return TabCompletionHelper.filterMatchingContains(npcSettings, args[0]);
|
||||||
|
} else {
|
||||||
|
if (npcSettings.contains(args[0]) && args.length == 2) {
|
||||||
|
return tabCompleteCommandValues(args[0], args[1]);
|
||||||
|
} else {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tab completes the values available for the given command
|
||||||
|
*
|
||||||
|
* @param commandName <p>The name of the used command</p>
|
||||||
|
* @param commandValue <p>The command value used to filter tab-completions</p>
|
||||||
|
* @return <p>Some valid options for the command's argument</p>
|
||||||
|
*/
|
||||||
|
private @Nullable List<String> tabCompleteCommandValues(@NotNull String commandName, @NotNull String commandValue) {
|
||||||
|
ScrapperSetting setting = ScrapperSetting.getSetting(commandName);
|
||||||
|
if (setting != null) {
|
||||||
|
return TabCompletionHelper.filterMatchingContains(TabCompleteValuesHelper.getTabCompletions(
|
||||||
|
setting.getValueType()), commandValue);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,109 +0,0 @@
|
|||||||
package net.knarcraft.blacksmith.config;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
public enum GlobalSetting {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The base price for repairing, regardless of durability
|
|
||||||
*
|
|
||||||
* <p>This allows specifying a price for each item, by setting basePrice.item_name.</p>
|
|
||||||
*/
|
|
||||||
BASE_PRICE("global.basePrice.default", SettingValueType.POSITIVE_DOUBLE, 10.0, "basePrice"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The base price for each durability point
|
|
||||||
*
|
|
||||||
* <p>If natural cost, this is the cost each missing durability point will add to the cost. If not natural cost,
|
|
||||||
* this is the cost each present durability point will add to the cost. This allows specifying a price per
|
|
||||||
* durability point value for each item, by setting pricePerDurabilityPoint.item_name</p>
|
|
||||||
*/
|
|
||||||
PRICE_PER_DURABILITY_POINT("global.pricePerDurabilityPoint.default", SettingValueType.POSITIVE_DOUBLE,
|
|
||||||
0.005, "pricePerDurabilityPoint"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The price increase for each level of each present enchantment
|
|
||||||
*
|
|
||||||
* <p>This can be specified for each possible enchantment by setting enchantment-cost.enchantment_name</p>
|
|
||||||
*/
|
|
||||||
ENCHANTMENT_COST("global.enchantmentCost.default", SettingValueType.POSITIVE_DOUBLE, 5.0, "enchantmentCost"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the cost should increase for damage taken, as opposed to increase for durability present
|
|
||||||
*/
|
|
||||||
NATURAL_COST("global.useNaturalCost", SettingValueType.BOOLEAN, true, "useNaturalCost"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to show exact time when displaying the wait time for a reforging or the cool-down
|
|
||||||
*/
|
|
||||||
SHOW_EXACT_TIME("global.showExactTime", SettingValueType.BOOLEAN, false, "showExactTime");
|
|
||||||
|
|
||||||
private final String path;
|
|
||||||
private final String parent;
|
|
||||||
private final String commandName;
|
|
||||||
private final Object value;
|
|
||||||
private final SettingValueType valueType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiates a new setting
|
|
||||||
*
|
|
||||||
* @param path <p>The full config path for this setting</p>
|
|
||||||
* @param valueType <p>The type of value used by this setting</p>
|
|
||||||
* @param value <p>The default value of this setting</p>
|
|
||||||
* @param commandName <p>The name of the command used to change this setting</p>
|
|
||||||
*/
|
|
||||||
GlobalSetting(String path, SettingValueType valueType, Object value, String commandName) {
|
|
||||||
this.path = path;
|
|
||||||
this.value = value;
|
|
||||||
this.commandName = commandName;
|
|
||||||
this.valueType = valueType;
|
|
||||||
String[] pathParts = path.split("\\.");
|
|
||||||
this.parent = String.join(".", Arrays.copyOfRange(pathParts, 0, pathParts.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the full config path for this setting
|
|
||||||
*
|
|
||||||
* @return <p>The full config path for this setting</p>
|
|
||||||
*/
|
|
||||||
public String getPath() {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the parent item of the defined path
|
|
||||||
*
|
|
||||||
* @return <p>The parent node</p>
|
|
||||||
*/
|
|
||||||
public String getParent() {
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value of this setting
|
|
||||||
*
|
|
||||||
* @return <p>The value of this setting</p>
|
|
||||||
*/
|
|
||||||
public Object getDefaultValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of the command used to change this setting
|
|
||||||
*
|
|
||||||
* @return <p>The name of this setting's command</p>
|
|
||||||
*/
|
|
||||||
public String getCommandName() {
|
|
||||||
return commandName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value type for this setting
|
|
||||||
*
|
|
||||||
* @return <p>The value type for this setting</p>
|
|
||||||
*/
|
|
||||||
public SettingValueType getValueType() {
|
|
||||||
return this.valueType;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,436 +0,0 @@
|
|||||||
package net.knarcraft.blacksmith.config;
|
|
||||||
|
|
||||||
import net.citizensnpcs.api.util.DataKey;
|
|
||||||
import net.citizensnpcs.api.util.YamlStorage;
|
|
||||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
|
||||||
import net.knarcraft.blacksmith.util.ConfigHelper;
|
|
||||||
import net.knarcraft.blacksmith.util.InputParsingHelper;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.enchantments.Enchantment;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class which keeps track of all default NPC settings and all global settings
|
|
||||||
*/
|
|
||||||
public class GlobalSettings {
|
|
||||||
|
|
||||||
private final Map<Material, Double> materialBasePrices = new HashMap<>();
|
|
||||||
private final Map<Material, Double> materialPricePerDurabilityPoints = new HashMap<>();
|
|
||||||
private final Map<Enchantment, Double> enchantmentCosts = new HashMap<>();
|
|
||||||
|
|
||||||
private final Map<NPCSetting, Object> defaultNPCSettings = new HashMap<>();
|
|
||||||
private final Map<GlobalSetting, Object> globalSettings = new HashMap<>();
|
|
||||||
|
|
||||||
private final YamlStorage defaultConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiates a new "Settings"
|
|
||||||
*
|
|
||||||
* @param plugin <p>A reference to the blacksmith plugin</p>
|
|
||||||
*/
|
|
||||||
public GlobalSettings(BlacksmithPlugin plugin) {
|
|
||||||
defaultConfig = new YamlStorage(new File(plugin.getDataFolder() + File.separator + "config.yml"),
|
|
||||||
"Blacksmith Configuration\nWarning: The values under defaults are the values set for a " +
|
|
||||||
"blacksmith upon creation. To change any values for existing NPCs, edit the citizens NPC file.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads all configuration values from the config file
|
|
||||||
*/
|
|
||||||
public void load() {
|
|
||||||
//Load the config from disk
|
|
||||||
defaultConfig.load();
|
|
||||||
DataKey root = defaultConfig.getKey("");
|
|
||||||
|
|
||||||
//Just in case, clear existing values
|
|
||||||
defaultNPCSettings.clear();
|
|
||||||
globalSettings.clear();
|
|
||||||
materialBasePrices.clear();
|
|
||||||
materialPricePerDurabilityPoints.clear();
|
|
||||||
enchantmentCosts.clear();
|
|
||||||
|
|
||||||
//Load/Save NPC default settings
|
|
||||||
loadDefaultNPCSettings(root);
|
|
||||||
|
|
||||||
//Load/Save global settings
|
|
||||||
loadGlobalSettings(root);
|
|
||||||
|
|
||||||
//Save any modified values to disk
|
|
||||||
defaultConfig.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the value of the given setting
|
|
||||||
*
|
|
||||||
* @param globalSetting <p>The global setting to change</p>
|
|
||||||
* @param newValue <p>The new value of the setting</p>
|
|
||||||
*/
|
|
||||||
public void changeValue(GlobalSetting globalSetting, Object newValue) {
|
|
||||||
globalSettings.put(globalSetting, newValue);
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the value of the given setting
|
|
||||||
*
|
|
||||||
* @param npcSetting <p>The default NPC setting to change</p>
|
|
||||||
* @param newValue <p>The new value for the setting</p>
|
|
||||||
*/
|
|
||||||
public void changeValue(NPCSetting npcSetting, Object newValue) {
|
|
||||||
if (npcSetting.getValueType() == SettingValueType.STRING_LIST) {
|
|
||||||
//Workaround to make sure it's treated as the correct type
|
|
||||||
defaultNPCSettings.put(npcSetting, ConfigHelper.asStringList(newValue));
|
|
||||||
} else {
|
|
||||||
defaultNPCSettings.put(npcSetting, newValue);
|
|
||||||
}
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current raw value of the given global setting
|
|
||||||
*
|
|
||||||
* @param globalSetting <p>The setting to get</p>
|
|
||||||
* @return <p>The current raw setting value</p>
|
|
||||||
*/
|
|
||||||
public Object getRawValue(GlobalSetting globalSetting) {
|
|
||||||
return globalSettings.get(globalSetting);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current raw value of the given default NPC setting
|
|
||||||
*
|
|
||||||
* @param npcSetting <p>The setting to get</p>
|
|
||||||
* @return <p>The current raw setting value</p>
|
|
||||||
*/
|
|
||||||
public Object getRawValue(NPCSetting npcSetting) {
|
|
||||||
return defaultNPCSettings.get(npcSetting);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the enchantment cost for the given enchantment
|
|
||||||
*
|
|
||||||
* @param enchantment <p>The enchantment to set the enchantment cost for</p>
|
|
||||||
* @param newEnchantmentCost <p>The new enchantment cost</p>
|
|
||||||
*/
|
|
||||||
public void setEnchantmentCost(Enchantment enchantment, double newEnchantmentCost) {
|
|
||||||
if (enchantment == null) {
|
|
||||||
if (newEnchantmentCost < 0) {
|
|
||||||
throw new IllegalArgumentException("Enchantment cost cannot be negative!");
|
|
||||||
}
|
|
||||||
globalSettings.put(GlobalSetting.ENCHANTMENT_COST, newEnchantmentCost);
|
|
||||||
} else {
|
|
||||||
if (newEnchantmentCost < 0) {
|
|
||||||
enchantmentCosts.put(enchantment, null);
|
|
||||||
} else {
|
|
||||||
enchantmentCosts.put(enchantment, newEnchantmentCost);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the price per durability point for the given material
|
|
||||||
*
|
|
||||||
* @param material <p>The material to set the price per durability point price for</p>
|
|
||||||
* @param newPrice <p>The new price per durability point price</p>
|
|
||||||
*/
|
|
||||||
public void setPricePerDurabilityPoint(Material material, double newPrice) {
|
|
||||||
if (material == null) {
|
|
||||||
if (newPrice < 0) {
|
|
||||||
throw new IllegalArgumentException("Price per durability point cannot be negative!");
|
|
||||||
}
|
|
||||||
globalSettings.put(GlobalSetting.PRICE_PER_DURABILITY_POINT, newPrice);
|
|
||||||
} else {
|
|
||||||
//Use a negative price to unset the per-item value
|
|
||||||
if (newPrice < 0) {
|
|
||||||
materialPricePerDurabilityPoints.put(material, null);
|
|
||||||
} else {
|
|
||||||
materialPricePerDurabilityPoints.put(material, newPrice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the base price for the given material
|
|
||||||
*
|
|
||||||
* @param material <p>The material to set the base price for</p>
|
|
||||||
* @param newBasePrice <p>The new base price</p>
|
|
||||||
*/
|
|
||||||
public void setBasePrice(Material material, double newBasePrice) {
|
|
||||||
if (material == null) {
|
|
||||||
if (newBasePrice < 0) {
|
|
||||||
throw new IllegalArgumentException("Base price cannot be negative!");
|
|
||||||
}
|
|
||||||
globalSettings.put(GlobalSetting.BASE_PRICE, newBasePrice);
|
|
||||||
} else {
|
|
||||||
//Use a negative price to unset the per-item value
|
|
||||||
if (newBasePrice < 0) {
|
|
||||||
materialBasePrices.put(material, null);
|
|
||||||
} else {
|
|
||||||
materialBasePrices.put(material, newBasePrice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current value of the default NPC settings
|
|
||||||
*
|
|
||||||
* @return <p>The current value of the default NPC settings</p>
|
|
||||||
*/
|
|
||||||
public Map<NPCSetting, Object> getDefaultNPCSettings() {
|
|
||||||
return new HashMap<>(this.defaultNPCSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether to use natural cost for cost calculation
|
|
||||||
*
|
|
||||||
* <p>Natural cost makes it more costly the more damage is dealt to an item. The alternative is the legacy behavior
|
|
||||||
* where the amount of durability points remaining increases the cost.</p>
|
|
||||||
*
|
|
||||||
* @return <p>Whether to use natural cost</p>
|
|
||||||
*/
|
|
||||||
public boolean getUseNaturalCost() {
|
|
||||||
return asBoolean(GlobalSetting.NATURAL_COST);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether to show exact time for reforging wait-time, and for wait-time between sessions
|
|
||||||
*
|
|
||||||
* @return <p>Whether to show exact time</p>
|
|
||||||
*/
|
|
||||||
public boolean getShowExactTime() {
|
|
||||||
return asBoolean(GlobalSetting.SHOW_EXACT_TIME);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the base price for the given material
|
|
||||||
*
|
|
||||||
* @param material <p>The material to get the base price for</p>
|
|
||||||
* @return <p>The base price for the material</p>
|
|
||||||
*/
|
|
||||||
public double getBasePrice(Material material) {
|
|
||||||
if (materialBasePrices.containsKey(material) && materialBasePrices.get(material) != null) {
|
|
||||||
return materialBasePrices.get(material);
|
|
||||||
} else {
|
|
||||||
return asDouble(GlobalSetting.BASE_PRICE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the price per durability point for the given material
|
|
||||||
*
|
|
||||||
* @param material <p>The material to get the durability point price for</p>
|
|
||||||
* @return <p>The durability point price for the material</p>
|
|
||||||
*/
|
|
||||||
public double getPricePerDurabilityPoint(Material material) {
|
|
||||||
if (materialPricePerDurabilityPoints.containsKey(material) &&
|
|
||||||
materialPricePerDurabilityPoints.get(material) != null) {
|
|
||||||
return materialPricePerDurabilityPoints.get(material);
|
|
||||||
} else {
|
|
||||||
return asDouble(GlobalSetting.PRICE_PER_DURABILITY_POINT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the cost to be added for each level of the given enchantment
|
|
||||||
*
|
|
||||||
* @param enchantment <p>The enchantment to get the cost for</p>
|
|
||||||
* @return <p>The cost of each enchantment level</p>
|
|
||||||
*/
|
|
||||||
public double getEnchantmentCost(Enchantment enchantment) {
|
|
||||||
if (enchantmentCosts.containsKey(enchantment) && enchantmentCosts.get(enchantment) != null) {
|
|
||||||
return enchantmentCosts.get(enchantment);
|
|
||||||
} else {
|
|
||||||
return asDouble(GlobalSetting.ENCHANTMENT_COST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the given value as a boolean
|
|
||||||
*
|
|
||||||
* <p>This will throw an exception if used for a non-boolean value</p>
|
|
||||||
*
|
|
||||||
* @param setting <p>The setting to get the value of</p>
|
|
||||||
* @return <p>The value of the given setting as a boolean</p>
|
|
||||||
*/
|
|
||||||
public boolean asBoolean(GlobalSetting setting) {
|
|
||||||
return ConfigHelper.asBoolean(getValue(setting));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the given value as a double
|
|
||||||
*
|
|
||||||
* <p>This will throw an exception if used for a non-double setting</p>
|
|
||||||
*
|
|
||||||
* @param setting <p>The setting to get the value of</p>
|
|
||||||
* @return <p>The value of the given setting as a double</p>
|
|
||||||
*/
|
|
||||||
public double asDouble(GlobalSetting setting) {
|
|
||||||
return ConfigHelper.asDouble(getValue(setting));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value of a setting, using the default if not set
|
|
||||||
*
|
|
||||||
* @param setting <p>The setting to get the value of</p>
|
|
||||||
* @return <p>The current value</p>
|
|
||||||
*/
|
|
||||||
private Object getValue(GlobalSetting setting) {
|
|
||||||
Object value = globalSettings.get(setting);
|
|
||||||
//If not set in config.yml, use the default value from the enum
|
|
||||||
if (value == null) {
|
|
||||||
value = setting.getDefaultValue();
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads all global settings
|
|
||||||
*
|
|
||||||
* @param root <p>The root node of all global settings</p>
|
|
||||||
*/
|
|
||||||
private void loadGlobalSettings(DataKey root) {
|
|
||||||
for (GlobalSetting globalSetting : GlobalSetting.values()) {
|
|
||||||
if (!root.keyExists(globalSetting.getPath())) {
|
|
||||||
//If the setting does not exist in the config file, add it
|
|
||||||
root.setRaw(globalSetting.getPath(), globalSetting.getDefaultValue());
|
|
||||||
} else {
|
|
||||||
//Set the setting to the value found in the path
|
|
||||||
globalSettings.put(globalSetting, root.getRaw(globalSetting.getPath()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Load all base prices
|
|
||||||
DataKey basePriceNode = root.getRelative(GlobalSetting.BASE_PRICE.getParent());
|
|
||||||
Map<String, String> relevantKeys = getRelevantKeys(basePriceNode);
|
|
||||||
for (String key : relevantKeys.keySet()) {
|
|
||||||
String materialName = relevantKeys.get(key);
|
|
||||||
Material material = InputParsingHelper.matchMaterial(materialName);
|
|
||||||
if (material != null) {
|
|
||||||
materialBasePrices.put(material, basePriceNode.getDouble(key));
|
|
||||||
} else {
|
|
||||||
BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING,
|
|
||||||
"Unable to find a material matching " + materialName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Load all per-durability-point prices
|
|
||||||
DataKey basePerDurabilityPriceNode = root.getRelative(GlobalSetting.PRICE_PER_DURABILITY_POINT.getParent());
|
|
||||||
relevantKeys = getRelevantKeys(basePerDurabilityPriceNode);
|
|
||||||
for (String key : relevantKeys.keySet()) {
|
|
||||||
String materialName = relevantKeys.get(key);
|
|
||||||
Material material = InputParsingHelper.matchMaterial(materialName);
|
|
||||||
if (material != null) {
|
|
||||||
materialPricePerDurabilityPoints.put(material, basePerDurabilityPriceNode.getDouble(key));
|
|
||||||
} else {
|
|
||||||
BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING,
|
|
||||||
"Unable to find a material matching " + materialName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Load all enchantment prices
|
|
||||||
DataKey enchantmentCostNode = root.getRelative(GlobalSetting.ENCHANTMENT_COST.getParent());
|
|
||||||
relevantKeys = getRelevantKeys(basePerDurabilityPriceNode);
|
|
||||||
for (String key : relevantKeys.keySet()) {
|
|
||||||
String enchantmentName = relevantKeys.get(key);
|
|
||||||
Enchantment enchantment = InputParsingHelper.matchEnchantment(enchantmentName);
|
|
||||||
if (enchantment != null) {
|
|
||||||
enchantmentCosts.put(enchantment, enchantmentCostNode.getDouble(key));
|
|
||||||
} else {
|
|
||||||
BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING,
|
|
||||||
"Unable to find an enchantment matching " + enchantmentName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a map between relevant keys and their normalized name
|
|
||||||
*
|
|
||||||
* @param rootKey <p>The root data key containing sub-keys</p>
|
|
||||||
* @return <p>Any sub-keys found that aren't the default</p>
|
|
||||||
*/
|
|
||||||
private Map<String, String> getRelevantKeys(DataKey rootKey) {
|
|
||||||
Map<String, String> relevant = new HashMap<>();
|
|
||||||
for (DataKey dataKey : rootKey.getSubKeys()) {
|
|
||||||
String keyName = dataKey.name();
|
|
||||||
//Skip the default value
|
|
||||||
if (keyName.equals("default")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String normalizedName = keyName.toUpperCase().replace("-", "_");
|
|
||||||
relevant.put(keyName, normalizedName);
|
|
||||||
}
|
|
||||||
return relevant;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a normalized material name to the format used in the config file
|
|
||||||
*
|
|
||||||
* @param normalizedName <p>The normalized name to un-normalize</p>
|
|
||||||
* @return <p>The un-normalized name</p>
|
|
||||||
*/
|
|
||||||
private String unNormalizeName(String normalizedName) {
|
|
||||||
return normalizedName.toLowerCase().replace("_", "-");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads all default NPC settings
|
|
||||||
*
|
|
||||||
* @param root <p>The root node of all default NPC settings</p>
|
|
||||||
*/
|
|
||||||
private void loadDefaultNPCSettings(DataKey root) {
|
|
||||||
for (NPCSetting setting : NPCSetting.values()) {
|
|
||||||
if (!root.keyExists(setting.getPath())) {
|
|
||||||
//If the setting does not exist in the config file, add it
|
|
||||||
root.setRaw(setting.getPath(), setting.getDefaultValue());
|
|
||||||
} else {
|
|
||||||
//Set the setting to the value found in the path
|
|
||||||
defaultNPCSettings.put(setting, root.getRaw(setting.getPath()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves all current settings to the config file
|
|
||||||
*/
|
|
||||||
private void save() {
|
|
||||||
DataKey root = defaultConfig.getKey("");
|
|
||||||
//Save all default NPC settings
|
|
||||||
for (NPCSetting setting : NPCSetting.values()) {
|
|
||||||
root.setRaw(setting.getPath(), defaultNPCSettings.get(setting));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Save all normal global settings
|
|
||||||
for (GlobalSetting globalSetting : GlobalSetting.values()) {
|
|
||||||
root.setRaw(globalSetting.getPath(), globalSettings.get(globalSetting));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Save all base prices
|
|
||||||
DataKey basePriceNode = root.getRelative(GlobalSetting.BASE_PRICE.getParent());
|
|
||||||
for (Material material : materialBasePrices.keySet()) {
|
|
||||||
basePriceNode.setRaw(unNormalizeName(material.name()), materialBasePrices.get(material));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Save all per-durability-point prices
|
|
||||||
DataKey basePerDurabilityPriceNode = root.getRelative(GlobalSetting.PRICE_PER_DURABILITY_POINT.getParent());
|
|
||||||
for (Material material : materialPricePerDurabilityPoints.keySet()) {
|
|
||||||
basePerDurabilityPriceNode.setRaw(unNormalizeName(material.name()), materialPricePerDurabilityPoints.get(material));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Load all enchantment prices
|
|
||||||
DataKey enchantmentCostNode = root.getRelative(GlobalSetting.ENCHANTMENT_COST.getParent());
|
|
||||||
for (Enchantment enchantment : enchantmentCosts.keySet()) {
|
|
||||||
enchantmentCostNode.setRaw(unNormalizeName(enchantment.getKey().getKey()), enchantmentCosts.get(enchantment));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Perform the actual save to disk
|
|
||||||
defaultConfig.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,203 +0,0 @@
|
|||||||
package net.knarcraft.blacksmith.config;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An enum representing all of Blacksmith's settings
|
|
||||||
*/
|
|
||||||
public enum NPCSetting {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The setting for whether the NPC should drop an item to the ground when finished
|
|
||||||
*
|
|
||||||
* <p>If set to false, the item will be directly put in the player's inventory instead</p>
|
|
||||||
*/
|
|
||||||
DROP_ITEM("dropItem", SettingValueType.BOOLEAN, true, "dropItem"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The setting for the chance of a reforging to fail
|
|
||||||
*/
|
|
||||||
FAIL_CHANCE("failReforgeChance", SettingValueType.PERCENTAGE, 10, "failReforgeChance"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The setting for the chance of an additional enchantment being added
|
|
||||||
*/
|
|
||||||
EXTRA_ENCHANTMENT_CHANCE("extraEnchantmentChance", SettingValueType.PERCENTAGE, 5,
|
|
||||||
"extraEnchantmentChance"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The setting for the maximum amount of enchantments that can be added to an item
|
|
||||||
*/
|
|
||||||
MAX_ENCHANTMENTS("maxEnchantments", SettingValueType.POSITIVE_INTEGER, 3, "maxEnchantments"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The maximum amount of seconds a player may need to wait for the reforging to finish
|
|
||||||
*/
|
|
||||||
MAX_REFORGE_DELAY("delaysInSeconds.maximum", SettingValueType.POSITIVE_INTEGER, 30, "maxReforgeDelay"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The minimum amount of seconds a player may need to wait for the reforging to finish
|
|
||||||
*/
|
|
||||||
MIN_REFORGE_DELAY("delaysInSeconds.minimum", SettingValueType.POSITIVE_INTEGER, 5, "minReforgeDelay"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The setting for number of seconds a player has to wait between each usage of the blacksmith
|
|
||||||
*/
|
|
||||||
REFORGE_COOL_DOWN("delaysInSeconds.reforgeCoolDown", SettingValueType.POSITIVE_INTEGER, 60, "reforgeCoolDown"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The setting for which items the blacksmith is able to reforge
|
|
||||||
*/
|
|
||||||
REFORGE_ABLE_ITEMS("reforgeAbleItems", SettingValueType.REFORGE_ABLE_ITEMS, "", "reforgeAbleItems"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The setting for the title used to display which kind of blacksmith the NPC is
|
|
||||||
*
|
|
||||||
* <p>While this should be entirely configurable, values such as armor-smith, sword-smith and similar, which
|
|
||||||
* describe the blacksmith's specialization, and thus the range of reforge-able items, is expected.</p>
|
|
||||||
*/
|
|
||||||
BLACKSMITH_TITLE("blacksmithTitle", SettingValueType.STRING, "blacksmith", "blacksmithTitle"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The setting for the enchantments a blacksmith cannot apply to items
|
|
||||||
*/
|
|
||||||
ENCHANTMENT_BLOCKLIST("enchantmentBlocklist", SettingValueType.STRING_LIST, new String[]{"binding_curse",
|
|
||||||
"mending", "vanishing_curse"}, "enchantmentBlocklist"),
|
|
||||||
|
|
||||||
/*-----------
|
|
||||||
| Messages |
|
|
||||||
-----------*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The message displayed when the blacksmith is busy with another player
|
|
||||||
*/
|
|
||||||
BUSY_WITH_PLAYER_MESSAGE("messages.busyPlayerMessage", SettingValueType.STRING,
|
|
||||||
"&cI'm busy at the moment. Come back later!", "busyPlayerMessage"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The message displayed when the blacksmith is already reforging something for the player
|
|
||||||
*/
|
|
||||||
BUSY_WITH_REFORGE_MESSAGE("messages.busyReforgeMessage", SettingValueType.STRING,
|
|
||||||
"&cI'm working on it. Be patient! I'll finish {time}!", "busyReforgeMessage"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The message displayed if the player has to wait for the cool-down to expire
|
|
||||||
*/
|
|
||||||
COOL_DOWN_UNEXPIRED_MESSAGE("messages.coolDownUnexpiredMessage", SettingValueType.STRING,
|
|
||||||
"&cYou've already had your chance! Give me a break! I'll be ready {time}!",
|
|
||||||
"coolDownUnexpiredMessage"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The message displayed when displaying the cost of reforging the held item to the player
|
|
||||||
*/
|
|
||||||
COST_MESSAGE("messages.costMessage", SettingValueType.STRING,
|
|
||||||
"&eIt will cost &a{cost}&e to reforge that &a{item}&e! Click again to reforge!", "costMessage"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The message displayed if the blacksmith fails reforging an item
|
|
||||||
*/
|
|
||||||
FAIL_MESSAGE("messages.failReforgeMessage", SettingValueType.STRING,
|
|
||||||
"&cWhoops! Didn't mean to do that! Maybe next time?", "failReforgeMessage"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The message displayed if a player is unable to pay the blacksmith
|
|
||||||
*/
|
|
||||||
INSUFFICIENT_FUNDS_MESSAGE("messages.insufficientFundsMessage", SettingValueType.STRING,
|
|
||||||
"&cYou don't have enough money to reforge that item!", "insufficientFundsMessage"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The message displayed if the blacksmith encounters an item they cannot reforge
|
|
||||||
*/
|
|
||||||
INVALID_ITEM_MESSAGE("messages.invalidItemMessage", SettingValueType.STRING,
|
|
||||||
"&cI'm sorry, but I'm a/an {title}, I don't know how to reforge that!", "invalidItemMessage"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The message displayed if a player presents a different item after seeing the price to reforge an item
|
|
||||||
*/
|
|
||||||
ITEM_UNEXPECTEDLY_CHANGED_MESSAGE("messages.itemChangedMessage", SettingValueType.STRING,
|
|
||||||
"&cThat's not the item you wanted to reforge before!", "itemChangedMessage"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The message displayed when the blacksmith starts reforging an item
|
|
||||||
*/
|
|
||||||
START_REFORGE_MESSAGE("messages.startReforgeMessage", SettingValueType.STRING,
|
|
||||||
"&eOk, let's see what I can do...", "startReforgeMessage"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The message displayed when the blacksmith successfully finishes reforging an item
|
|
||||||
*/
|
|
||||||
SUCCESS_MESSAGE("messages.successMessage", SettingValueType.STRING,
|
|
||||||
"There you go! All better!", "successMessage"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The message displayed when trying to reforge an item with full durability
|
|
||||||
*/
|
|
||||||
NOT_DAMAGED_MESSAGE("messages.notDamagedMessage", SettingValueType.STRING,
|
|
||||||
"&cThat item is not in need of repair", "notDamagedMessage");
|
|
||||||
|
|
||||||
private final String path;
|
|
||||||
private final String childPath;
|
|
||||||
private final Object value;
|
|
||||||
private final String commandName;
|
|
||||||
private final SettingValueType valueType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiates a new setting
|
|
||||||
*
|
|
||||||
* @param path <p>The full config path for this setting</p>
|
|
||||||
* @param valueType <p>The type of value used by this setting</p>
|
|
||||||
* @param value <p>The default value of this setting</p>
|
|
||||||
* @param commandName <p>The name of the command used to change this setting</p>
|
|
||||||
*/
|
|
||||||
NPCSetting(String path, SettingValueType valueType, Object value, String commandName) {
|
|
||||||
this.path = "defaults." + path;
|
|
||||||
this.value = value;
|
|
||||||
this.valueType = valueType;
|
|
||||||
this.childPath = path;
|
|
||||||
this.commandName = commandName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the full config path for this setting
|
|
||||||
*
|
|
||||||
* @return <p>The full config path for this setting</p>
|
|
||||||
*/
|
|
||||||
public String getPath() {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the config path without the root node
|
|
||||||
*
|
|
||||||
* @return <p>The config path without the root node</p>
|
|
||||||
*/
|
|
||||||
public String getChildPath() {
|
|
||||||
return childPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value of this setting
|
|
||||||
*
|
|
||||||
* @return <p>The value of this setting</p>
|
|
||||||
*/
|
|
||||||
public Object getDefaultValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of the command used to change this setting
|
|
||||||
*
|
|
||||||
* @return <p>The name of this setting's command</p>
|
|
||||||
*/
|
|
||||||
public String getCommandName() {
|
|
||||||
return commandName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value type for this setting
|
|
||||||
*
|
|
||||||
* @return <p>The value type for this setting</p>
|
|
||||||
*/
|
|
||||||
public SettingValueType getValueType() {
|
|
||||||
return this.valueType;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
75
src/main/java/net/knarcraft/blacksmith/config/Setting.java
Normal file
75
src/main/java/net/knarcraft/blacksmith/config/Setting.java
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package net.knarcraft.blacksmith.config;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface describing a setting
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public interface Setting {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the full config path for this setting
|
||||||
|
*
|
||||||
|
* @return <p>The full config path for this setting</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
String getPath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the config path without the root node
|
||||||
|
*
|
||||||
|
* @return <p>The config path without the root node</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
String getChildPath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of this setting
|
||||||
|
*
|
||||||
|
* @return <p>The value of this setting</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
Object getDefaultValue();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the command used to change this setting
|
||||||
|
*
|
||||||
|
* @return <p>The name of this setting's command</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
String getCommandName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value type for this setting
|
||||||
|
*
|
||||||
|
* @return <p>The value type for this setting</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
SettingValueType getValueType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the description explaining the usage of this setting
|
||||||
|
*
|
||||||
|
* @return <p>This setting's description</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
String getDescription();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this setting can be set per-NPC, or if it's set globally
|
||||||
|
*
|
||||||
|
* @return <p>True if this setting is set per-NPC</p>
|
||||||
|
*/
|
||||||
|
boolean isPerNPC();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this setting is a customizable message
|
||||||
|
*
|
||||||
|
* <p>Messages are a special case, as you generally want to see the raw formatting, not just the result.</p>
|
||||||
|
*
|
||||||
|
* @return <p>True if this setting is a customizable message</p>
|
||||||
|
*/
|
||||||
|
boolean isMessage();
|
||||||
|
|
||||||
|
}
|
@ -50,4 +50,9 @@ public enum SettingValueType {
|
|||||||
*/
|
*/
|
||||||
REFORGE_ABLE_ITEMS,
|
REFORGE_ABLE_ITEMS,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of enchantments
|
||||||
|
*/
|
||||||
|
ENCHANTMENT_LIST,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
30
src/main/java/net/knarcraft/blacksmith/config/Settings.java
Normal file
30
src/main/java/net/knarcraft/blacksmith/config/Settings.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package net.knarcraft.blacksmith.config;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface describing an object for managing settings
|
||||||
|
*
|
||||||
|
* @param <K> <p>The type of setting managed</p>
|
||||||
|
*/
|
||||||
|
public interface Settings<K extends Setting> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the value of the given setting
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting to change</p>
|
||||||
|
* @param newValue <p>The new value of the setting</p>
|
||||||
|
*/
|
||||||
|
void changeValue(@NotNull K setting, @Nullable Object newValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current raw value of the given global setting
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting to get</p>
|
||||||
|
* @return <p>The current raw setting value</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
Object getRawValue(@NotNull K setting);
|
||||||
|
|
||||||
|
}
|
@ -1,17 +1,29 @@
|
|||||||
package net.knarcraft.blacksmith.config;
|
package net.knarcraft.blacksmith.config;
|
||||||
|
|
||||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Tag;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A representation of the presets for different kinds of smiths
|
* A representation of the presets for different kinds of smiths
|
||||||
*/
|
*/
|
||||||
public enum SmithPreset {
|
public enum SmithPreset {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A blacksmith capable of re-forging everything
|
||||||
|
*/
|
||||||
|
BLACKSMITH(new SmithPresetFilter[]{SmithPresetFilter.GOLD, SmithPresetFilter.IRON, SmithPresetFilter.DIAMOND,
|
||||||
|
SmithPresetFilter.NETHERITE}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A blacksmith capable of re-forging all weapons (including shields)
|
* A blacksmith capable of re-forging all weapons (including shields)
|
||||||
*/
|
*/
|
||||||
@ -32,13 +44,19 @@ public enum SmithPreset {
|
|||||||
SmithPresetFilter.AXE, SmithPresetFilter.HOE, SmithPresetFilter.SHOVEL, SmithPresetFilter.MISC});
|
SmithPresetFilter.AXE, SmithPresetFilter.HOE, SmithPresetFilter.SHOVEL, SmithPresetFilter.MISC});
|
||||||
|
|
||||||
private final SmithPresetFilter[] filters;
|
private final SmithPresetFilter[] filters;
|
||||||
|
private static final Map<SmithPreset, Set<String>> presetMaterialNames = new HashMap<>();
|
||||||
|
private static final Map<SmithPreset, Map<SmithPresetFilter, Set<String>>> filterMaterialNames = new HashMap<>();
|
||||||
|
private static Set<Material> armor = null;
|
||||||
|
private static Set<Material> ranged = null;
|
||||||
|
private static Set<Material> weapons = null;
|
||||||
|
private static Set<Material> tools = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new smith preset
|
* Instantiates a new smith preset
|
||||||
*
|
*
|
||||||
* @param filters <p>The filters applicable to this preset</p>
|
* @param filters <p>The filters applicable to this preset</p>
|
||||||
*/
|
*/
|
||||||
SmithPreset(SmithPresetFilter[] filters) {
|
SmithPreset(@NotNull SmithPresetFilter[] filters) {
|
||||||
this.filters = filters;
|
this.filters = filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +66,7 @@ public enum SmithPreset {
|
|||||||
* @param filter <p>The filter to check</p>
|
* @param filter <p>The filter to check</p>
|
||||||
* @return <p>True if the filter is supported</p>
|
* @return <p>True if the filter is supported</p>
|
||||||
*/
|
*/
|
||||||
public boolean supportsFilter(SmithPresetFilter filter) {
|
public boolean supportsFilter(@NotNull SmithPresetFilter filter) {
|
||||||
return List.of(filters).contains(filter);
|
return List.of(filters).contains(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +75,7 @@ public enum SmithPreset {
|
|||||||
*
|
*
|
||||||
* @return <p>The filters supported by this preset</p>
|
* @return <p>The filters supported by this preset</p>
|
||||||
*/
|
*/
|
||||||
|
@NotNull
|
||||||
public List<SmithPresetFilter> getSupportedFilters() {
|
public List<SmithPresetFilter> getSupportedFilters() {
|
||||||
return List.of(filters);
|
return List.of(filters);
|
||||||
}
|
}
|
||||||
@ -66,6 +85,7 @@ public enum SmithPreset {
|
|||||||
*
|
*
|
||||||
* @return <p>All available smith presets</p>
|
* @return <p>All available smith presets</p>
|
||||||
*/
|
*/
|
||||||
|
@NotNull
|
||||||
public static List<String> getPresetNames() {
|
public static List<String> getPresetNames() {
|
||||||
List<String> presetNames = new ArrayList<>();
|
List<String> presetNames = new ArrayList<>();
|
||||||
for (SmithPreset preset : SmithPreset.values()) {
|
for (SmithPreset preset : SmithPreset.values()) {
|
||||||
@ -80,12 +100,25 @@ public enum SmithPreset {
|
|||||||
* @param possiblePreset <p>The string that might be a preset</p>
|
* @param possiblePreset <p>The string that might be a preset</p>
|
||||||
* @return <p>The string, possibly with the preset replaced</p>
|
* @return <p>The string, possibly with the preset replaced</p>
|
||||||
*/
|
*/
|
||||||
public static String replacePreset(String possiblePreset) {
|
@NotNull
|
||||||
|
public static String replacePreset(@NotNull String possiblePreset) {
|
||||||
|
boolean negated = false;
|
||||||
|
|
||||||
String upperCasedPreset = possiblePreset.replace('-', '_').toUpperCase();
|
String upperCasedPreset = possiblePreset.replace('-', '_').toUpperCase();
|
||||||
if (!upperCasedPreset.startsWith("PRESET:")) {
|
if (possiblePreset.startsWith("-")) {
|
||||||
|
negated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((negated && !upperCasedPreset.startsWith("_PRESET:")) ||
|
||||||
|
(!negated && !upperCasedPreset.startsWith("PRESET:"))) {
|
||||||
return possiblePreset;
|
return possiblePreset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Strip the "-" here to prevent stripping for material names
|
||||||
|
if (negated) {
|
||||||
|
upperCasedPreset = upperCasedPreset.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
//Parse the input
|
//Parse the input
|
||||||
SmithPresetFilter filter = null;
|
SmithPresetFilter filter = null;
|
||||||
SmithPreset preset;
|
SmithPreset preset;
|
||||||
@ -99,17 +132,38 @@ public enum SmithPreset {
|
|||||||
} catch (IllegalArgumentException exception) {
|
} catch (IllegalArgumentException exception) {
|
||||||
/* This case means that either the preset or the filter given is invalid, and thus the preset string should
|
/* This case means that either the preset or the filter given is invalid, and thus the preset string should
|
||||||
be ignored to prevent any problems. */
|
be ignored to prevent any problems. */
|
||||||
BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING, String.format("The smith preset %s is " +
|
BlacksmithPlugin.warn(String.format("The smith preset %s is invalid, and will be ignored. Please fix it!",
|
||||||
"invalid, and will be ignored. Please fix it!", possiblePreset));
|
possiblePreset));
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
//Return the list of materials included in the preset
|
// Check if the preset result has been stored
|
||||||
if (filter != null) {
|
Set<String> materialNames = null;
|
||||||
return String.join(",", preset.getMaterialNames(filter));
|
if (filter == null) {
|
||||||
} else {
|
if (presetMaterialNames.containsKey(preset)) {
|
||||||
return String.join(",", preset.getMaterialNames());
|
materialNames = presetMaterialNames.get(preset);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (filterMaterialNames.containsKey(preset) && filterMaterialNames.get(preset).containsKey(filter)) {
|
||||||
|
materialNames = filterMaterialNames.get(preset).get(filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Return the list of materials included in the preset
|
||||||
|
if (materialNames == null) {
|
||||||
|
if (filter != null) {
|
||||||
|
materialNames = preset.getMaterialNames(filter);
|
||||||
|
filterMaterialNames.putIfAbsent(preset, new HashMap<>());
|
||||||
|
filterMaterialNames.get(preset).put(filter, materialNames);
|
||||||
|
} else {
|
||||||
|
materialNames = preset.getMaterialNames();
|
||||||
|
presetMaterialNames.put(preset, materialNames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (negated) {
|
||||||
|
materialNames = negateMaterials(materialNames);
|
||||||
|
}
|
||||||
|
return String.join(",", materialNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,8 +172,9 @@ public enum SmithPreset {
|
|||||||
* @param filter <p>The filter to use for filtering</p>
|
* @param filter <p>The filter to use for filtering</p>
|
||||||
* @return <p>The materials included in this preset, filtered using the given filter</p>
|
* @return <p>The materials included in this preset, filtered using the given filter</p>
|
||||||
*/
|
*/
|
||||||
public List<Material> getFilteredMaterials(SmithPresetFilter filter) {
|
@NotNull
|
||||||
List<Material> materials = new ArrayList<>(this.getMaterials());
|
public Set<Material> getFilteredMaterials(SmithPresetFilter filter) {
|
||||||
|
Set<Material> materials = new HashSet<>(this.getMaterials());
|
||||||
materials.removeIf((item) -> !filter.isIncluded(item));
|
materials.removeIf((item) -> !filter.isIncluded(item));
|
||||||
return materials;
|
return materials;
|
||||||
}
|
}
|
||||||
@ -129,8 +184,10 @@ public enum SmithPreset {
|
|||||||
*
|
*
|
||||||
* @return <p>All materials in this preset</p>
|
* @return <p>All materials in this preset</p>
|
||||||
*/
|
*/
|
||||||
public List<Material> getMaterials() {
|
@NotNull
|
||||||
|
public Set<Material> getMaterials() {
|
||||||
return switch (this) {
|
return switch (this) {
|
||||||
|
case BLACKSMITH -> ItemHelper.getAllReforgeAbleMaterials();
|
||||||
case WEAPON_SMITH -> getWeapons();
|
case WEAPON_SMITH -> getWeapons();
|
||||||
case ARMOR_SMITH -> getArmor();
|
case ARMOR_SMITH -> getArmor();
|
||||||
case TOOL_SMITH -> getTools();
|
case TOOL_SMITH -> getTools();
|
||||||
@ -142,11 +199,14 @@ public enum SmithPreset {
|
|||||||
*
|
*
|
||||||
* @return <p>All ranged weapon materials</p>
|
* @return <p>All ranged weapon materials</p>
|
||||||
*/
|
*/
|
||||||
private List<Material> getRanged() {
|
@NotNull
|
||||||
List<Material> ranged = new ArrayList<>();
|
private Set<Material> getRanged() {
|
||||||
|
if (ranged == null) {
|
||||||
|
ranged = new HashSet<>();
|
||||||
ranged.add(Material.TRIDENT);
|
ranged.add(Material.TRIDENT);
|
||||||
ranged.add(Material.BOW);
|
ranged.add(Material.BOW);
|
||||||
ranged.add(Material.CROSSBOW);
|
ranged.add(Material.CROSSBOW);
|
||||||
|
}
|
||||||
return ranged;
|
return ranged;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,15 +215,18 @@ public enum SmithPreset {
|
|||||||
*
|
*
|
||||||
* @return <p>All tool materials</p>
|
* @return <p>All tool materials</p>
|
||||||
*/
|
*/
|
||||||
private List<Material> getTools() {
|
@NotNull
|
||||||
List<Material> tools = new ArrayList<>();
|
private Set<Material> getTools() {
|
||||||
tools.addAll(getMaterialsEndingWith("_HOE"));
|
if (tools == null) {
|
||||||
tools.addAll(getMaterialsEndingWith("_SHOVEL"));
|
tools = new HashSet<>();
|
||||||
tools.addAll(getMaterialsEndingWith("_AXE"));
|
tools.addAll(Tag.ITEMS_HOES.getValues());
|
||||||
tools.addAll(getMaterialsEndingWith("_PICKAXE"));
|
tools.addAll(Tag.ITEMS_SHOVELS.getValues());
|
||||||
|
tools.addAll(Tag.ITEMS_AXES.getValues());
|
||||||
|
tools.addAll(Tag.ITEMS_PICKAXES.getValues());
|
||||||
tools.add(Material.FLINT_AND_STEEL);
|
tools.add(Material.FLINT_AND_STEEL);
|
||||||
tools.add(Material.FISHING_ROD);
|
tools.add(Material.FISHING_ROD);
|
||||||
tools.add(Material.SHEARS);
|
tools.add(Material.SHEARS);
|
||||||
|
}
|
||||||
return tools;
|
return tools;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,10 +235,13 @@ public enum SmithPreset {
|
|||||||
*
|
*
|
||||||
* @return <p>All weapon materials</p>
|
* @return <p>All weapon materials</p>
|
||||||
*/
|
*/
|
||||||
private List<Material> getWeapons() {
|
@NotNull
|
||||||
List<Material> weapons = new ArrayList<>(getSwords());
|
private Set<Material> getWeapons() {
|
||||||
|
if (weapons == null) {
|
||||||
|
weapons = new HashSet<>(getSwords());
|
||||||
weapons.addAll(getRanged());
|
weapons.addAll(getRanged());
|
||||||
weapons.add(Material.SHIELD);
|
weapons.add(Material.SHIELD);
|
||||||
|
}
|
||||||
return weapons;
|
return weapons;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,17 +250,26 @@ public enum SmithPreset {
|
|||||||
*
|
*
|
||||||
* @return <p>All sword materials</p>
|
* @return <p>All sword materials</p>
|
||||||
*/
|
*/
|
||||||
private List<Material> getSwords() {
|
@NotNull
|
||||||
return getMaterialsEndingWith("_SWORD");
|
private Set<Material> getSwords() {
|
||||||
|
return Tag.ITEMS_SWORDS.getValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Material> getArmor() {
|
/**
|
||||||
List<Material> armor = new ArrayList<>();
|
* Gets all types of armor
|
||||||
|
*
|
||||||
|
* @return <p>All armor types</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private Set<Material> getArmor() {
|
||||||
|
if (armor == null) {
|
||||||
|
armor = new HashSet<>();
|
||||||
armor.addAll(getMaterialsEndingWith("HELMET"));
|
armor.addAll(getMaterialsEndingWith("HELMET"));
|
||||||
armor.addAll(getMaterialsEndingWith("CHESTPLATE"));
|
armor.addAll(getMaterialsEndingWith("CHESTPLATE"));
|
||||||
armor.addAll(getMaterialsEndingWith("LEGGINGS"));
|
armor.addAll(getMaterialsEndingWith("LEGGINGS"));
|
||||||
armor.addAll(getMaterialsEndingWith("BOOTS"));
|
armor.addAll(getMaterialsEndingWith("BOOTS"));
|
||||||
armor.add(Material.ELYTRA);
|
armor.add(Material.ELYTRA);
|
||||||
|
}
|
||||||
return armor;
|
return armor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,22 +279,24 @@ public enum SmithPreset {
|
|||||||
* @param end <p>The string to look for</p>
|
* @param end <p>The string to look for</p>
|
||||||
* @return <p>The resulting materials</p>
|
* @return <p>The resulting materials</p>
|
||||||
*/
|
*/
|
||||||
private List<Material> getMaterialsEndingWith(String end) {
|
@NotNull
|
||||||
List<Material> swords = new ArrayList<>();
|
private Set<Material> getMaterialsEndingWith(@NotNull String end) {
|
||||||
for (Material material : Material.values()) {
|
Set<Material> matchedMaterials = new HashSet<>();
|
||||||
|
for (Material material : ItemHelper.getAllReforgeAbleMaterials()) {
|
||||||
if (!material.name().startsWith("LEGACY") && material.name().endsWith(end)) {
|
if (!material.name().startsWith("LEGACY") && material.name().endsWith(end)) {
|
||||||
swords.add(material);
|
matchedMaterials.add(material);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return swords;
|
return matchedMaterials;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets material names of all materials reforge-able by this smith
|
* Gets material names of all materials reforge-able by this smith preset
|
||||||
*
|
*
|
||||||
* @return <p>All material names for this smith</p>
|
* @return <p>All material names for this smith preset</p>
|
||||||
*/
|
*/
|
||||||
private List<String> getMaterialNames() {
|
@NotNull
|
||||||
|
private Set<String> getMaterialNames() {
|
||||||
return getNames(this.getMaterials());
|
return getNames(this.getMaterials());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +306,8 @@ public enum SmithPreset {
|
|||||||
* @param filter <p>The filter used for filtering materials</p>
|
* @param filter <p>The filter used for filtering materials</p>
|
||||||
* @return <p>All material names for this smith</p>
|
* @return <p>All material names for this smith</p>
|
||||||
*/
|
*/
|
||||||
private List<String> getMaterialNames(SmithPresetFilter filter) {
|
@NotNull
|
||||||
|
private Set<String> getMaterialNames(@NotNull SmithPresetFilter filter) {
|
||||||
return getNames(this.getFilteredMaterials(filter));
|
return getNames(this.getFilteredMaterials(filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,12 +317,30 @@ public enum SmithPreset {
|
|||||||
* @param materials <p>The materials to get the names of</p>
|
* @param materials <p>The materials to get the names of</p>
|
||||||
* @return <p>The names of the materials</p>
|
* @return <p>The names of the materials</p>
|
||||||
*/
|
*/
|
||||||
private List<String> getNames(List<Material> materials) {
|
@NotNull
|
||||||
List<String> items = new ArrayList<>();
|
private Set<String> getNames(@NotNull Set<Material> materials) {
|
||||||
|
Set<String> items = new HashSet<>();
|
||||||
for (Material material : materials) {
|
for (Material material : materials) {
|
||||||
items.add(material.name().toLowerCase().replace("_", "-"));
|
items.add(material.name().toLowerCase().replace("_", "-"));
|
||||||
}
|
}
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Negates the given material names
|
||||||
|
*
|
||||||
|
* @param materials <p>The material names to negate</p>
|
||||||
|
* @return <p>The negated material names</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private static Set<String> negateMaterials(@NotNull Set<String> materials) {
|
||||||
|
Set<String> negatedMaterials = new HashSet<>(materials.size());
|
||||||
|
materials.forEach((material) -> {
|
||||||
|
if (material != null && !material.isBlank()) {
|
||||||
|
negatedMaterials.add("-" + material);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return negatedMaterials;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ public enum SmithPresetFilter {
|
|||||||
HELMET(false, "_HELMET"),
|
HELMET(false, "_HELMET"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filters to only include chestplates
|
* Filters to only include chest-plates
|
||||||
*/
|
*/
|
||||||
CHESTPLATE(false, "_CHESTPLATE"),
|
CHESTPLATE(false, "_CHESTPLATE"),
|
||||||
|
|
||||||
|
@ -0,0 +1,246 @@
|
|||||||
|
package net.knarcraft.blacksmith.config;
|
||||||
|
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.configuration.InvalidConfigurationException;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A YAML configuration which retains all comments
|
||||||
|
*
|
||||||
|
* <p>This configuration converts all comments to YAML values when loaded, which all start with comment_. When saved,
|
||||||
|
* those YAML values are converted to normal text comments. This ensures that the comments aren't removed by the
|
||||||
|
* YamlConfiguration during its parsing.</p>
|
||||||
|
*
|
||||||
|
* <p>Note: When retrieving a configuration section, that will include comments that start with "comment_". You should
|
||||||
|
* filter those before parsing input.</p>
|
||||||
|
*
|
||||||
|
* @author Kristian Knarvik
|
||||||
|
* @author Thorin
|
||||||
|
*/
|
||||||
|
public class StargateYamlConfiguration extends YamlConfiguration {
|
||||||
|
|
||||||
|
private static final String START_OF_COMMENT_LINE = "[HASHTAG]";
|
||||||
|
private static final String END_OF_COMMENT = "_endOfComment_";
|
||||||
|
private static final String START_OF_COMMENT = "comment_";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
protected String buildHeader() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public String saveToString() {
|
||||||
|
// Convert YAML comments to normal comments
|
||||||
|
return this.convertYAMLMappingsToComments(super.saveToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadFromString(@NotNull String contents) throws InvalidConfigurationException {
|
||||||
|
// Convert normal comments to YAML comments to prevent them from disappearing
|
||||||
|
super.loadFromString(this.convertCommentsToYAMLMappings(contents));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a configuration section's keys, without any comment entries
|
||||||
|
*
|
||||||
|
* @param configurationSection <p>The configuration section to get keys for</p>
|
||||||
|
* @param deep <p>Whether to get keys for child elements as well</p>
|
||||||
|
* @return <p>The configuration section's keys, with comment entries removed</p>
|
||||||
|
*/
|
||||||
|
public static Set<String> getKeysWithoutComments(@NotNull ConfigurationSection configurationSection, boolean deep) {
|
||||||
|
Set<String> keys = new HashSet<>(configurationSection.getKeys(deep));
|
||||||
|
keys.removeIf(key -> key.matches(START_OF_COMMENT + "[0-9]+"));
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a file with comments, and recreates them into yaml mappings
|
||||||
|
*
|
||||||
|
* <p>A mapping follows this format: comment_{CommentNumber}: "The comment"
|
||||||
|
* This needs to be done as comments otherwise get removed using
|
||||||
|
* the {@link FileConfiguration#save(File)} method. The config
|
||||||
|
* needs to be saved if a config value has changed.</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private String convertCommentsToYAMLMappings(@NotNull String configString) {
|
||||||
|
StringBuilder yamlBuilder = new StringBuilder();
|
||||||
|
List<String> currentComment = new ArrayList<>();
|
||||||
|
int commentId = 0;
|
||||||
|
int previousIndentation = 0;
|
||||||
|
|
||||||
|
for (String line : configString.split("\n")) {
|
||||||
|
String trimmed = line.trim();
|
||||||
|
if (trimmed.startsWith("#")) {
|
||||||
|
// Store the indentation of the block
|
||||||
|
if (currentComment.isEmpty()) {
|
||||||
|
previousIndentation = getIndentation(line);
|
||||||
|
}
|
||||||
|
//Temporarily store the comment line
|
||||||
|
addComment(currentComment, trimmed);
|
||||||
|
} else {
|
||||||
|
addYamlString(yamlBuilder, currentComment, line, previousIndentation, commentId);
|
||||||
|
commentId++;
|
||||||
|
previousIndentation = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return yamlBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a YAML string to the given string builder
|
||||||
|
*
|
||||||
|
* @param yamlBuilder <p>The string builder used for building YAML</p>
|
||||||
|
* @param currentComment <p>The comment to add as a YAML string</p>
|
||||||
|
* @param line <p>The current line</p>
|
||||||
|
* @param previousIndentation <p>The indentation of the current block comment</p>
|
||||||
|
* @param commentId <p>The id of the comment</p>
|
||||||
|
*/
|
||||||
|
private void addYamlString(@NotNull StringBuilder yamlBuilder, @NotNull List<String> currentComment,
|
||||||
|
@NotNull String line, int previousIndentation, int commentId) {
|
||||||
|
String trimmed = line.trim();
|
||||||
|
//Write the full formatted comment to the StringBuilder
|
||||||
|
if (!currentComment.isEmpty()) {
|
||||||
|
int indentation = trimmed.isEmpty() ? previousIndentation : getIndentation(line);
|
||||||
|
generateCommentYAML(yamlBuilder, currentComment, commentId, indentation);
|
||||||
|
currentComment.clear();
|
||||||
|
}
|
||||||
|
//Add the non-comment line assuming it isn't empty
|
||||||
|
if (!trimmed.isEmpty()) {
|
||||||
|
yamlBuilder.append(line).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given comment to the given list
|
||||||
|
*
|
||||||
|
* @param commentParts <p>The list to add to</p>
|
||||||
|
* @param comment <p>The comment to add</p>
|
||||||
|
*/
|
||||||
|
private void addComment(@NotNull List<String> commentParts, @NotNull String comment) {
|
||||||
|
if (comment.startsWith("# ")) {
|
||||||
|
commentParts.add(comment.replaceFirst("# ", START_OF_COMMENT_LINE));
|
||||||
|
} else {
|
||||||
|
commentParts.add(comment.replaceFirst("#", START_OF_COMMENT_LINE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a YAML-compatible string for one comment block
|
||||||
|
*
|
||||||
|
* @param yamlBuilder <p>The string builder to add the generated YAML to</p>
|
||||||
|
* @param commentLines <p>The lines of the comment to convert into YAML</p>
|
||||||
|
* @param commentId <p>The unique id of the comment</p>
|
||||||
|
* @param indentation <p>The indentation to add to every line</p>
|
||||||
|
*/
|
||||||
|
private void generateCommentYAML(@NotNull StringBuilder yamlBuilder, @NotNull List<String> commentLines,
|
||||||
|
int commentId, int indentation) {
|
||||||
|
String subIndentation = this.addIndentation(indentation + 2);
|
||||||
|
//Add the comment start marker
|
||||||
|
yamlBuilder.append(this.addIndentation(indentation)).append(START_OF_COMMENT).append(commentId).append(": |\n");
|
||||||
|
for (String commentLine : commentLines) {
|
||||||
|
//Add each comment line with the proper indentation
|
||||||
|
yamlBuilder.append(subIndentation).append(commentLine).append("\n");
|
||||||
|
}
|
||||||
|
//Add the comment end marker
|
||||||
|
yamlBuilder.append(subIndentation).append(subIndentation).append(END_OF_COMMENT).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the internal YAML mapping format to a readable config file
|
||||||
|
*
|
||||||
|
* <p>The internal YAML structure is converted to a string with the same format as a standard configuration file.
|
||||||
|
* The internal structure has comments in the format: START_OF_COMMENT + id + multi-line YAML string +
|
||||||
|
* END_OF_COMMENT.</p>
|
||||||
|
*
|
||||||
|
* @param yamlString <p>A string using the YAML format</p>
|
||||||
|
* @return <p>The corresponding comment string</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private String convertYAMLMappingsToComments(@NotNull String yamlString) {
|
||||||
|
StringBuilder finalText = new StringBuilder();
|
||||||
|
|
||||||
|
String[] lines = yamlString.split("\n");
|
||||||
|
for (int currentIndex = 0; currentIndex < lines.length; currentIndex++) {
|
||||||
|
String line = lines[currentIndex];
|
||||||
|
String possibleComment = line.trim();
|
||||||
|
|
||||||
|
if (possibleComment.startsWith(START_OF_COMMENT)) {
|
||||||
|
//Add an empty line before every comment block
|
||||||
|
finalText.append("\n");
|
||||||
|
currentIndex = readComment(finalText, lines, currentIndex + 1, getIndentation(line));
|
||||||
|
} else {
|
||||||
|
//Output the configuration key
|
||||||
|
finalText.append(line).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalText.toString().trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fully reads a comment
|
||||||
|
*
|
||||||
|
* @param builder <p>The string builder to write to</p>
|
||||||
|
* @param lines <p>The lines to read from</p>
|
||||||
|
* @param startIndex <p>The index to start reading from</p>
|
||||||
|
* @param commentIndentation <p>The indentation of the read comment</p>
|
||||||
|
* @return <p>The index containing the next non-comment line</p>
|
||||||
|
*/
|
||||||
|
private int readComment(@NotNull StringBuilder builder, @NotNull String[] lines, int startIndex,
|
||||||
|
int commentIndentation) {
|
||||||
|
for (int currentIndex = startIndex; currentIndex < lines.length; currentIndex++) {
|
||||||
|
String line = lines[currentIndex];
|
||||||
|
String possibleComment = line.trim();
|
||||||
|
if (!line.contains(END_OF_COMMENT)) {
|
||||||
|
possibleComment = possibleComment.replace(START_OF_COMMENT_LINE, "");
|
||||||
|
builder.append(addIndentation(commentIndentation)).append("# ").append(possibleComment).append("\n");
|
||||||
|
} else {
|
||||||
|
return currentIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return startIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string containing the given indentation
|
||||||
|
*
|
||||||
|
* @param indentationSpaces <p>The number spaces to use for indentation</p>
|
||||||
|
* @return <p>A string containing the number of spaces specified</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private String addIndentation(int indentationSpaces) {
|
||||||
|
return " ".repeat(Math.max(0, indentationSpaces));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the indentation (number of spaces) of the given line
|
||||||
|
*
|
||||||
|
* @param line <p>The line to get indentation of</p>
|
||||||
|
* @return <p>The number of spaces in the line's indentation</p>
|
||||||
|
*/
|
||||||
|
private int getIndentation(@NotNull String line) {
|
||||||
|
int spacesFound = 0;
|
||||||
|
for (char aCharacter : line.toCharArray()) {
|
||||||
|
if (aCharacter == ' ') {
|
||||||
|
spacesFound++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return spacesFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package net.knarcraft.blacksmith.config;
|
||||||
|
|
||||||
|
public interface TraitSettings<K extends Setting> extends Settings<K> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether to disable the action cool-down
|
||||||
|
*
|
||||||
|
* @return <p>Whether to disable the action cool-down</p>
|
||||||
|
*/
|
||||||
|
boolean getDisableCoolDown();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when a blacksmith or scrapper is still affected by a cool-down
|
||||||
|
*
|
||||||
|
* @return <p>The cool down unexpired message</p>
|
||||||
|
*/
|
||||||
|
String getCoolDownUnexpiredMessage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when the blacksmith is busy with another player
|
||||||
|
*
|
||||||
|
* @return <p>The busy with player message</p>
|
||||||
|
*/
|
||||||
|
String getBusyWithPlayerMessage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when the blacksmith is busy with reforging or salvaging an item
|
||||||
|
*
|
||||||
|
* @return <p>The busy working message</p>
|
||||||
|
*/
|
||||||
|
String getBusyWorkingMessage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when a blacksmith starts reforging or salvaging an item
|
||||||
|
*
|
||||||
|
* @return <p>The start working message</p>
|
||||||
|
*/
|
||||||
|
String getStartWorkingMessage();
|
||||||
|
|
||||||
|
}
|
@ -1,35 +1,37 @@
|
|||||||
package net.knarcraft.blacksmith.config;
|
package net.knarcraft.blacksmith.config.blacksmith;
|
||||||
|
|
||||||
import net.citizensnpcs.api.util.DataKey;
|
import net.citizensnpcs.api.util.DataKey;
|
||||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
import net.knarcraft.blacksmith.trait.BlacksmithTrait;
|
import net.knarcraft.blacksmith.config.SettingValueType;
|
||||||
|
import net.knarcraft.blacksmith.config.TraitSettings;
|
||||||
import net.knarcraft.blacksmith.util.ConfigHelper;
|
import net.knarcraft.blacksmith.util.ConfigHelper;
|
||||||
import net.knarcraft.blacksmith.util.InputParsingHelper;
|
import net.knarcraft.blacksmith.util.InputParsingHelper;
|
||||||
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class which keeps track of all Blacksmith settings/config values for one NPC
|
* A class which keeps track of all Blacksmith settings/config values for one NPC
|
||||||
*/
|
*/
|
||||||
public class NPCSettings {
|
public class BlacksmithNPCSettings implements TraitSettings<BlacksmithSetting> {
|
||||||
|
|
||||||
private final List<Material> reforgeAbleItems = new ArrayList<>();
|
private final List<Material> reforgeAbleItems = new ArrayList<>();
|
||||||
private final List<Enchantment> enchantmentBlocklist = new ArrayList<>();
|
private final List<Enchantment> enchantmentBlockList = new ArrayList<>();
|
||||||
private final Map<NPCSetting, Object> currentValues = new HashMap<>();
|
private final Map<BlacksmithSetting, Object> currentValues = new HashMap<>();
|
||||||
private final GlobalSettings globalSettings;
|
private final GlobalBlacksmithSettings globalBlacksmithSettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new "Settings" object
|
* Instantiates a new "Settings" object
|
||||||
*/
|
*/
|
||||||
public NPCSettings(GlobalSettings globalSettings) {
|
public BlacksmithNPCSettings(GlobalBlacksmithSettings globalBlacksmithSettings) {
|
||||||
this.globalSettings = globalSettings;
|
this.globalBlacksmithSettings = globalBlacksmithSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,14 +40,14 @@ public class NPCSettings {
|
|||||||
* @param key <p>The data key to load variables from</p>
|
* @param key <p>The data key to load variables from</p>
|
||||||
*/
|
*/
|
||||||
public void loadVariables(DataKey key) {
|
public void loadVariables(DataKey key) {
|
||||||
for (NPCSetting setting : NPCSetting.values()) {
|
for (BlacksmithSetting setting : BlacksmithSetting.values()) {
|
||||||
if (key.keyExists(setting.getChildPath())) {
|
if (key.keyExists(setting.getChildPath())) {
|
||||||
currentValues.put(setting, key.getRaw(setting.getChildPath()));
|
currentValues.put(setting, key.getRaw(setting.getChildPath()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Updates the list of reforge-able items/materials
|
//Updates the list of reforge-able items/materials
|
||||||
updateReforgeAbleItems();
|
updateReforgeAbleItems();
|
||||||
updateEnchantmentBlocklist();
|
updateEnchantmentBlockList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,29 +56,25 @@ public class NPCSettings {
|
|||||||
* @param key <p>The data key to save variables to</p>
|
* @param key <p>The data key to save variables to</p>
|
||||||
*/
|
*/
|
||||||
public void saveVariables(DataKey key) {
|
public void saveVariables(DataKey key) {
|
||||||
for (NPCSetting setting : NPCSetting.values()) {
|
for (BlacksmithSetting setting : BlacksmithSetting.values()) {
|
||||||
key.setRaw(setting.getChildPath(), currentValues.get(setting));
|
key.setRaw(setting.getChildPath(), currentValues.get(setting));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Changes one setting to the given value
|
public void changeValue(@NotNull BlacksmithSetting setting, @Nullable Object newValue) {
|
||||||
*
|
if (setting.getValueType() == SettingValueType.ENCHANTMENT_LIST ||
|
||||||
* @param setting <p>The setting to change</p>
|
setting.getValueType() == SettingValueType.REFORGE_ABLE_ITEMS) {
|
||||||
* @param newValue <p>The new value of the setting</p>
|
|
||||||
*/
|
|
||||||
public void changeSetting(NPCSetting setting, Object newValue) {
|
|
||||||
if (setting.getValueType() == SettingValueType.STRING_LIST) {
|
|
||||||
//Workaround to make sure it's treated as the correct type
|
//Workaround to make sure it's treated as the correct type
|
||||||
currentValues.put(setting, ConfigHelper.asStringList(newValue));
|
currentValues.put(setting, newValue == null ? null : ConfigHelper.asStringList(newValue));
|
||||||
} else {
|
} else {
|
||||||
currentValues.put(setting, newValue);
|
currentValues.put(setting, newValue);
|
||||||
}
|
}
|
||||||
if (setting == NPCSetting.REFORGE_ABLE_ITEMS) {
|
if (setting == BlacksmithSetting.REFORGE_ABLE_ITEMS) {
|
||||||
updateReforgeAbleItems();
|
updateReforgeAbleItems();
|
||||||
}
|
}
|
||||||
if (setting == NPCSetting.ENCHANTMENT_BLOCKLIST) {
|
if (setting == BlacksmithSetting.ENCHANTMENT_BLOCK_LIST) {
|
||||||
updateEnchantmentBlocklist();
|
updateEnchantmentBlockList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,17 +84,13 @@ public class NPCSettings {
|
|||||||
* @param setting <p>The setting to get the value of</p>
|
* @param setting <p>The setting to get the value of</p>
|
||||||
* @return <p>The current value of the setting</p>
|
* @return <p>The current value of the setting</p>
|
||||||
*/
|
*/
|
||||||
public Object getRawValue(NPCSetting setting) {
|
public @NotNull Object getRawValue(@NotNull BlacksmithSetting setting) {
|
||||||
return currentValues.get(setting);
|
return currentValues.get(setting);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Gets the message to display when the blacksmith is busy with another player
|
|
||||||
*
|
|
||||||
* @return <p>The busy with player message</p>
|
|
||||||
*/
|
|
||||||
public String getBusyWithPlayerMessage() {
|
public String getBusyWithPlayerMessage() {
|
||||||
return asString(NPCSetting.BUSY_WITH_PLAYER_MESSAGE);
|
return asString(BlacksmithSetting.BUSY_WITH_PLAYER_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -104,8 +98,8 @@ public class NPCSettings {
|
|||||||
*
|
*
|
||||||
* @return <p>The busy reforging message</p>
|
* @return <p>The busy reforging message</p>
|
||||||
*/
|
*/
|
||||||
public String getBusyReforgingMessage() {
|
public String getBusyWorkingMessage() {
|
||||||
return asString(NPCSetting.BUSY_WITH_REFORGE_MESSAGE);
|
return asString(BlacksmithSetting.BUSY_WITH_REFORGE_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,7 +108,7 @@ public class NPCSettings {
|
|||||||
* @return <p>The message to use for displaying item cost</p>
|
* @return <p>The message to use for displaying item cost</p>
|
||||||
*/
|
*/
|
||||||
public String getCostMessage() {
|
public String getCostMessage() {
|
||||||
return asString(NPCSetting.COST_MESSAGE);
|
return asString(BlacksmithSetting.COST_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,7 +117,7 @@ public class NPCSettings {
|
|||||||
* @return <p>The invalid item message</p>
|
* @return <p>The invalid item message</p>
|
||||||
*/
|
*/
|
||||||
public String getInvalidItemMessage() {
|
public String getInvalidItemMessage() {
|
||||||
return asString(NPCSetting.INVALID_ITEM_MESSAGE);
|
return asString(BlacksmithSetting.INVALID_ITEM_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -132,16 +126,12 @@ public class NPCSettings {
|
|||||||
* @return <p>The not damaged message</p>
|
* @return <p>The not damaged message</p>
|
||||||
*/
|
*/
|
||||||
public String getNotDamagedMessage() {
|
public String getNotDamagedMessage() {
|
||||||
return asString(NPCSetting.NOT_DAMAGED_MESSAGE);
|
return asString(BlacksmithSetting.NOT_DAMAGED_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Gets the message to display when a blacksmith starts reforging an item
|
public String getStartWorkingMessage() {
|
||||||
*
|
return asString(BlacksmithSetting.START_REFORGE_MESSAGE);
|
||||||
* @return <p>The start reforge message</p>
|
|
||||||
*/
|
|
||||||
public String getStartReforgeMessage() {
|
|
||||||
return asString(NPCSetting.START_REFORGE_MESSAGE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -150,7 +140,7 @@ public class NPCSettings {
|
|||||||
* @return <p>The reforge success message</p>
|
* @return <p>The reforge success message</p>
|
||||||
*/
|
*/
|
||||||
public String getSuccessMessage() {
|
public String getSuccessMessage() {
|
||||||
return asString(NPCSetting.SUCCESS_MESSAGE);
|
return asString(BlacksmithSetting.SUCCESS_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -159,7 +149,7 @@ public class NPCSettings {
|
|||||||
* @return <p>The reforge fail message</p>
|
* @return <p>The reforge fail message</p>
|
||||||
*/
|
*/
|
||||||
public String getFailMessage() {
|
public String getFailMessage() {
|
||||||
return asString(NPCSetting.FAIL_MESSAGE);
|
return asString(BlacksmithSetting.FAIL_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -168,16 +158,12 @@ public class NPCSettings {
|
|||||||
* @return <p>The insufficient funds message</p>
|
* @return <p>The insufficient funds message</p>
|
||||||
*/
|
*/
|
||||||
public String getInsufficientFundsMessage() {
|
public String getInsufficientFundsMessage() {
|
||||||
return asString(NPCSetting.INSUFFICIENT_FUNDS_MESSAGE);
|
return asString(BlacksmithSetting.INSUFFICIENT_FUNDS_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Gets the message to display when a blacksmith is still affected by a cool-down
|
|
||||||
*
|
|
||||||
* @return <p>The cool down unexpired message</p>
|
|
||||||
*/
|
|
||||||
public String getCoolDownUnexpiredMessage() {
|
public String getCoolDownUnexpiredMessage() {
|
||||||
return asString(NPCSetting.COOL_DOWN_UNEXPIRED_MESSAGE);
|
return asString(BlacksmithSetting.COOL_DOWN_UNEXPIRED_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -186,7 +172,17 @@ public class NPCSettings {
|
|||||||
* @return <p>The item changed message</p>
|
* @return <p>The item changed message</p>
|
||||||
*/
|
*/
|
||||||
public String getItemChangedMessage() {
|
public String getItemChangedMessage() {
|
||||||
return asString(NPCSetting.ITEM_UNEXPECTEDLY_CHANGED_MESSAGE);
|
return asString(BlacksmithSetting.ITEM_UNEXPECTEDLY_CHANGED_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message displayed if a player presents the blacksmith with an empty hand
|
||||||
|
*
|
||||||
|
* @return <p>The no item message</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getNoItemMessage() {
|
||||||
|
return asString(BlacksmithSetting.NO_ITEM_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -197,16 +193,26 @@ public class NPCSettings {
|
|||||||
* @return <p>All items reforge-able by this NPC</p>
|
* @return <p>All items reforge-able by this NPC</p>
|
||||||
*/
|
*/
|
||||||
public List<Material> getReforgeAbleItems() {
|
public List<Material> getReforgeAbleItems() {
|
||||||
|
Object currentValue = currentValues.get(BlacksmithSetting.REFORGE_ABLE_ITEMS);
|
||||||
|
if (currentValue == null || String.valueOf(currentValue).isEmpty()) {
|
||||||
|
return globalBlacksmithSettings.getReforgeAbleItems();
|
||||||
|
} else {
|
||||||
return new ArrayList<>(this.reforgeAbleItems);
|
return new ArrayList<>(this.reforgeAbleItems);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the list of blocked enchantments
|
* Gets the list of blocked enchantments
|
||||||
*
|
*
|
||||||
* @return <p>The list of blocked enchantments</p>
|
* @return <p>The list of blocked enchantments</p>
|
||||||
*/
|
*/
|
||||||
public List<Enchantment> getEnchantmentBlocklist() {
|
public List<Enchantment> getEnchantmentBlockList() {
|
||||||
return new ArrayList<>(this.enchantmentBlocklist);
|
Object currentValue = currentValues.get(BlacksmithSetting.ENCHANTMENT_BLOCK_LIST);
|
||||||
|
if (currentValue == null || String.valueOf(currentValue).isEmpty()) {
|
||||||
|
return globalBlacksmithSettings.getEnchantmentBlockList();
|
||||||
|
} else {
|
||||||
|
return new ArrayList<>(this.enchantmentBlockList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -215,7 +221,7 @@ public class NPCSettings {
|
|||||||
* @return <p>The minimum reforge delay</p>
|
* @return <p>The minimum reforge delay</p>
|
||||||
*/
|
*/
|
||||||
public int getMinReforgeDelay() {
|
public int getMinReforgeDelay() {
|
||||||
return asInt(NPCSetting.MIN_REFORGE_DELAY);
|
return asInt(BlacksmithSetting.MIN_REFORGE_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -224,7 +230,7 @@ public class NPCSettings {
|
|||||||
* @return <p>The maximum reforge delay</p>
|
* @return <p>The maximum reforge delay</p>
|
||||||
*/
|
*/
|
||||||
public int getMaxReforgeDelay() {
|
public int getMaxReforgeDelay() {
|
||||||
return asInt(NPCSetting.MAX_REFORGE_DELAY);
|
return asInt(BlacksmithSetting.MAX_REFORGE_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -233,7 +239,7 @@ public class NPCSettings {
|
|||||||
* @return <p>The reforge cool-down</p>
|
* @return <p>The reforge cool-down</p>
|
||||||
*/
|
*/
|
||||||
public int getReforgeCoolDown() {
|
public int getReforgeCoolDown() {
|
||||||
return asInt(NPCSetting.REFORGE_COOL_DOWN);
|
return asInt(BlacksmithSetting.REFORGE_COOL_DOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -242,7 +248,16 @@ public class NPCSettings {
|
|||||||
* @return <p>The fail chance</p>
|
* @return <p>The fail chance</p>
|
||||||
*/
|
*/
|
||||||
public int getFailChance() {
|
public int getFailChance() {
|
||||||
return asInt(NPCSetting.FAIL_CHANCE);
|
return asInt(BlacksmithSetting.FAIL_CHANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether a failed reforging should remove/downgrade enchantments
|
||||||
|
*
|
||||||
|
* @return <p>Whether enchantments should be removed</p>
|
||||||
|
*/
|
||||||
|
public boolean getFailRemovesEnchantments() {
|
||||||
|
return asBoolean(BlacksmithSetting.FAIL_REMOVE_ENCHANTMENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -251,7 +266,7 @@ public class NPCSettings {
|
|||||||
* @return <p>The extra enchantment chance</p>
|
* @return <p>The extra enchantment chance</p>
|
||||||
*/
|
*/
|
||||||
public int getExtraEnchantmentChance() {
|
public int getExtraEnchantmentChance() {
|
||||||
return asInt(NPCSetting.EXTRA_ENCHANTMENT_CHANCE);
|
return asInt(BlacksmithSetting.EXTRA_ENCHANTMENT_CHANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -260,7 +275,7 @@ public class NPCSettings {
|
|||||||
* @return <p>The maximum enchantments</p>
|
* @return <p>The maximum enchantments</p>
|
||||||
*/
|
*/
|
||||||
public int getMaxEnchantments() {
|
public int getMaxEnchantments() {
|
||||||
return asInt(NPCSetting.MAX_ENCHANTMENTS);
|
return asInt(BlacksmithSetting.MAX_ENCHANTMENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -269,7 +284,7 @@ public class NPCSettings {
|
|||||||
* @return <p>Whether to drop reforged items on the ground</p>
|
* @return <p>Whether to drop reforged items on the ground</p>
|
||||||
*/
|
*/
|
||||||
public boolean getDropItem() {
|
public boolean getDropItem() {
|
||||||
return ConfigHelper.asBoolean(getValue(NPCSetting.DROP_ITEM));
|
return asBoolean(BlacksmithSetting.DROP_ITEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -278,25 +293,21 @@ public class NPCSettings {
|
|||||||
* @return <p>The title of the blacksmith</p>
|
* @return <p>The title of the blacksmith</p>
|
||||||
*/
|
*/
|
||||||
public String getBlacksmithTitle() {
|
public String getBlacksmithTitle() {
|
||||||
return asString(NPCSetting.BLACKSMITH_TITLE);
|
return asString(BlacksmithSetting.BLACKSMITH_TITLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Gets whether to disable the reforge-cool-down
|
|
||||||
*
|
|
||||||
* @return <p>Whether to disable the reforge-cool-down</p>
|
|
||||||
*/
|
|
||||||
public boolean getDisableCoolDown() {
|
public boolean getDisableCoolDown() {
|
||||||
return asInt(NPCSetting.REFORGE_COOL_DOWN) <= 0;
|
return asInt(BlacksmithSetting.REFORGE_COOL_DOWN) <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets whether to disable the delay between starting reforging and the reforging finishing
|
* Gets whether this blacksmith is able to repair anvils
|
||||||
*
|
*
|
||||||
* @return <p>Whether to disable the reforge delay</p>
|
* @return <p>True if this blacksmith is able to repair anvils</p>
|
||||||
*/
|
*/
|
||||||
public boolean getDisableDelay() {
|
public boolean getRepairAnvils() {
|
||||||
return asInt(NPCSetting.MAX_REFORGE_DELAY) <= 0;
|
return asBoolean(BlacksmithSetting.REPAIR_ANVILS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -307,7 +318,7 @@ public class NPCSettings {
|
|||||||
* @param setting <p>The setting to get the value of</p>
|
* @param setting <p>The setting to get the value of</p>
|
||||||
* @return <p>The value of the given setting as an integer</p>
|
* @return <p>The value of the given setting as an integer</p>
|
||||||
*/
|
*/
|
||||||
private int asInt(NPCSetting setting) {
|
private int asInt(BlacksmithSetting setting) {
|
||||||
return ConfigHelper.asInt(getValue(setting));
|
return ConfigHelper.asInt(getValue(setting));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,21 +328,31 @@ public class NPCSettings {
|
|||||||
* @param setting <p>The setting to get the value of</p>
|
* @param setting <p>The setting to get the value of</p>
|
||||||
* @return <p>The value of the given setting as a string</p>
|
* @return <p>The value of the given setting as a string</p>
|
||||||
*/
|
*/
|
||||||
private String asString(NPCSetting setting) {
|
private String asString(BlacksmithSetting setting) {
|
||||||
return getValue(setting).toString();
|
return getValue(setting).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the boolean value of the given setting
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting to get the value of</p>
|
||||||
|
* @return <p>The value of the given setting as a boolean</p>
|
||||||
|
*/
|
||||||
|
private boolean asBoolean(BlacksmithSetting setting) {
|
||||||
|
return ConfigHelper.asBoolean(getValue(setting));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of a setting, using the default if not set
|
* Gets the value of a setting, using the default if not set
|
||||||
*
|
*
|
||||||
* @param setting <p>The setting to get the value of</p>
|
* @param setting <p>The setting to get the value of</p>
|
||||||
* @return <p>The current value</p>
|
* @return <p>The current value</p>
|
||||||
*/
|
*/
|
||||||
private Object getValue(NPCSetting setting) {
|
private Object getValue(BlacksmithSetting setting) {
|
||||||
Object value = currentValues.get(setting);
|
Object value = currentValues.get(setting);
|
||||||
//If not set, use the default value from the config.yml file
|
//If not set, use the default value from the config.yml file
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
Map<NPCSetting, Object> defaultNPCSettings = globalSettings.getDefaultNPCSettings();
|
Map<BlacksmithSetting, Object> defaultNPCSettings = globalBlacksmithSettings.getDefaultNPCSettings();
|
||||||
if (defaultNPCSettings.containsKey(setting)) {
|
if (defaultNPCSettings.containsKey(setting)) {
|
||||||
value = defaultNPCSettings.get(setting);
|
value = defaultNPCSettings.get(setting);
|
||||||
}
|
}
|
||||||
@ -344,51 +365,38 @@ public class NPCSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces placeholders in the given reforge-able value
|
* Updates the list of blocked enchantments
|
||||||
*
|
|
||||||
* @param value <p>The value specified by a user</p>
|
|
||||||
* @return <p>The value with placeholders replaced</p>
|
|
||||||
*/
|
*/
|
||||||
private Object replaceReforgeAblePresets(Object value) {
|
private void updateEnchantmentBlockList() {
|
||||||
if (value instanceof String string) {
|
this.enchantmentBlockList.clear();
|
||||||
String[] list = string.split(",");
|
List<String> enchantments = ConfigHelper.asStringList(getValue(BlacksmithSetting.ENCHANTMENT_BLOCK_LIST));
|
||||||
List<String> replaced = new ArrayList<>(list.length);
|
if (enchantments != null) {
|
||||||
for (String item : list) {
|
this.enchantmentBlockList.addAll(getEnchantmentBlockList(enchantments));
|
||||||
replaced.add(SmithPreset.replacePreset(item));
|
|
||||||
}
|
|
||||||
return String.join(",", replaced);
|
|
||||||
} else if (value instanceof String[] stringList) {
|
|
||||||
List<String> replaced = new ArrayList<>(stringList.length);
|
|
||||||
for (String item : stringList) {
|
|
||||||
replaced.add(SmithPreset.replacePreset(item));
|
|
||||||
}
|
|
||||||
return replaced.toArray();
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("Unexpected object type encountered!");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the list of blocked enchantments
|
* Gets the list of enchantments listed in the given string list
|
||||||
|
*
|
||||||
|
* @param enchantments <p>The enchantment names to block</p>
|
||||||
|
* @return <p>The enchantments to be blocked</p>
|
||||||
*/
|
*/
|
||||||
private void updateEnchantmentBlocklist() {
|
public static List<Enchantment> getEnchantmentBlockList(List<String> enchantments) {
|
||||||
this.enchantmentBlocklist.clear();
|
List<Enchantment> enchantmentBlockList = new ArrayList<>();
|
||||||
List<String> newEnchantmentBlocklist = ConfigHelper.asStringList(getValue(NPCSetting.ENCHANTMENT_BLOCKLIST));
|
|
||||||
|
|
||||||
for (String item : newEnchantmentBlocklist) {
|
|
||||||
|
|
||||||
|
for (String item : enchantments) {
|
||||||
if (InputParsingHelper.isEmpty(item)) {
|
if (InputParsingHelper.isEmpty(item)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Enchantment enchantment = InputParsingHelper.matchEnchantment(item);
|
Enchantment enchantment = InputParsingHelper.matchEnchantment(item);
|
||||||
if (enchantment != null) {
|
if (enchantment != null) {
|
||||||
this.enchantmentBlocklist.add(enchantment);
|
enchantmentBlockList.add(enchantment);
|
||||||
} else {
|
} else {
|
||||||
BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING, "Unable to verify " + item +
|
BlacksmithPlugin.warn("Unable to verify " + item + " as a valid enchantment");
|
||||||
" as a valid enchantment");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return enchantmentBlockList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -396,25 +404,9 @@ public class NPCSettings {
|
|||||||
*/
|
*/
|
||||||
private void updateReforgeAbleItems() {
|
private void updateReforgeAbleItems() {
|
||||||
this.reforgeAbleItems.clear();
|
this.reforgeAbleItems.clear();
|
||||||
String newReforgeAbleItems = (String) currentValues.get(NPCSetting.REFORGE_ABLE_ITEMS);
|
List<String> materialStrings = ConfigHelper.asStringList(getValue(BlacksmithSetting.REFORGE_ABLE_ITEMS));
|
||||||
if (newReforgeAbleItems == null) {
|
if (materialStrings != null) {
|
||||||
return;
|
this.reforgeAbleItems.addAll(ItemHelper.getItems(materialStrings, true));
|
||||||
}
|
|
||||||
|
|
||||||
//Convert any presets with a list of materials
|
|
||||||
newReforgeAbleItems = (String) replaceReforgeAblePresets(newReforgeAbleItems);
|
|
||||||
|
|
||||||
for (String item : newReforgeAbleItems.split(",")) {
|
|
||||||
if (InputParsingHelper.isEmpty(item)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Material material = InputParsingHelper.matchMaterial(item);
|
|
||||||
if (material != null && BlacksmithTrait.isRepairable(new ItemStack(material, 1))) {
|
|
||||||
this.reforgeAbleItems.add(material);
|
|
||||||
} else {
|
|
||||||
BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING, "Unable to verify " + item +
|
|
||||||
" as a valid reforge-able item");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,352 @@
|
|||||||
|
package net.knarcraft.blacksmith.config.blacksmith;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.config.Setting;
|
||||||
|
import net.knarcraft.blacksmith.config.SettingValueType;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enum representing all blacksmith-related settings
|
||||||
|
*/
|
||||||
|
public enum BlacksmithSetting implements Setting {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for whether the NPC should drop an item to the ground when finished
|
||||||
|
*
|
||||||
|
* <p>If set to false, the item will be directly put in the player's inventory instead</p>
|
||||||
|
*/
|
||||||
|
DROP_ITEM("dropItem", SettingValueType.BOOLEAN, true, "Whether the " +
|
||||||
|
"item will drop a reforged item on the ground, instead of putting it into the user's inventory",
|
||||||
|
true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for the chance of a reforging to fail
|
||||||
|
*/
|
||||||
|
FAIL_CHANCE("failReforgeChance", SettingValueType.PERCENTAGE, 10,
|
||||||
|
"The chance to fail reforging an item, which only repairs the item a tiny bit or not at all (0-100)",
|
||||||
|
true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for whether failing a reforging should downgrade/remove enchantments as well
|
||||||
|
*/
|
||||||
|
FAIL_REMOVE_ENCHANTMENTS("failReforgeRemovesEnchantments", SettingValueType.BOOLEAN, false,
|
||||||
|
"Whether failed reforging should remove or " +
|
||||||
|
"downgrade the item's enchantments", true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for the chance of an additional enchantment being added
|
||||||
|
*/
|
||||||
|
EXTRA_ENCHANTMENT_CHANCE("extraEnchantmentChance", SettingValueType.PERCENTAGE, 5,
|
||||||
|
"The chance that an enchantment will be added to the " +
|
||||||
|
"reforged item (0-100)", true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for the maximum amount of enchantments that can be added to an item
|
||||||
|
*/
|
||||||
|
MAX_ENCHANTMENTS("maxEnchantments", SettingValueType.POSITIVE_INTEGER, 3,
|
||||||
|
"The maximum number of enchantments the blacksmith will try to" +
|
||||||
|
" add", true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum amount of seconds a player may need to wait for the reforging to finish
|
||||||
|
*/
|
||||||
|
MAX_REFORGE_DELAY("maxReforgeWaitTimeSeconds", SettingValueType.POSITIVE_INTEGER, 30,
|
||||||
|
"The maximum time for a reforging to finish",
|
||||||
|
true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum amount of seconds a player may need to wait for the reforging to finish
|
||||||
|
*/
|
||||||
|
MIN_REFORGE_DELAY("minReforgeWaitTimeSeconds", SettingValueType.POSITIVE_INTEGER, 5,
|
||||||
|
"The minimum time for a reforging to finish",
|
||||||
|
true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for number of seconds a player has to wait between each usage of the blacksmith
|
||||||
|
*/
|
||||||
|
REFORGE_COOL_DOWN("reforgeCoolDownSeconds", SettingValueType.POSITIVE_INTEGER, 60,
|
||||||
|
"The cool-down period between each reforge",
|
||||||
|
true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for which items the blacksmith is able to reforge
|
||||||
|
*/
|
||||||
|
REFORGE_ABLE_ITEMS("reforgeAbleItems", SettingValueType.REFORGE_ABLE_ITEMS, "",
|
||||||
|
"The items a blacksmith is able to reforge. Setting this only " +
|
||||||
|
"allows NPCs to repair the listed items. This should be set for each individual NPC.",
|
||||||
|
true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for the title used to display which kind of blacksmith the NPC is
|
||||||
|
*
|
||||||
|
* <p>While this should be entirely configurable, values such as armor-smith, sword-smith and similar, which
|
||||||
|
* describe the blacksmith's specialization, and thus the range of reforge-able items, is expected.</p>
|
||||||
|
*/
|
||||||
|
BLACKSMITH_TITLE("blacksmithTitle", SettingValueType.STRING, "blacksmith",
|
||||||
|
"The title describing the blacksmith's usage/speciality", true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for the enchantments a blacksmith cannot apply to items
|
||||||
|
*/
|
||||||
|
ENCHANTMENT_BLOCK_LIST("enchantmentBlockList", SettingValueType.ENCHANTMENT_LIST, List.of("binding_curse",
|
||||||
|
"mending", "vanishing_curse"), "The enchantments a " +
|
||||||
|
"blacksmith is denied from applying to an item. Disable anything you find too op or annoying.",
|
||||||
|
true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to allow this blacksmith to repair anvils
|
||||||
|
*/
|
||||||
|
REPAIR_ANVILS("reforgeAnvils", SettingValueType.BOOLEAN, false,
|
||||||
|
"Whether the blacksmith will reforge anvils as a special case", true, false),
|
||||||
|
|
||||||
|
/*-----------
|
||||||
|
| Messages |
|
||||||
|
-----------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when the blacksmith is busy with another player
|
||||||
|
*/
|
||||||
|
BUSY_WITH_PLAYER_MESSAGE("busyPlayerMessage", SettingValueType.STRING,
|
||||||
|
"&cI'm busy at the moment. Come back later!",
|
||||||
|
"The message to display when another player is using the blacksmith", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when the blacksmith is already reforging something for the player
|
||||||
|
*/
|
||||||
|
BUSY_WITH_REFORGE_MESSAGE("busyReforgeMessage", SettingValueType.STRING,
|
||||||
|
"&cI'm working on it. Be patient! I'll finish {time}!",
|
||||||
|
"The message to display when the blacksmith is working on the reforging", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed if the player has to wait for the cool-down to expire
|
||||||
|
*/
|
||||||
|
COOL_DOWN_UNEXPIRED_MESSAGE("coolDownUnexpiredMessage", SettingValueType.STRING,
|
||||||
|
"&cYou've already had your chance! Give me a break! I'll be ready {time}!",
|
||||||
|
"The message to display when the blacksmith is still on" +
|
||||||
|
" a cool-down from the previous re-forging", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when displaying the cost of reforging the held item to the player
|
||||||
|
*/
|
||||||
|
COST_MESSAGE("costMessage", SettingValueType.STRING,
|
||||||
|
"&eIt will cost &a{cost}&e to reforge that &a{item}&e! Click again to reforge!",
|
||||||
|
"The message to display when informing a player about the reforging" +
|
||||||
|
" cost", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed if the blacksmith fails reforging an item
|
||||||
|
*/
|
||||||
|
FAIL_MESSAGE("failReforgeMessage", SettingValueType.STRING,
|
||||||
|
"&cWhoops! Didn't mean to do that! Maybe next time?",
|
||||||
|
"The message to display when the blacksmith fails to reforge an item", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed if a player is unable to pay the blacksmith
|
||||||
|
*/
|
||||||
|
INSUFFICIENT_FUNDS_MESSAGE("insufficientFundsMessage", SettingValueType.STRING,
|
||||||
|
"&cYou don't have enough money to reforge that item!",
|
||||||
|
"The message to display when a player cannot pay for the reforging", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed if the blacksmith encounters an item they cannot reforge
|
||||||
|
*/
|
||||||
|
INVALID_ITEM_MESSAGE("invalidItemMessage", SettingValueType.STRING,
|
||||||
|
"&cI'm sorry, but I'm a/an {title}, I don't know how to reforge that!",
|
||||||
|
"The message to display when holding an item the blacksmith " +
|
||||||
|
"is unable to reforge", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed if a player presents a different item after seeing the price to reforge an item
|
||||||
|
*/
|
||||||
|
ITEM_UNEXPECTEDLY_CHANGED_MESSAGE("itemChangedMessage", SettingValueType.STRING,
|
||||||
|
"&cThat's not the item you wanted to reforge before!",
|
||||||
|
"The message to display when presenting a different item than the one just evaluated",
|
||||||
|
true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when the blacksmith starts reforging an item
|
||||||
|
*/
|
||||||
|
START_REFORGE_MESSAGE("startReforgeMessage", SettingValueType.STRING,
|
||||||
|
"&eOk, let's see what I can do...", "The message to " +
|
||||||
|
"display once the blacksmith starts re-forging", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when the blacksmith successfully finishes reforging an item
|
||||||
|
*/
|
||||||
|
SUCCESS_MESSAGE("successMessage", SettingValueType.STRING,
|
||||||
|
"There you go! All better!", "The message to display once " +
|
||||||
|
"the reforging has successfully finished", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when trying to reforge an item with full durability
|
||||||
|
*/
|
||||||
|
NOT_DAMAGED_MESSAGE("notDamagedMessage", SettingValueType.STRING, "&cThat item is not in need of repair",
|
||||||
|
"The message to display if a player is trying to reforge an item with full durability",
|
||||||
|
true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when clicking a blacksmith with an empty hand
|
||||||
|
*/
|
||||||
|
NO_ITEM_MESSAGE("noItemMessage", SettingValueType.STRING, "Please present the item you want to reforge",
|
||||||
|
"The message to display when a blacksmith is clicked with an empty hand", true, true),
|
||||||
|
|
||||||
|
/*------------------
|
||||||
|
| Global settings |
|
||||||
|
------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base price for repairing, regardless of durability
|
||||||
|
*
|
||||||
|
* <p>This allows specifying a price for each item, by setting basePrice.item_name.</p>
|
||||||
|
*/
|
||||||
|
BASE_PRICE("basePrice.default", SettingValueType.POSITIVE_DOUBLE, 10.0, "The minimum price of " +
|
||||||
|
"each cost", false, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base price for each durability point
|
||||||
|
*
|
||||||
|
* <p>If natural cost, this is the cost each missing durability point will add to the cost. If not natural cost,
|
||||||
|
* this is the cost each present durability point will add to the cost. This allows specifying a price per
|
||||||
|
* durability point value for each item, by setting pricePerDurabilityPoint.item_name</p>
|
||||||
|
*/
|
||||||
|
PRICE_PER_DURABILITY_POINT("pricePerDurabilityPoint.default", SettingValueType.POSITIVE_DOUBLE, 0.005,
|
||||||
|
"The additional cost for each durability point missing (natural cost) or present (not natural " +
|
||||||
|
"cost)", false, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The price increase for each level of each present enchantment
|
||||||
|
*
|
||||||
|
* <p>This can be specified for each possible enchantment by setting enchantment-cost.enchantment_name</p>
|
||||||
|
*/
|
||||||
|
ENCHANTMENT_COST("enchantmentCost.default", SettingValueType.POSITIVE_DOUBLE, 5.0,
|
||||||
|
"The additional cost for each enchantment level present on an item", false, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the cost should increase for damage taken, as opposed to increase for durability present
|
||||||
|
*/
|
||||||
|
NATURAL_COST("useNaturalCost", SettingValueType.BOOLEAN, true, "Natural cost makes re-forging " +
|
||||||
|
"more expensive the more damaged the item is. Disabling this will enable the legacy blacksmith behavior " +
|
||||||
|
"instead", false, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to show exact time when displaying the wait time for a reforging or the cool-down
|
||||||
|
*/
|
||||||
|
SHOW_EXACT_TIME("showExactTime", SettingValueType.BOOLEAN, false, "Exact time displays the " +
|
||||||
|
"exact number of seconds and minutes remaining as part of the reforging cool-down and reforging delay " +
|
||||||
|
"messages, instead of just vaguely hinting at the remaining time.", false, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cost for repairing a chipped anvil
|
||||||
|
*/
|
||||||
|
ANVIL_CHIPPED_COST("chippedAnvilReforgingCost", SettingValueType.POSITIVE_DOUBLE, 10.0,
|
||||||
|
"The cost of fully repairing a chipped anvil", false, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cost for repairing a damaged anvil
|
||||||
|
*/
|
||||||
|
ANVIL_DAMAGED_COST("damagedAnvilReforgingCost", SettingValueType.POSITIVE_DOUBLE, 20.0,
|
||||||
|
"The cost of fully repairing a damaged anvil", false, false),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final String path;
|
||||||
|
private final String childPath;
|
||||||
|
private final Object value;
|
||||||
|
private final String commandName;
|
||||||
|
private final SettingValueType valueType;
|
||||||
|
private final String description;
|
||||||
|
private final boolean isPerNPC;
|
||||||
|
private final boolean isMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new setting
|
||||||
|
*
|
||||||
|
* @param key <p>The configuration key for this setting</p>
|
||||||
|
* @param valueType <p>The type of value used by this setting</p>
|
||||||
|
* @param value <p>The default value of this setting</p>
|
||||||
|
* @param description <p>The description describing this setting</p>
|
||||||
|
* @param isPerNPC <p>Whether this setting is per-NPC or global</p>
|
||||||
|
* @param isMessage <p>Whether this option is for an NPC message</p>
|
||||||
|
*/
|
||||||
|
BlacksmithSetting(@NotNull String key, @NotNull SettingValueType valueType, @Nullable Object value,
|
||||||
|
@NotNull String description, boolean isPerNPC, boolean isMessage) {
|
||||||
|
if (isPerNPC) {
|
||||||
|
if (isMessage) {
|
||||||
|
this.path = "blacksmith.defaults.messages." + key;
|
||||||
|
} else {
|
||||||
|
this.path = "blacksmith.defaults." + key;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.path = "blacksmith.global." + key;
|
||||||
|
}
|
||||||
|
this.value = value;
|
||||||
|
this.valueType = valueType;
|
||||||
|
this.childPath = key;
|
||||||
|
if (key.contains(".")) {
|
||||||
|
String[] pathParts = key.split("\\.");
|
||||||
|
this.commandName = pathParts[0];
|
||||||
|
} else {
|
||||||
|
this.commandName = key;
|
||||||
|
}
|
||||||
|
this.description = description;
|
||||||
|
this.isPerNPC = isPerNPC;
|
||||||
|
this.isMessage = isMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String getChildPath() {
|
||||||
|
return childPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Object getDefaultValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String getCommandName() {
|
||||||
|
return commandName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull SettingValueType getValueType() {
|
||||||
|
return this.valueType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String getDescription() {
|
||||||
|
return this.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPerNPC() {
|
||||||
|
return this.isPerNPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMessage() {
|
||||||
|
return this.isMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the blacksmith setting specified by the input string
|
||||||
|
*
|
||||||
|
* @param input <p>The input to check</p>
|
||||||
|
* @return <p>The matching blacksmith setting, or null if not found</p>
|
||||||
|
*/
|
||||||
|
public static @Nullable BlacksmithSetting getSetting(@NotNull String input) {
|
||||||
|
for (BlacksmithSetting blacksmithSetting : BlacksmithSetting.values()) {
|
||||||
|
if (input.equalsIgnoreCase(blacksmithSetting.commandName)) {
|
||||||
|
return blacksmithSetting;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,566 @@
|
|||||||
|
package net.knarcraft.blacksmith.config.blacksmith;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.config.SettingValueType;
|
||||||
|
import net.knarcraft.blacksmith.config.Settings;
|
||||||
|
import net.knarcraft.blacksmith.config.StargateYamlConfiguration;
|
||||||
|
import net.knarcraft.blacksmith.util.ConfigHelper;
|
||||||
|
import net.knarcraft.blacksmith.util.InputParsingHelper;
|
||||||
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class which keeps track of all default blacksmith NPC settings and all global blacksmith settings
|
||||||
|
*/
|
||||||
|
public class GlobalBlacksmithSettings implements Settings<BlacksmithSetting> {
|
||||||
|
|
||||||
|
private final Map<Material, Double> materialBasePrices = new HashMap<>();
|
||||||
|
private final Map<Material, Double> materialPricePerDurabilityPoints = new HashMap<>();
|
||||||
|
private final Map<Enchantment, Double> enchantmentCosts = new HashMap<>();
|
||||||
|
private final Map<BlacksmithSetting, Object> settings = new HashMap<>();
|
||||||
|
private final List<Material> defaultReforgeAbleMaterials = new ArrayList<>();
|
||||||
|
private final List<Enchantment> defaultEnchantmentBlockList = new ArrayList<>();
|
||||||
|
private final BlacksmithPlugin instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new "Global Blacksmith Settings"
|
||||||
|
*
|
||||||
|
* @param instance <p>The blacksmith plugin to load and save configurations for</p>
|
||||||
|
*/
|
||||||
|
public GlobalBlacksmithSettings(BlacksmithPlugin instance) {
|
||||||
|
this.instance = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all configuration values from the config file
|
||||||
|
*/
|
||||||
|
public void load() {
|
||||||
|
// Just in case, clear existing values
|
||||||
|
this.settings.clear();
|
||||||
|
this.materialBasePrices.clear();
|
||||||
|
this.materialPricePerDurabilityPoints.clear();
|
||||||
|
this.enchantmentCosts.clear();
|
||||||
|
|
||||||
|
// Load/Save settings
|
||||||
|
loadSettings();
|
||||||
|
|
||||||
|
// Save any modified values to disk
|
||||||
|
instance.saveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the value of the given setting
|
||||||
|
*
|
||||||
|
* @param blacksmithSetting <p>The default NPC setting to change</p>
|
||||||
|
* @param newValue <p>The new value for the setting</p>
|
||||||
|
*/
|
||||||
|
public void changeValue(@NotNull BlacksmithSetting blacksmithSetting, @Nullable Object newValue) {
|
||||||
|
if (blacksmithSetting.getValueType() == SettingValueType.ENCHANTMENT_LIST ||
|
||||||
|
blacksmithSetting.getValueType() == SettingValueType.REFORGE_ABLE_ITEMS) {
|
||||||
|
//Workaround to make sure it's treated as the correct type
|
||||||
|
this.settings.put(blacksmithSetting, newValue == null ? null : ConfigHelper.asStringList(newValue));
|
||||||
|
} else {
|
||||||
|
this.settings.put(blacksmithSetting, newValue);
|
||||||
|
}
|
||||||
|
save();
|
||||||
|
if (blacksmithSetting == BlacksmithSetting.REFORGE_ABLE_ITEMS) {
|
||||||
|
loadReforgeAbleItems();
|
||||||
|
} else if (blacksmithSetting == BlacksmithSetting.ENCHANTMENT_BLOCK_LIST) {
|
||||||
|
loadEnchantmentBlockList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current raw value of the given default NPC setting
|
||||||
|
*
|
||||||
|
* @param blacksmithSetting <p>The setting to get</p>
|
||||||
|
* @return <p>The current raw setting value</p>
|
||||||
|
*/
|
||||||
|
public @NotNull Object getRawValue(@NotNull BlacksmithSetting blacksmithSetting) {
|
||||||
|
return this.settings.get(blacksmithSetting);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the enchantment cost for the given enchantment
|
||||||
|
*
|
||||||
|
* @param enchantment <p>The enchantment to set the enchantment cost for</p>
|
||||||
|
* @param newEnchantmentCost <p>The new enchantment cost</p>
|
||||||
|
*/
|
||||||
|
public void setEnchantmentCost(Enchantment enchantment, double newEnchantmentCost) {
|
||||||
|
if (enchantment == null) {
|
||||||
|
if (newEnchantmentCost < 0) {
|
||||||
|
throw new IllegalArgumentException("Enchantment cost cannot be negative!");
|
||||||
|
}
|
||||||
|
this.settings.put(BlacksmithSetting.ENCHANTMENT_COST, newEnchantmentCost);
|
||||||
|
} else {
|
||||||
|
if (newEnchantmentCost < 0) {
|
||||||
|
this.enchantmentCosts.put(enchantment, null);
|
||||||
|
} else {
|
||||||
|
this.enchantmentCosts.put(enchantment, newEnchantmentCost);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the price per durability point for the given material
|
||||||
|
*
|
||||||
|
* @param material <p>The material to set the price per durability point price for</p>
|
||||||
|
* @param newPrice <p>The new price per durability point price</p>
|
||||||
|
*/
|
||||||
|
public void setPricePerDurabilityPoint(Material material, double newPrice) {
|
||||||
|
if (material == null) {
|
||||||
|
if (newPrice < 0) {
|
||||||
|
throw new IllegalArgumentException("Price per durability point cannot be negative!");
|
||||||
|
}
|
||||||
|
this.settings.put(BlacksmithSetting.PRICE_PER_DURABILITY_POINT, newPrice);
|
||||||
|
} else {
|
||||||
|
//Use a negative price to unset the per-item value
|
||||||
|
if (newPrice < 0) {
|
||||||
|
this.materialPricePerDurabilityPoints.put(material, null);
|
||||||
|
} else {
|
||||||
|
this.materialPricePerDurabilityPoints.put(material, newPrice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the base price for the given material
|
||||||
|
*
|
||||||
|
* @param material <p>The material to set the base price for</p>
|
||||||
|
* @param newBasePrice <p>The new base price</p>
|
||||||
|
*/
|
||||||
|
public void setBasePrice(Material material, double newBasePrice) {
|
||||||
|
if (material == null) {
|
||||||
|
if (newBasePrice < 0) {
|
||||||
|
throw new IllegalArgumentException("Base price cannot be negative!");
|
||||||
|
}
|
||||||
|
settings.put(BlacksmithSetting.BASE_PRICE, newBasePrice);
|
||||||
|
} else {
|
||||||
|
//Use a negative price to unset the per-item value
|
||||||
|
if (newBasePrice < 0) {
|
||||||
|
this.materialBasePrices.put(material, null);
|
||||||
|
} else {
|
||||||
|
this.materialBasePrices.put(material, newBasePrice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current value of the default NPC settings
|
||||||
|
*
|
||||||
|
* @return <p>The current value of the default NPC settings</p>
|
||||||
|
*/
|
||||||
|
public Map<BlacksmithSetting, Object> getDefaultNPCSettings() {
|
||||||
|
return new HashMap<>(this.settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether to use natural cost for cost calculation
|
||||||
|
*
|
||||||
|
* <p>Natural cost makes it more costly the more damage is dealt to an item. The alternative is the legacy behavior
|
||||||
|
* where the amount of durability points remaining increases the cost.</p>
|
||||||
|
*
|
||||||
|
* @return <p>Whether to use natural cost</p>
|
||||||
|
*/
|
||||||
|
public boolean getUseNaturalCost() {
|
||||||
|
return asBoolean(BlacksmithSetting.NATURAL_COST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether to show exact time for reforging wait-time, and for wait-time between sessions
|
||||||
|
*
|
||||||
|
* @return <p>Whether to show exact time</p>
|
||||||
|
*/
|
||||||
|
public boolean getShowExactTime() {
|
||||||
|
return asBoolean(BlacksmithSetting.SHOW_EXACT_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the base price for the given material
|
||||||
|
*
|
||||||
|
* @param material <p>The material to get the base price for</p>
|
||||||
|
* @return <p>The base price for the material</p>
|
||||||
|
*/
|
||||||
|
public double getBasePrice(Material material) {
|
||||||
|
if (this.materialBasePrices.containsKey(material) && this.materialBasePrices.get(material) != null) {
|
||||||
|
return this.materialBasePrices.get(material);
|
||||||
|
} else {
|
||||||
|
return asDouble(BlacksmithSetting.BASE_PRICE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the price per durability point for the given material
|
||||||
|
*
|
||||||
|
* @param material <p>The material to get the durability point price for</p>
|
||||||
|
* @return <p>The durability point price for the material</p>
|
||||||
|
*/
|
||||||
|
public double getPricePerDurabilityPoint(Material material) {
|
||||||
|
if (this.materialPricePerDurabilityPoints.containsKey(material) &&
|
||||||
|
this.materialPricePerDurabilityPoints.get(material) != null) {
|
||||||
|
return this.materialPricePerDurabilityPoints.get(material);
|
||||||
|
} else {
|
||||||
|
return asDouble(BlacksmithSetting.PRICE_PER_DURABILITY_POINT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cost to be added for each level of the given enchantment
|
||||||
|
*
|
||||||
|
* @param enchantment <p>The enchantment to get the cost for</p>
|
||||||
|
* @return <p>The cost of each enchantment level</p>
|
||||||
|
*/
|
||||||
|
public double getEnchantmentCost(Enchantment enchantment) {
|
||||||
|
if (this.enchantmentCosts.containsKey(enchantment) && this.enchantmentCosts.get(enchantment) != null) {
|
||||||
|
return this.enchantmentCosts.get(enchantment);
|
||||||
|
} else {
|
||||||
|
return asDouble(BlacksmithSetting.ENCHANTMENT_COST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of reforgeAbleItems
|
||||||
|
*
|
||||||
|
* @return <p>The value of reforgeAbleItems</p>
|
||||||
|
*/
|
||||||
|
public @NotNull List<Material> getReforgeAbleItems() {
|
||||||
|
return this.defaultReforgeAbleMaterials;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of enchantmentBlockList
|
||||||
|
*
|
||||||
|
* @return <p>The value of enchantmentBlockList</p>
|
||||||
|
*/
|
||||||
|
public @NotNull List<Enchantment> getEnchantmentBlockList() {
|
||||||
|
return this.defaultEnchantmentBlockList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cost for repairing the given type of anvil
|
||||||
|
*
|
||||||
|
* @param material <p>The anvil material to repair</p>
|
||||||
|
* @return <p>The cost of repairing the anvil</p>
|
||||||
|
*/
|
||||||
|
public double getAnvilCost(Material material) {
|
||||||
|
if (material == Material.CHIPPED_ANVIL) {
|
||||||
|
return asDouble(BlacksmithSetting.ANVIL_CHIPPED_COST);
|
||||||
|
} else if (material == Material.DAMAGED_ANVIL) {
|
||||||
|
return asDouble(BlacksmithSetting.ANVIL_DAMAGED_COST);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("An unexpected item was encountered!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the given value as a boolean
|
||||||
|
*
|
||||||
|
* <p>This will throw an exception if used for a non-boolean value</p>
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting to get the value of</p>
|
||||||
|
* @return <p>The value of the given setting as a boolean</p>
|
||||||
|
*/
|
||||||
|
public boolean asBoolean(BlacksmithSetting setting) {
|
||||||
|
return ConfigHelper.asBoolean(getValue(setting));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the given value as a double
|
||||||
|
*
|
||||||
|
* <p>This will throw an exception if used for a non-double setting</p>
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting to get the value of</p>
|
||||||
|
* @return <p>The value of the given setting as a double</p>
|
||||||
|
*/
|
||||||
|
public double asDouble(BlacksmithSetting setting) {
|
||||||
|
return ConfigHelper.asDouble(getValue(setting));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of a setting, using the default if not set
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting to get the value of</p>
|
||||||
|
* @return <p>The current value</p>
|
||||||
|
*/
|
||||||
|
private Object getValue(BlacksmithSetting setting) {
|
||||||
|
Object value = this.settings.get(setting);
|
||||||
|
//If not set in config.yml, use the default value from the enum
|
||||||
|
if (value == null) {
|
||||||
|
value = setting.getDefaultValue();
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all global settings
|
||||||
|
*/
|
||||||
|
private void loadSettings() {
|
||||||
|
instance.reloadConfig();
|
||||||
|
FileConfiguration configuration = instance.getConfiguration();
|
||||||
|
|
||||||
|
for (BlacksmithSetting blacksmithSetting : BlacksmithSetting.values()) {
|
||||||
|
if (!configuration.contains(blacksmithSetting.getPath())) {
|
||||||
|
//If the setting does not exist in the config file, add it
|
||||||
|
configuration.set(blacksmithSetting.getPath(), blacksmithSetting.getDefaultValue());
|
||||||
|
} else {
|
||||||
|
//Set the setting to the value found in the path
|
||||||
|
settings.put(blacksmithSetting, configuration.get(blacksmithSetting.getPath()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadReforgeAbleItems();
|
||||||
|
loadEnchantmentBlockList();
|
||||||
|
|
||||||
|
//Load all base prices
|
||||||
|
loadBasePrices(configuration);
|
||||||
|
|
||||||
|
//Load all per-durability-point prices
|
||||||
|
loadPricesPerDurabilityPoint(configuration);
|
||||||
|
|
||||||
|
//Load all enchantment prices
|
||||||
|
loadEnchantmentPrices(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all prices for enchantments
|
||||||
|
*
|
||||||
|
* @param fileConfiguration <p>The configuration to read</p>
|
||||||
|
*/
|
||||||
|
private void loadEnchantmentPrices(@NotNull FileConfiguration fileConfiguration) {
|
||||||
|
ConfigurationSection enchantmentCostNode = fileConfiguration.getConfigurationSection(
|
||||||
|
getBase(BlacksmithSetting.ENCHANTMENT_COST.getPath()));
|
||||||
|
if (enchantmentCostNode == null) {
|
||||||
|
BlacksmithPlugin.warn("Could not load enchantment prices. because the configuration section doesn't exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Map<String, String> relevantKeys = getRelevantKeys(enchantmentCostNode);
|
||||||
|
for (String key : relevantKeys.keySet()) {
|
||||||
|
String enchantmentName = relevantKeys.get(key);
|
||||||
|
Enchantment enchantment = InputParsingHelper.matchEnchantment(enchantmentName);
|
||||||
|
BlacksmithPlugin.warn("loadEnchantmentPrices " + enchantmentName);
|
||||||
|
setItemPrice(this.enchantmentCosts, enchantmentName, enchantment, enchantmentCostNode.getDouble(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all prices per durability point for all materials
|
||||||
|
*
|
||||||
|
* @param fileConfiguration <p>The configuration to read</p>
|
||||||
|
*/
|
||||||
|
private void loadPricesPerDurabilityPoint(@NotNull FileConfiguration fileConfiguration) {
|
||||||
|
ConfigurationSection basePerDurabilityPriceNode = fileConfiguration.getConfigurationSection(
|
||||||
|
getBase(BlacksmithSetting.PRICE_PER_DURABILITY_POINT.getPath()));
|
||||||
|
if (basePerDurabilityPriceNode == null) {
|
||||||
|
BlacksmithPlugin.warn("Could not load per durability prices. because the configuration section doesn't exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Map<String, String> relevantKeys = getRelevantKeys(basePerDurabilityPriceNode);
|
||||||
|
|
||||||
|
for (String key : relevantKeys.keySet()) {
|
||||||
|
String materialName = relevantKeys.get(key);
|
||||||
|
double price = basePerDurabilityPriceNode.getDouble(key);
|
||||||
|
if (materialName.contains("*")) {
|
||||||
|
//Treat *CHESTPLATE as a regular expression to match all chest-plates
|
||||||
|
setMatchedMaterialPrices(this.materialPricePerDurabilityPoints, materialName, price);
|
||||||
|
} else {
|
||||||
|
Material material = InputParsingHelper.matchMaterial(materialName);
|
||||||
|
setItemPrice(this.materialPricePerDurabilityPoints, materialName, material, price);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads base prices for all materials
|
||||||
|
*
|
||||||
|
* @param fileConfiguration <p>The configuration to read</p>
|
||||||
|
*/
|
||||||
|
private void loadBasePrices(@NotNull FileConfiguration fileConfiguration) {
|
||||||
|
ConfigurationSection basePriceNode = fileConfiguration.getConfigurationSection(
|
||||||
|
getBase(BlacksmithSetting.BASE_PRICE.getPath()));
|
||||||
|
if (basePriceNode == null) {
|
||||||
|
BlacksmithPlugin.warn("Could not load base prices, because the configuration section doesn't exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Map<String, String> relevantKeys = getRelevantKeys(basePriceNode);
|
||||||
|
|
||||||
|
for (String key : relevantKeys.keySet()) {
|
||||||
|
String materialName = relevantKeys.get(key);
|
||||||
|
double price = basePriceNode.getDouble(key);
|
||||||
|
if (materialName.contains("*")) {
|
||||||
|
//Treat *CHESTPLATE as a regular expression to match all chest-plates
|
||||||
|
setMatchedMaterialPrices(this.materialBasePrices, materialName, price);
|
||||||
|
} else {
|
||||||
|
Material material = InputParsingHelper.matchMaterial(materialName);
|
||||||
|
setItemPrice(this.materialBasePrices, materialName, material, price);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the price for any materials matching the given wildcard material name
|
||||||
|
*
|
||||||
|
* @param prices <p>The map to store the prices in</p>
|
||||||
|
* @param materialName <p>The material name to match</p>
|
||||||
|
* @param price <p>The price to set for the matched materials</p>
|
||||||
|
*/
|
||||||
|
private void setMatchedMaterialPrices(@NotNull Map<Material, Double> prices, @NotNull String materialName, double price) {
|
||||||
|
String search = InputParsingHelper.regExIfy(materialName);
|
||||||
|
for (Material material : ItemHelper.getAllReforgeAbleMaterials()) {
|
||||||
|
if (material.name().matches(search)) {
|
||||||
|
setItemPrice(prices, material.name(), material, price);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the price for the given material
|
||||||
|
*
|
||||||
|
* @param prices <p>The map to store the price in</p>
|
||||||
|
* @param itemName <p>The name of the material to add a price for</p>
|
||||||
|
* @param item <p>The material parsed from the name</p>
|
||||||
|
* @param price <p>The price to set</p>
|
||||||
|
*/
|
||||||
|
private <K> void setItemPrice(@NotNull Map<K, Double> prices, @NotNull String itemName, @Nullable K item,
|
||||||
|
double price) {
|
||||||
|
if (item != null) {
|
||||||
|
prices.put(item, price);
|
||||||
|
} else {
|
||||||
|
BlacksmithPlugin.warn("Unable to find a material/enchantment matching " + itemName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a map between relevant keys and their normalized name
|
||||||
|
*
|
||||||
|
* @param configurationSection <p>The configuration section to search</p>
|
||||||
|
* @return <p>Any sub-keys found that aren't the default</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private Map<String, String> getRelevantKeys(@NotNull ConfigurationSection configurationSection) {
|
||||||
|
Map<String, String> relevant = new HashMap<>();
|
||||||
|
for (String dataKey : StargateYamlConfiguration.getKeysWithoutComments(configurationSection, false)) {
|
||||||
|
//Skip the default value
|
||||||
|
if (dataKey.equals("default")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String normalizedName = dataKey.toUpperCase().replace("-", "_");
|
||||||
|
relevant.put(dataKey, normalizedName);
|
||||||
|
}
|
||||||
|
return relevant;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a normalized material name to the format used in the config file
|
||||||
|
*
|
||||||
|
* @param normalizedName <p>The normalized name to un-normalize</p>
|
||||||
|
* @return <p>The un-normalized name</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private String unNormalizeName(@NotNull String normalizedName) {
|
||||||
|
return normalizedName.toLowerCase().replace("_", "-");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads reforgeAble items from the current value
|
||||||
|
*/
|
||||||
|
private void loadReforgeAbleItems() {
|
||||||
|
this.defaultReforgeAbleMaterials.clear();
|
||||||
|
List<String> materialNames = ConfigHelper.asStringList(settings.get(
|
||||||
|
BlacksmithSetting.REFORGE_ABLE_ITEMS));
|
||||||
|
if (materialNames != null) {
|
||||||
|
this.defaultReforgeAbleMaterials.addAll(ItemHelper.getItems(materialNames, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the enchantment block list from the current value
|
||||||
|
*/
|
||||||
|
private void loadEnchantmentBlockList() {
|
||||||
|
this.defaultEnchantmentBlockList.clear();
|
||||||
|
List<String> enchantmentNames = ConfigHelper.asStringList(settings.get(
|
||||||
|
BlacksmithSetting.ENCHANTMENT_BLOCK_LIST));
|
||||||
|
if (enchantmentNames != null) {
|
||||||
|
this.defaultEnchantmentBlockList.addAll(BlacksmithNPCSettings.getEnchantmentBlockList(enchantmentNames));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves all current settings to the config file
|
||||||
|
*/
|
||||||
|
private void save() {
|
||||||
|
FileConfiguration fileConfiguration = instance.getConfiguration();
|
||||||
|
|
||||||
|
//Save all default settings
|
||||||
|
for (BlacksmithSetting setting : BlacksmithSetting.values()) {
|
||||||
|
fileConfiguration.set(setting.getPath(), this.settings.get(setting));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Save all base prices
|
||||||
|
ConfigurationSection basePriceNode = getAndCreateSection(fileConfiguration, getBase(BlacksmithSetting.BASE_PRICE.getPath()));
|
||||||
|
for (Material material : this.materialBasePrices.keySet()) {
|
||||||
|
basePriceNode.set(unNormalizeName(material.name()), this.materialBasePrices.get(material));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Save all per-durability-point prices
|
||||||
|
ConfigurationSection basePerDurabilityPriceNode = getAndCreateSection(fileConfiguration, getBase(BlacksmithSetting.PRICE_PER_DURABILITY_POINT.getPath()));
|
||||||
|
for (Material material : this.materialPricePerDurabilityPoints.keySet()) {
|
||||||
|
basePerDurabilityPriceNode.set(unNormalizeName(material.name()), this.materialPricePerDurabilityPoints.get(material));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Load all enchantment prices
|
||||||
|
ConfigurationSection enchantmentCostNode = getAndCreateSection(fileConfiguration, getBase(BlacksmithSetting.ENCHANTMENT_COST.getPath()));
|
||||||
|
for (Enchantment enchantment : this.enchantmentCosts.keySet()) {
|
||||||
|
enchantmentCostNode.set(unNormalizeName(enchantment.getKey().getKey()), this.enchantmentCosts.get(enchantment));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Perform the actual save to disk
|
||||||
|
instance.saveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a configuration section, creating it if necessary
|
||||||
|
*
|
||||||
|
* @param fileConfiguration <p>The file configuration to read</p>
|
||||||
|
* @param sectionPath <p>The path to the configuration section to get</p>
|
||||||
|
* @return <p>The configuration section</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private ConfigurationSection getAndCreateSection(@NotNull FileConfiguration fileConfiguration, @NotNull String sectionPath) {
|
||||||
|
ConfigurationSection configurationSection = fileConfiguration.getConfigurationSection(sectionPath);
|
||||||
|
if (configurationSection == null) {
|
||||||
|
fileConfiguration.createSection(sectionPath);
|
||||||
|
configurationSection = fileConfiguration.getConfigurationSection(sectionPath);
|
||||||
|
}
|
||||||
|
if (configurationSection == null) {
|
||||||
|
throw new RuntimeException("Unable to create configuration section!");
|
||||||
|
}
|
||||||
|
return configurationSection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the base path of a configuration path pointing to a specific value
|
||||||
|
*
|
||||||
|
* @param configurationPath <p>The configuration path to get the base of</p>
|
||||||
|
* @return <p>The base configuration path</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private String getBase(@NotNull String configurationPath) {
|
||||||
|
String[] parts = configurationPath.split("\\.");
|
||||||
|
String[] base = Arrays.copyOfRange(parts, 0, parts.length - 1);
|
||||||
|
return String.join(".", base);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,278 @@
|
|||||||
|
package net.knarcraft.blacksmith.config.scrapper;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.config.SettingValueType;
|
||||||
|
import net.knarcraft.blacksmith.config.Settings;
|
||||||
|
import net.knarcraft.blacksmith.util.ConfigHelper;
|
||||||
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class which keeps track of all default scrapper NPC settings and all global scrapper settings
|
||||||
|
*/
|
||||||
|
public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
|
||||||
|
|
||||||
|
private final Map<ScrapperSetting, Object> settings = new HashMap<>();
|
||||||
|
private final List<Material> defaultSalvageableMaterials = new ArrayList<>();
|
||||||
|
private final Map<Material, Set<Material>> trashSalvage = new HashMap<>();
|
||||||
|
|
||||||
|
private final BlacksmithPlugin instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new "Settings"
|
||||||
|
*
|
||||||
|
* @param instance <p>A reference to the blacksmith plugin</p>
|
||||||
|
*/
|
||||||
|
public GlobalScrapperSettings(@NotNull BlacksmithPlugin instance) {
|
||||||
|
this.instance = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all configuration values from the config file
|
||||||
|
*/
|
||||||
|
public void load() {
|
||||||
|
//Just in case, clear existing values
|
||||||
|
this.settings.clear();
|
||||||
|
|
||||||
|
//Load/Save global settings
|
||||||
|
loadSettings();
|
||||||
|
|
||||||
|
//Save any modified values to disk
|
||||||
|
instance.saveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the value of the given setting
|
||||||
|
*
|
||||||
|
* @param scrapperSetting <p>The default NPC setting to change</p>
|
||||||
|
* @param newValue <p>The new value for the setting</p>
|
||||||
|
*/
|
||||||
|
public void changeValue(@NotNull ScrapperSetting scrapperSetting, @Nullable Object newValue) {
|
||||||
|
if (scrapperSetting.getValueType() == SettingValueType.STRING_LIST ||
|
||||||
|
scrapperSetting.getValueType() == SettingValueType.REFORGE_ABLE_ITEMS) {
|
||||||
|
//Workaround to make sure it's treated as the correct type
|
||||||
|
this.settings.put(scrapperSetting, newValue == null ? null : ConfigHelper.asStringList(newValue));
|
||||||
|
} else {
|
||||||
|
this.settings.put(scrapperSetting, newValue);
|
||||||
|
}
|
||||||
|
if (scrapperSetting == ScrapperSetting.SALVAGE_ABLE_ITEMS) {
|
||||||
|
loadSalvageAbleItems();
|
||||||
|
}
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current raw value of the given global setting
|
||||||
|
*
|
||||||
|
* @param scrapperSetting <p>The setting to get</p>
|
||||||
|
* @return <p>The current raw setting value</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public Object getRawValue(@NotNull ScrapperSetting scrapperSetting) {
|
||||||
|
return this.settings.get(scrapperSetting);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current value of the default NPC settings
|
||||||
|
*
|
||||||
|
* @return <p>The current value of the default NPC settings</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public Map<ScrapperSetting, Object> getDefaultNPCSettings() {
|
||||||
|
return new HashMap<>(this.settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether to show exact time for reforging wait-time, and for wait-time between sessions
|
||||||
|
*
|
||||||
|
* @return <p>Whether to show exact time</p>
|
||||||
|
*/
|
||||||
|
public boolean showExactTime() {
|
||||||
|
return asBoolean(ScrapperSetting.SHOW_EXACT_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the given value as a boolean
|
||||||
|
*
|
||||||
|
* <p>This will throw an exception if used for a non-boolean value</p>
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting to get the value of</p>
|
||||||
|
* @return <p>The value of the given setting as a boolean</p>
|
||||||
|
*/
|
||||||
|
public boolean asBoolean(@NotNull ScrapperSetting setting) {
|
||||||
|
return ConfigHelper.asBoolean(getValue(setting));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the given value as a double
|
||||||
|
*
|
||||||
|
* <p>This will throw an exception if used for a non-double setting</p>
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting to get the value of</p>
|
||||||
|
* @return <p>The value of the given setting as a double</p>
|
||||||
|
*/
|
||||||
|
public double asDouble(@NotNull ScrapperSetting setting) {
|
||||||
|
return ConfigHelper.asDouble(getValue(setting));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of a setting, using the default if not set
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting to get the value of</p>
|
||||||
|
* @return <p>The current value</p>
|
||||||
|
*/
|
||||||
|
private Object getValue(ScrapperSetting setting) {
|
||||||
|
Object value = this.settings.get(setting);
|
||||||
|
//If not set in config.yml, use the default value from the enum
|
||||||
|
if (value == null) {
|
||||||
|
value = setting.getDefaultValue();
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all global settings
|
||||||
|
*/
|
||||||
|
private void loadSettings() {
|
||||||
|
instance.reloadConfig();
|
||||||
|
FileConfiguration configuration = instance.getConfiguration();
|
||||||
|
|
||||||
|
for (ScrapperSetting setting : ScrapperSetting.values()) {
|
||||||
|
if (!configuration.contains(setting.getPath())) {
|
||||||
|
//If the setting does not exist in the config file, add it
|
||||||
|
configuration.set(setting.getPath(), setting.getDefaultValue());
|
||||||
|
} else {
|
||||||
|
//Set the setting to the value found in the path
|
||||||
|
this.settings.put(setting, configuration.get(setting.getPath()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadSalvageAbleItems();
|
||||||
|
loadTrashSalvage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves all current settings to the config file
|
||||||
|
*/
|
||||||
|
private void save() {
|
||||||
|
FileConfiguration fileConfiguration = instance.getConfiguration();
|
||||||
|
|
||||||
|
//Save all default settings
|
||||||
|
for (ScrapperSetting setting : ScrapperSetting.values()) {
|
||||||
|
fileConfiguration.set(setting.getPath(), this.settings.get(setting));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Perform the actual save to disk
|
||||||
|
instance.saveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of salvageAbleItems
|
||||||
|
*
|
||||||
|
* @return <p>The value of salvageAbleItems</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public List<Material> getSalvageAbleItems() {
|
||||||
|
return this.defaultSalvageableMaterials;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cost of using a scrapper to salvage an item
|
||||||
|
*
|
||||||
|
* @return <p>The cost of using a scrapper to salvage an item</p>
|
||||||
|
*/
|
||||||
|
public double getSalvageCost() {
|
||||||
|
return asDouble(ScrapperSetting.SALVAGE_COST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cost of using a scrapper to remove armor trim
|
||||||
|
*
|
||||||
|
* @return <p>The cost of using a scrapper to remove armor trim</p>
|
||||||
|
*/
|
||||||
|
public double getArmorTrimSalvageCost() {
|
||||||
|
return asDouble(ScrapperSetting.ARMOR_TRIM_SALVAGE_COST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cost of using a scrapper to remove netherite from an item
|
||||||
|
*
|
||||||
|
* @return <p>The cost of using a scrapper to remove netherite from an item</p>
|
||||||
|
*/
|
||||||
|
public double getNetheriteSalvageCost() {
|
||||||
|
return asDouble(ScrapperSetting.NETHERITE_SALVAGE_COST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets trash salvage for the given material
|
||||||
|
*
|
||||||
|
* <p>The trash salvage should be deferred when calculating item salvage, in order to increase the probability of
|
||||||
|
* getting the more expensive materials back.</p>
|
||||||
|
*
|
||||||
|
* @param material <p>The material to get trash salvage for</p>
|
||||||
|
* @return <p>The trash salvage</p>
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public Set<Material> getTrashSalvage(@NotNull Material material) {
|
||||||
|
return this.trashSalvage.get(material);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads reforgeAble items from the current value
|
||||||
|
*/
|
||||||
|
private void loadSalvageAbleItems() {
|
||||||
|
this.defaultSalvageableMaterials.clear();
|
||||||
|
List<String> materialNames = ConfigHelper.asStringList(this.settings.get(ScrapperSetting.SALVAGE_ABLE_ITEMS));
|
||||||
|
if (materialNames != null) {
|
||||||
|
this.defaultSalvageableMaterials.addAll(ItemHelper.getItems(materialNames, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all trash salvage from the configuration file
|
||||||
|
*/
|
||||||
|
private void loadTrashSalvage() {
|
||||||
|
this.trashSalvage.clear();
|
||||||
|
List<String> allTrashSalvage = ConfigHelper.asStringList(this.settings.get(ScrapperSetting.IGNORED_SALVAGE));
|
||||||
|
if (allTrashSalvage == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String trashSalvageInfo : allTrashSalvage) {
|
||||||
|
// Ignore invalid lines
|
||||||
|
if (!trashSalvageInfo.contains(":")) {
|
||||||
|
BlacksmithPlugin.warn(String.format("The trash salvage configuration line %s is invalid", trashSalvageInfo));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse all material names
|
||||||
|
String[] data = trashSalvageInfo.split(":");
|
||||||
|
String[] materialStrings = data[0].split(";");
|
||||||
|
List<Material> materials = new ArrayList<>();
|
||||||
|
for (String materialString : materialStrings) {
|
||||||
|
materials.addAll(ItemHelper.getWildcardMatch(materialString, true));
|
||||||
|
}
|
||||||
|
String[] trashSalvageStrings = data[1].split(";");
|
||||||
|
List<Material> ignored = new ArrayList<>();
|
||||||
|
for (String trashSalvageString : trashSalvageStrings) {
|
||||||
|
ignored.addAll(ItemHelper.getWildcardMatch(trashSalvageString, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the trash salvage to all the matched materials
|
||||||
|
for (Material material : materials) {
|
||||||
|
trashSalvage.computeIfAbsent(material, k -> new HashSet<>());
|
||||||
|
trashSalvage.get(material).addAll(ignored);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,469 @@
|
|||||||
|
package net.knarcraft.blacksmith.config.scrapper;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.util.DataKey;
|
||||||
|
import net.knarcraft.blacksmith.config.SettingValueType;
|
||||||
|
import net.knarcraft.blacksmith.config.TraitSettings;
|
||||||
|
import net.knarcraft.blacksmith.util.ConfigHelper;
|
||||||
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
|
||||||
|
|
||||||
|
private final Map<ScrapperSetting, Object> currentValues = new HashMap<>();
|
||||||
|
private final GlobalScrapperSettings globalScrapperSettings;
|
||||||
|
private final List<Material> salvageAbleItems = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new scrapper NPC settings object
|
||||||
|
*
|
||||||
|
* @param globalScrapperSettings <p>The global settings object to get default values from</p>
|
||||||
|
*/
|
||||||
|
public ScrapperNPCSettings(GlobalScrapperSettings globalScrapperSettings) {
|
||||||
|
this.globalScrapperSettings = globalScrapperSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads variables from the given data key
|
||||||
|
*
|
||||||
|
* @param key <p>The data key to load variables from</p>
|
||||||
|
*/
|
||||||
|
public void loadVariables(DataKey key) {
|
||||||
|
for (ScrapperSetting setting : ScrapperSetting.values()) {
|
||||||
|
if (key.keyExists(setting.getChildPath())) {
|
||||||
|
currentValues.put(setting, key.getRaw(setting.getChildPath()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves variables to the given data key
|
||||||
|
*
|
||||||
|
* @param key <p>The data key to save variables to</p>
|
||||||
|
*/
|
||||||
|
public void saveVariables(DataKey key) {
|
||||||
|
for (ScrapperSetting setting : ScrapperSetting.values()) {
|
||||||
|
key.setRaw(setting.getChildPath(), currentValues.get(setting));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes one setting to the given value
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting to change</p>
|
||||||
|
* @param newValue <p>The new value of the setting</p>
|
||||||
|
*/
|
||||||
|
public void changeValue(@NotNull ScrapperSetting setting, @Nullable Object newValue) {
|
||||||
|
if (setting.getValueType() == SettingValueType.STRING_LIST ||
|
||||||
|
setting.getValueType() == SettingValueType.REFORGE_ABLE_ITEMS) {
|
||||||
|
//Workaround to make sure it's treated as the correct type
|
||||||
|
currentValues.put(setting, newValue == null ? null : ConfigHelper.asStringList(newValue));
|
||||||
|
} else {
|
||||||
|
currentValues.put(setting, newValue);
|
||||||
|
}
|
||||||
|
if (setting == ScrapperSetting.SALVAGE_ABLE_ITEMS) {
|
||||||
|
updateSalvageAbleItems();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the reforge-able items according to the current value of the setting
|
||||||
|
*/
|
||||||
|
private void updateSalvageAbleItems() {
|
||||||
|
this.salvageAbleItems.clear();
|
||||||
|
List<String> materialStrings = ConfigHelper.asStringList(getValue(ScrapperSetting.SALVAGE_ABLE_ITEMS));
|
||||||
|
if (materialStrings != null) {
|
||||||
|
this.salvageAbleItems.addAll(ItemHelper.getItems(materialStrings, !extendedSalvageEnabled()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the raw current value of a setting
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting to get the value of</p>
|
||||||
|
* @return <p>The current value of the setting</p>
|
||||||
|
*/
|
||||||
|
public @NotNull Object getRawValue(@NotNull ScrapperSetting setting) {
|
||||||
|
return currentValues.get(setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public String getBusyWithPlayerMessage() {
|
||||||
|
return asString(ScrapperSetting.BUSY_WITH_PLAYER_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public String getBusyWorkingMessage() {
|
||||||
|
return asString(ScrapperSetting.BUSY_WITH_SALVAGE_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public String getStartWorkingMessage() {
|
||||||
|
return asString(ScrapperSetting.START_SALVAGE_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when a scrapper has successfully scrapped an item
|
||||||
|
*
|
||||||
|
* @return <p>The salvage success message</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getSuccessMessage() {
|
||||||
|
return asString(ScrapperSetting.SUCCESS_SALVAGE_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when a scrapper fails to salvage an item
|
||||||
|
*
|
||||||
|
* @return <p>The salvage fail message</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getFailSalvageMessage() {
|
||||||
|
return asString(ScrapperSetting.FAIL_SALVAGE_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when a scrapper fails to salvage an item without durability
|
||||||
|
*
|
||||||
|
* @return <p>The extended salvage fail message</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getFailExtendedSalvageMessage() {
|
||||||
|
return asString(ScrapperSetting.FAIL_SALVAGE_EXTENDED_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to use for displaying salvage cost
|
||||||
|
*
|
||||||
|
* @return <p>The message to use for displaying salvage cost</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getCostMessage() {
|
||||||
|
return asString(ScrapperSetting.COST_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to use for displaying armor trim salvage cost
|
||||||
|
*
|
||||||
|
* @return <p>The message to use for displaying armor trim salvage cost</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getArmorTrimCostMessage() {
|
||||||
|
return asString(ScrapperSetting.COST_MESSAGE_ARMOR_TRIM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to use for displaying netherite salvage cost
|
||||||
|
*
|
||||||
|
* @return <p>The message to use for displaying netherite salvage cost</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getNetheriteCostMessage() {
|
||||||
|
return asString(ScrapperSetting.COST_MESSAGE_NETHERITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public String getCoolDownUnexpiredMessage() {
|
||||||
|
return asString(ScrapperSetting.COOL_DOWN_UNEXPIRED_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message displayed if a player presents a different item after seeing the price to salvage an item
|
||||||
|
*
|
||||||
|
* @return <p>The item changed message</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getItemChangedMessage() {
|
||||||
|
return asString(ScrapperSetting.ITEM_UNEXPECTEDLY_CHANGED_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message displayed if a player presents the scrapper with an empty hand
|
||||||
|
*
|
||||||
|
* @return <p>The no item message</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getNoItemMessage() {
|
||||||
|
return asString(ScrapperSetting.NO_ITEM_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the minimum delay used to wait for a salvaging to finish.
|
||||||
|
*
|
||||||
|
* @return <p>The minimum salvage delay</p>
|
||||||
|
*/
|
||||||
|
public int getMinSalvageDelay() {
|
||||||
|
return asInt(ScrapperSetting.MIN_SALVAGE_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the maximum delay used to wait for a salvaging to finish
|
||||||
|
*
|
||||||
|
* @return <p>The maximum salvage delay</p>
|
||||||
|
*/
|
||||||
|
public int getMaxSalvageDelay() {
|
||||||
|
return asInt(ScrapperSetting.MAX_SALVAGE_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cool-down between each salvaging
|
||||||
|
*
|
||||||
|
* @return <p>The salvage cool-down</p>
|
||||||
|
*/
|
||||||
|
public int getSalvageCoolDown() {
|
||||||
|
return asInt(ScrapperSetting.SALVAGE_COOL_DOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether an item should be dropped on the ground instead of being given to the player
|
||||||
|
*
|
||||||
|
* @return <p>Whether to drop reforged items on the ground</p>
|
||||||
|
*/
|
||||||
|
public boolean getDropItem() {
|
||||||
|
return asBoolean(ScrapperSetting.DROP_ITEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getDisableCoolDown() {
|
||||||
|
return asInt(ScrapperSetting.SALVAGE_COOL_DOWN) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the chance of a salvaging to fail
|
||||||
|
*
|
||||||
|
* @return <p>The chance of a salvaging to fail</p>
|
||||||
|
*/
|
||||||
|
public int getFailChance() {
|
||||||
|
return asInt(ScrapperSetting.FAIL_SALVAGE_CHANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the given value as an integer
|
||||||
|
*
|
||||||
|
* <p>This will throw an exception if used for a non-integer setting</p>
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting to get the value of</p>
|
||||||
|
* @return <p>The value of the given setting as an integer</p>
|
||||||
|
*/
|
||||||
|
private int asInt(@NotNull ScrapperSetting setting) {
|
||||||
|
return ConfigHelper.asInt(getValue(setting));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the string value of the given setting
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting to get the value of</p>
|
||||||
|
* @return <p>The value of the given setting as a string</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private String asString(@NotNull ScrapperSetting setting) {
|
||||||
|
return getValue(setting).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the boolean value of the given setting
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting to get the value of</p>
|
||||||
|
* @return <p>The value of the given setting as a boolean</p>
|
||||||
|
*/
|
||||||
|
private boolean asBoolean(@NotNull ScrapperSetting setting) {
|
||||||
|
return ConfigHelper.asBoolean(getValue(setting));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of a setting, using the default if not set
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting to get the value of</p>
|
||||||
|
* @return <p>The current value</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private Object getValue(@NotNull ScrapperSetting setting) {
|
||||||
|
Object value = currentValues.get(setting);
|
||||||
|
//If not set, use the default value from the config.yml file
|
||||||
|
if (value == null) {
|
||||||
|
Map<ScrapperSetting, Object> defaultNPCSettings = globalScrapperSettings.getDefaultNPCSettings();
|
||||||
|
if (defaultNPCSettings.containsKey(setting)) {
|
||||||
|
value = defaultNPCSettings.get(setting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//If not set in config.yml, use the default value from the enum
|
||||||
|
if (value == null) {
|
||||||
|
value = setting.getDefaultValue();
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all item types this NPC is able to salvage
|
||||||
|
*
|
||||||
|
* @return <p>All salvageable items</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public List<Material> getSalvageAbleItems() {
|
||||||
|
Object currentValue = currentValues.get(ScrapperSetting.SALVAGE_ABLE_ITEMS);
|
||||||
|
if (currentValue == null || String.valueOf(currentValue).isEmpty()) {
|
||||||
|
return globalScrapperSettings.getSalvageAbleItems();
|
||||||
|
} else {
|
||||||
|
return new ArrayList<>(this.salvageAbleItems);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether extended salvaging is enabled
|
||||||
|
*
|
||||||
|
* <p>When not extended, only repairable items can be salvaged. When extended, any item produced using a crafting
|
||||||
|
* recipe can be salvaged. This does not include smelting or similar.</p>
|
||||||
|
*
|
||||||
|
* @return <p>True if extended salvaging is enabled</p>
|
||||||
|
*/
|
||||||
|
public boolean extendedSalvageEnabled() {
|
||||||
|
return asBoolean(ScrapperSetting.EXTENDED_SALVAGE_ENABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether salvage of enchanted items is enabled
|
||||||
|
*
|
||||||
|
* @return <p>True of this scrapper can salvage enchanted items</p>
|
||||||
|
*/
|
||||||
|
public boolean salvageEnchanted() {
|
||||||
|
return asBoolean(ScrapperSetting.SALVAGE_ENCHANTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether salvage of armor trims is enabled
|
||||||
|
*
|
||||||
|
* @return <p>True if this scrapper can salvage armor trims</p>
|
||||||
|
*/
|
||||||
|
public boolean salvageArmorTrims() {
|
||||||
|
return asBoolean(ScrapperSetting.SALVAGE_ARMOR_TRIMS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether salvage of netherite items is enabled
|
||||||
|
*
|
||||||
|
* @return <p>True if this scrapper can salvage netherite items</p>
|
||||||
|
*/
|
||||||
|
public boolean salvageNetherite() {
|
||||||
|
return asBoolean(ScrapperSetting.SALVAGE_NETHERITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the title of this scrapper NPC
|
||||||
|
*
|
||||||
|
* <p>The title is used to specify scrapper sub-types in order to make it clear which items a scrapper can salvage.
|
||||||
|
* For example, an armor-scrapper would only be able to salvage armor pieces.</p>
|
||||||
|
*
|
||||||
|
* @return <p>The title of this scrapper NPC</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getScrapperTitle() {
|
||||||
|
return asString(ScrapperSetting.SCRAPPER_TITLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display if this NPC is given an item it cannot salvage
|
||||||
|
*
|
||||||
|
* @return <p>The message to display</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getInvalidItemMessage() {
|
||||||
|
return asString(ScrapperSetting.INVALID_ITEM_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display if the player is unable to afford an item salvage
|
||||||
|
*
|
||||||
|
* @return <p>The message to display</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getInsufficientFundsMessage() {
|
||||||
|
return asString(ScrapperSetting.INSUFFICIENT_FUNDS_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display if an item is too damaged to produce any salvage
|
||||||
|
*
|
||||||
|
* @return <p>The no salvage message</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getTooDamagedMessage() {
|
||||||
|
return asString(ScrapperSetting.TOO_DAMAGED_FOR_SALVAGE_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when explaining that full salvage will be given for an item
|
||||||
|
*
|
||||||
|
* @return <p>The full salvage message</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getFullSalvageMessage() {
|
||||||
|
return asString(ScrapperSetting.FULL_SALVAGE_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when explaining that only partial salvage will be given for an item
|
||||||
|
*
|
||||||
|
* @return <p>The partial salvage message</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getPartialSalvageMessage() {
|
||||||
|
return asString(ScrapperSetting.PARTIAL_SALVAGE_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when explaining that this scrapper is unable to salvage enchanted items
|
||||||
|
*
|
||||||
|
* @return <p>The cannot salvage enchanted message</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getCannotSalvageEnchantedMessage() {
|
||||||
|
return asString(ScrapperSetting.CANNOT_SALVAGE_ENCHANTED_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when explaining that this scrapper is unable to salvage armor trims
|
||||||
|
*
|
||||||
|
* @return <p>The cannot salvage armor trim message</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getCannotSalvageArmorTrimMessage() {
|
||||||
|
return asString(ScrapperSetting.CANNOT_SALVAGE_ARMOR_TRIM_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when explaining that this scrapper is unable to find salvage for the armor trim
|
||||||
|
*
|
||||||
|
* <p>Because there is no direct way (that I have found) to convert TrimMaterial and TrimPattern to Material, armor
|
||||||
|
* trim salvaging relies on material string and a hard-coded map. As those are prone to breaking because of API
|
||||||
|
* changes, there is a high likelihood that cases will arise when the scrapper is unable to find the correct
|
||||||
|
* materials.</p>
|
||||||
|
*
|
||||||
|
* @return <p>The cannot find armor trim salvage message</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getArmorTrimSalvageNotFoundMessage() {
|
||||||
|
return asString(ScrapperSetting.ARMOR_TRIM_SALVAGE_NOT_FOUND_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when explaining that this scrapper is unable to salvage netherite items
|
||||||
|
*
|
||||||
|
* @return <p>The message to display when explaining that this scrapper is unable to salvage netherite items</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getCannotSalvageNetheriteMessage() {
|
||||||
|
return asString(ScrapperSetting.CANNOT_SALVAGE_NETHERITE_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,397 @@
|
|||||||
|
package net.knarcraft.blacksmith.config.scrapper;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.config.Setting;
|
||||||
|
import net.knarcraft.blacksmith.config.SettingValueType;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enum representing all scrapper-related settings
|
||||||
|
*/
|
||||||
|
public enum ScrapperSetting implements Setting {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for whether the NPC should drop an item to the ground when finished
|
||||||
|
*
|
||||||
|
* <p>If set to false, the item will be directly put in the player's inventory instead</p>
|
||||||
|
*/
|
||||||
|
DROP_ITEM("dropItem", SettingValueType.BOOLEAN, true, "Whether the " +
|
||||||
|
"item will drop materials resulting from salvaging on the ground, instead of putting them into the user's" +
|
||||||
|
" inventory", true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The chance of a scrapper returning no salvage, regardless of item condition
|
||||||
|
*/
|
||||||
|
FAIL_SALVAGE_CHANCE("failSalvageChance", SettingValueType.POSITIVE_DOUBLE, 0,
|
||||||
|
"The chance to fail a salvage, thus destroying the item (0-100)",
|
||||||
|
true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for which items a scrapper is able to salvage
|
||||||
|
*/
|
||||||
|
SALVAGE_ABLE_ITEMS("salvageAbleItems", SettingValueType.REFORGE_ABLE_ITEMS, "",
|
||||||
|
"The items a blacksmith is able to salvage. Setting this only " +
|
||||||
|
"allows NPCs to repair the listed items. This should be set for each individual NPC",
|
||||||
|
true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum amount of seconds a player may need to wait for the reforging to finish
|
||||||
|
*/
|
||||||
|
MAX_SALVAGE_DELAY("maxSalvageWaitTimeSeconds", SettingValueType.POSITIVE_INTEGER, 30,
|
||||||
|
"The maximum time for a salvaging to finish",
|
||||||
|
true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum amount of seconds a player may need to wait for the reforging to finish
|
||||||
|
*/
|
||||||
|
MIN_SALVAGE_DELAY("minSalvageWaitTimeSeconds", SettingValueType.POSITIVE_INTEGER, 5,
|
||||||
|
"The minimum time for a salvaging to finish",
|
||||||
|
true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for number of seconds a player has to wait between each usage of the blacksmith
|
||||||
|
*/
|
||||||
|
SALVAGE_COOL_DOWN("salvageCoolDownSeconds", SettingValueType.POSITIVE_INTEGER, 60,
|
||||||
|
"The cool-down period between each salvage",
|
||||||
|
true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for the title used to display which kind of scrapper the NPC is
|
||||||
|
*
|
||||||
|
* <p>While this should be entirely configurable, values such as armor-scrapper, sword-scrapper and similar, which
|
||||||
|
* describe the scrapper's specialization, and thus the range of salvageable items, is expected.</p>
|
||||||
|
*/
|
||||||
|
SCRAPPER_TITLE("scrapperTitle", SettingValueType.STRING, "scrapper",
|
||||||
|
"The title describing the scrapper's usage/speciality", true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for whether the NPC should allow salvaging of any craft-able item instead of just repairable items
|
||||||
|
*/
|
||||||
|
EXTENDED_SALVAGE_ENABLED("extendedSalvageEnabled", SettingValueType.BOOLEAN, false,
|
||||||
|
"Whether to enable salvaging of non-repairable items, such as planks", true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for whether the NPC should allow salvaging of enchanted items
|
||||||
|
*/
|
||||||
|
SALVAGE_ENCHANTED("salvageEnchanted", SettingValueType.BOOLEAN, false,
|
||||||
|
"Whether to enable salvaging of enchanted items. This is disabled by default because it's " +
|
||||||
|
"possible to accidentally salvage items with very good enchantments.", true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for whether the NPC should allow salvaging of armor trims
|
||||||
|
*/
|
||||||
|
SALVAGE_ARMOR_TRIMS("salvageArmorTrims", SettingValueType.BOOLEAN, true,
|
||||||
|
"Whether to enable salvaging of armor trims.", true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for whether the NPC should allow salvaging netherite items to diamond items
|
||||||
|
*/
|
||||||
|
SALVAGE_NETHERITE("salvageNetherite", SettingValueType.BOOLEAN, true,
|
||||||
|
"Whether to enable salvaging of netherite items", true, false),
|
||||||
|
|
||||||
|
/*-----------
|
||||||
|
| Messages |
|
||||||
|
-----------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when the scrapper is busy with another player
|
||||||
|
*/
|
||||||
|
BUSY_WITH_PLAYER_MESSAGE("busyPlayerMessage", SettingValueType.STRING, "&cI'm busy at the moment. Come " +
|
||||||
|
"back later!", "The message to display when another player is using the scrapper",
|
||||||
|
true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when the scrapper is busy salvaging the player's item
|
||||||
|
*/
|
||||||
|
BUSY_WITH_SALVAGE_MESSAGE("busySalvageMessage", SettingValueType.STRING, "&cI'm working on it. Be " +
|
||||||
|
"patient! I'll finish {time}!", "The message to display when the blacksmith is working on the " +
|
||||||
|
"salvaging", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed if the player needs to wait for the cool-down to expire
|
||||||
|
*/
|
||||||
|
COOL_DOWN_UNEXPIRED_MESSAGE("coolDownUnexpiredMessage", SettingValueType.STRING,
|
||||||
|
"&cYou've already had your chance! Give me a break! I'll be ready {time}!",
|
||||||
|
"The message to display when the blacksmith is still " +
|
||||||
|
"on a cool-down from the previous re-forging", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed if the scrapper encounters an item they cannot salvage
|
||||||
|
*/
|
||||||
|
INVALID_ITEM_MESSAGE("invalidItemMessage", SettingValueType.STRING,
|
||||||
|
"&cI'm sorry, but I'm a/an {title}, I don't know how to salvage that!",
|
||||||
|
"The message to display if the player tries to salvage" +
|
||||||
|
" an item the scrapper cannot salvage", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed if salvaging an item would return in no items
|
||||||
|
*/
|
||||||
|
TOO_DAMAGED_FOR_SALVAGE_MESSAGE("tooDamagedForSalvageMessage", SettingValueType.STRING,
|
||||||
|
"&cThat item is too damaged to be salvaged into anything useful", "The message to display " +
|
||||||
|
"if salvaging the player's item would result in no salvage", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed if a salvage is successful
|
||||||
|
*/
|
||||||
|
SUCCESS_SALVAGE_MESSAGE("successSalvagedMessage", SettingValueType.STRING, "There you go!",
|
||||||
|
"The message to display when an item is successfully salvaged", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed if a salvage is unsuccessful
|
||||||
|
*/
|
||||||
|
FAIL_SALVAGE_MESSAGE("failSalvageMessage", SettingValueType.STRING, "&cWhoops! The item broke! Maybe " +
|
||||||
|
"next time?", "The message to display when a scrapper fails to salvage an item because of the " +
|
||||||
|
"fail chance.", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed if a salvage of an item without durability is unsuccessful
|
||||||
|
*/
|
||||||
|
FAIL_SALVAGE_EXTENDED_MESSAGE("failExtendedSalvageMessage", SettingValueType.STRING,
|
||||||
|
"&cWhoops! I was unable to extract much, if any, salvage! Maybe next time?",
|
||||||
|
"The message to display when the scrapper fails to salvage an item without durability", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed if a player presents a different item after seeing the price to reforge an item
|
||||||
|
*/
|
||||||
|
ITEM_UNEXPECTEDLY_CHANGED_MESSAGE("itemChangedMessage", SettingValueType.STRING, "&cThat's not the item" +
|
||||||
|
" you wanted to salvage before!", "The message to display when presenting a different item than" +
|
||||||
|
" the one just evaluated", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when the scrapper starts salvaging an item
|
||||||
|
*/
|
||||||
|
START_SALVAGE_MESSAGE("startSalvageMessage", SettingValueType.STRING, "&eOk, let's see what I can do...",
|
||||||
|
"The message to display once the blacksmith starts re-forging", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed if a player is unable to pay the blacksmith
|
||||||
|
*/
|
||||||
|
INSUFFICIENT_FUNDS_MESSAGE("insufficientFundsMessage", SettingValueType.STRING,
|
||||||
|
"&cYou don't have enough money to salvage an item!",
|
||||||
|
"The message to display when a player cannot pay for the salvaging", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when displaying the cost of salvaging the held item to the player
|
||||||
|
*/
|
||||||
|
COST_MESSAGE("costMessage", SettingValueType.STRING,
|
||||||
|
"&eIt will cost &a{cost}&e to salvage that &a{item}&e! {yield} &eClick again to salvage!",
|
||||||
|
"The message to display when informing a player about the salvaging cost", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when displaying the cost of salvaging the armor trim of the held item to the player
|
||||||
|
*/
|
||||||
|
COST_MESSAGE_ARMOR_TRIM("costMessageArmorTrim", SettingValueType.STRING,
|
||||||
|
"&eIt will cost &a{cost}&e to salvage that &a{item}&e's armor trim!",
|
||||||
|
"The message to display when explaining the shown item's armor trim's salvage cost", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when displaying the cost of salvaging the netherite of the held item to the player
|
||||||
|
*/
|
||||||
|
COST_MESSAGE_NETHERITE("costMessageNetherite", SettingValueType.STRING,
|
||||||
|
"&eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond!",
|
||||||
|
"The message to display when explaining the shown item's netherite salvage cost", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when explaining that all items will be returned as salvage
|
||||||
|
*/
|
||||||
|
FULL_SALVAGE_MESSAGE("fullSalvageMessage", SettingValueType.STRING,
|
||||||
|
"&aI should be able to extract all components from that pristine item.&r",
|
||||||
|
"The message to display when explaining expected full yield as part of the cost message", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when explaining that only some items will be returned as salvage
|
||||||
|
*/
|
||||||
|
PARTIAL_SALVAGE_MESSAGE("partialSalvageMessage", SettingValueType.STRING,
|
||||||
|
"&cI cannot extract all components from that damaged item.&r",
|
||||||
|
"The message to display when explaining expected partial yield as part of the cost message", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when explaining that enchanted item salvage is disabled
|
||||||
|
*/
|
||||||
|
CANNOT_SALVAGE_ENCHANTED_MESSAGE("cannotSalvageEnchantedMessage", SettingValueType.STRING,
|
||||||
|
"&cI'm sorry, but I'm unable to salvage enchanted items!",
|
||||||
|
"The message to display when asked to salvage an enchanted item, and that option is disabled", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when explaining that armor trim salvage is disabled
|
||||||
|
*/
|
||||||
|
CANNOT_SALVAGE_ARMOR_TRIM_MESSAGE("cannotSalvageArmorTrimMessage", SettingValueType.STRING,
|
||||||
|
"&cI'm sorry, but I'm unable to salvage armor trims!",
|
||||||
|
"The message to display when asked to salvage an armor trim, and that option is disabled", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when explaining that the items to return as armor trim salvage are unknown
|
||||||
|
*/
|
||||||
|
ARMOR_TRIM_SALVAGE_NOT_FOUND_MESSAGE("armorTrimSalvageNotFoundMessage", SettingValueType.STRING,
|
||||||
|
"&cI'm sorry, but I don't know how to salvage that armor trim!",
|
||||||
|
"The message to display if the correct materials to return for the armor trim are unknown", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when explaining that netherite salvage is disabled
|
||||||
|
*/
|
||||||
|
CANNOT_SALVAGE_NETHERITE_MESSAGE("cannotSalvageNetheriteMessage", SettingValueType.STRING,
|
||||||
|
"&cI'm sorry, but I'm unable to salvage netherite items!",
|
||||||
|
"The message to display when asked to salvage netherite items, and that option is disabled", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when clicking a scrapper with an empty hand
|
||||||
|
*/
|
||||||
|
NO_ITEM_MESSAGE("noItemMessage", SettingValueType.STRING, "Please present the item you want to salvage",
|
||||||
|
"The message to display when a scrapper is clicked with an empty hand", true, true),
|
||||||
|
|
||||||
|
/*------------------
|
||||||
|
| Global settings |
|
||||||
|
------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for the salvage cost
|
||||||
|
*/
|
||||||
|
SALVAGE_COST("salvagePrice", SettingValueType.POSITIVE_DOUBLE, 0,
|
||||||
|
"The cost of using a scrapper to salvage an item", false, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for the armor trim salvage cost
|
||||||
|
*/
|
||||||
|
ARMOR_TRIM_SALVAGE_COST("armorTrimSalvagePrice", SettingValueType.POSITIVE_DOUBLE, 5,
|
||||||
|
"The cost of using the scrapper to remove armor trim", false, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for the netherite salvage cost
|
||||||
|
*/
|
||||||
|
NETHERITE_SALVAGE_COST("netheriteSalvagePrice", SettingValueType.POSITIVE_DOUBLE, 15,
|
||||||
|
"The cost of using the scrapper to remove netherite from an item", false, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to display exact time in minutes and seconds when displaying a remaining cool-down
|
||||||
|
*/
|
||||||
|
SHOW_EXACT_TIME("showExactTime", SettingValueType.BOOLEAN, "false", "Exact time displays the " +
|
||||||
|
"exact number of seconds and minutes remaining as part of the salvaging cool-down and salvaging delay " +
|
||||||
|
"messages, instead of just vaguely hinting at the remaining time.", false, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to give experience back when salvaging an enchanted item
|
||||||
|
*/
|
||||||
|
GIVE_EXPERIENCE("giveExperience", SettingValueType.BOOLEAN, "true", "Whether enchanted " +
|
||||||
|
"salvaged items should return some amount of exp upon salvage", false, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Which items are ignored when calculating salvage for a given material
|
||||||
|
*/
|
||||||
|
IGNORED_SALVAGE("trashSalvage", SettingValueType.STRING_LIST,
|
||||||
|
new ArrayList<>(List.of("*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD;SHIELD;*_BOW:STICK")),
|
||||||
|
"Items treated as trash during salvage calculation. This follows the format: " +
|
||||||
|
"\"MATERIAL[;MATERIAL2][;MATERIAL3]:TRASH_MATERIAL[;TRASH_MATERIAL2]\", so the material or " +
|
||||||
|
"materials listed will treat the material specified after the \":\" as trash when calculating " +
|
||||||
|
"salvage unless all non-trash items can be given as well(* matches any character).",
|
||||||
|
false, false),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final String path;
|
||||||
|
private final String childPath;
|
||||||
|
private final Object value;
|
||||||
|
private final String commandName;
|
||||||
|
private final SettingValueType valueType;
|
||||||
|
private final String description;
|
||||||
|
private final boolean isPerNPC;
|
||||||
|
private final boolean isMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new setting
|
||||||
|
*
|
||||||
|
* @param key <p>The configuration key for this setting</p>
|
||||||
|
* @param valueType <p>The type of value used by this setting</p>
|
||||||
|
* @param value <p>The default value of this setting</p>
|
||||||
|
* @param description <p>The description describing this setting</p>
|
||||||
|
* @param isPerNPC <p>Whether this setting is per-NPC or global</p>
|
||||||
|
* @param isMessage <p>Whether this option is for an NPC message</p>
|
||||||
|
*/
|
||||||
|
ScrapperSetting(@NotNull String key, @NotNull SettingValueType valueType, @Nullable Object value,
|
||||||
|
@NotNull String description, boolean isPerNPC, boolean isMessage) {
|
||||||
|
if (isPerNPC) {
|
||||||
|
if (isMessage) {
|
||||||
|
this.path = "scrapper.defaults.messages." + key;
|
||||||
|
} else {
|
||||||
|
this.path = "scrapper.defaults." + key;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.path = "scrapper.global." + key;
|
||||||
|
}
|
||||||
|
this.value = value;
|
||||||
|
this.valueType = valueType;
|
||||||
|
this.childPath = key;
|
||||||
|
if (key.contains(".")) {
|
||||||
|
String[] pathParts = key.split("\\.");
|
||||||
|
this.commandName = pathParts[0];
|
||||||
|
} else {
|
||||||
|
this.commandName = key;
|
||||||
|
}
|
||||||
|
this.description = description;
|
||||||
|
this.isPerNPC = isPerNPC;
|
||||||
|
this.isMessage = isMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public String getPath() {
|
||||||
|
return this.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public String getChildPath() {
|
||||||
|
return this.childPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public Object getDefaultValue() {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public String getCommandName() {
|
||||||
|
return this.commandName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public SettingValueType getValueType() {
|
||||||
|
return this.valueType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public String getDescription() {
|
||||||
|
return this.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPerNPC() {
|
||||||
|
return this.isPerNPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMessage() {
|
||||||
|
return this.isMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the scrapper setting specified by the input string
|
||||||
|
*
|
||||||
|
* @param input <p>The input to check</p>
|
||||||
|
* @return <p>The matching scrapper setting, or null if not found</p>
|
||||||
|
*/
|
||||||
|
public static @Nullable ScrapperSetting getSetting(@NotNull String input) {
|
||||||
|
for (ScrapperSetting scrapperSetting : ScrapperSetting.values()) {
|
||||||
|
if (input.equalsIgnoreCase(scrapperSetting.getCommandName())) {
|
||||||
|
return scrapperSetting;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package net.knarcraft.blacksmith.container;
|
||||||
|
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.Recipe;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The result of a recipe's salvage
|
||||||
|
*
|
||||||
|
* @param recipe <p>The selected recipe</p>
|
||||||
|
* @param salvage <p>The resulting salvage</p>
|
||||||
|
*/
|
||||||
|
public record RecipeResult(@NotNull Recipe recipe, @NotNull List<ItemStack> salvage) {
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package net.knarcraft.blacksmith.container;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.property.SalvageMethod;
|
||||||
|
import net.knarcraft.blacksmith.property.SalvageState;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The result of an attempted salvage
|
||||||
|
*
|
||||||
|
* @param salvageMethod <p>The salvage method used</p>
|
||||||
|
* @param salvage <p>The produced salvage</p>
|
||||||
|
* @param salvageState <p>The state of the salvage result</p>
|
||||||
|
* @param requiredAmount <p>The amount of items required for the salvage</p>
|
||||||
|
*/
|
||||||
|
public record SalvageResult(@NotNull SalvageMethod salvageMethod, @NotNull List<ItemStack> salvage,
|
||||||
|
@NotNull SalvageState salvageState, int requiredAmount) {
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base class for all blacksmith plugin events
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public abstract class AbstractBlacksmithPluginEvent extends Event implements BlacksmithPluginEvent {
|
||||||
|
|
||||||
|
protected final NPC npc;
|
||||||
|
protected final Player player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new blacksmith plugin event
|
||||||
|
*
|
||||||
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param player <p>The player involved in the event</p>
|
||||||
|
*/
|
||||||
|
public AbstractBlacksmithPluginEvent(@NotNull NPC npc, @NotNull Player player) {
|
||||||
|
this.npc = npc;
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public NPC getNpc() {
|
||||||
|
return this.npc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public Player getPlayer() {
|
||||||
|
return this.player;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event triggered when a blacksmith or scrapper starts reforging or salvaging an item
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public interface ActionStartEvent extends BlacksmithPluginEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the amount of ticks this action will take
|
||||||
|
*
|
||||||
|
* @return <p>The duration in ticks</p>
|
||||||
|
*/
|
||||||
|
long getActionDurationTicks();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the appropriate crafting station for this action
|
||||||
|
*
|
||||||
|
* @return <p>The appropriate crafting station</p>
|
||||||
|
*/
|
||||||
|
Material getCraftingStation();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event triggered by the Blacksmith plugin
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public interface BlacksmithPluginEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the NPC involved in the event
|
||||||
|
*
|
||||||
|
* @return <p>The NPC</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
NPC getNpc();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the player involved in the event
|
||||||
|
*
|
||||||
|
* @return <p>The player</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
Player getPlayer();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event triggered when a blacksmith reforging fails
|
||||||
|
*/
|
||||||
|
public class BlacksmithReforgeFailEvent extends AbstractBlacksmithPluginEvent implements ReforgeEndEvent {
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new blacksmith reforge fail event
|
||||||
|
*
|
||||||
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
*/
|
||||||
|
public BlacksmithReforgeFailEvent(@NotNull NPC npc, @NotNull Player player) {
|
||||||
|
super(npc, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a handler-list containing all event handlers
|
||||||
|
*
|
||||||
|
* @return <p>A handler-list with all event handlers</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event triggered when a blacksmith reforging starts
|
||||||
|
*/
|
||||||
|
public class BlacksmithReforgeStartEvent extends AbstractBlacksmithPluginEvent implements ActionStartEvent {
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
private final long durationTicks;
|
||||||
|
private final Material craftingStation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new blacksmith reforge start event
|
||||||
|
*
|
||||||
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param player <p>The player involved in the event</p>
|
||||||
|
* @param durationTicks <p>The duration of the reforge</p>
|
||||||
|
* @param craftingStation <p>The appropriate crafting station for this reforging</p>
|
||||||
|
*/
|
||||||
|
public BlacksmithReforgeStartEvent(@NotNull NPC npc, @NotNull Player player, long durationTicks,
|
||||||
|
@NotNull Material craftingStation) {
|
||||||
|
super(npc, player);
|
||||||
|
this.durationTicks = durationTicks;
|
||||||
|
this.craftingStation = craftingStation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getActionDurationTicks() {
|
||||||
|
return durationTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Material getCraftingStation() {
|
||||||
|
return craftingStation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a handler-list containing all event handlers
|
||||||
|
*
|
||||||
|
* @return <p>A handler-list with all event handlers</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event triggered when a blacksmith reforging succeeds
|
||||||
|
*/
|
||||||
|
public class BlacksmithReforgeSucceedEvent extends AbstractBlacksmithPluginEvent implements ReforgeEndEvent {
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new blacksmith reforge succeed event
|
||||||
|
*
|
||||||
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param player <p>The player involved in the event</p>
|
||||||
|
*/
|
||||||
|
public BlacksmithReforgeSucceedEvent(@NotNull NPC npc, @NotNull Player player) {
|
||||||
|
super(npc, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a handler-list containing all event handlers
|
||||||
|
*
|
||||||
|
* @return <p>A handler-list with all event handlers</p>
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@NotNull
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
142
src/main/java/net/knarcraft/blacksmith/event/NPCSoundEvent.java
Normal file
142
src/main/java/net/knarcraft/blacksmith/event/NPCSoundEvent.java
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.SoundCategory;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Cancellable;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event triggered when an NPC plays a sound indicating an action
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class NPCSoundEvent extends AbstractBlacksmithPluginEvent implements Cancellable {
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
private boolean cancelled;
|
||||||
|
private float pitch;
|
||||||
|
private float volume;
|
||||||
|
private SoundCategory soundCategory;
|
||||||
|
private Sound sound;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new NPC sound event
|
||||||
|
*
|
||||||
|
* @param npc <p>The NPC playing the sound</p>
|
||||||
|
* @param player <p>The player whose interaction triggered the sound</p>
|
||||||
|
* @param soundCategory <p>The category the sound is to play in</p>
|
||||||
|
* @param sound <p>The sound to play</p>
|
||||||
|
* @param volume <p>The volume of the played sound</p>
|
||||||
|
* @param pitch <p>The pitch of the played sound</p>
|
||||||
|
*/
|
||||||
|
public NPCSoundEvent(@NotNull NPC npc, @NotNull Player player, @NotNull SoundCategory soundCategory,
|
||||||
|
@NotNull Sound sound, float volume, float pitch) {
|
||||||
|
super(npc, player);
|
||||||
|
this.soundCategory = soundCategory;
|
||||||
|
this.sound = sound;
|
||||||
|
this.volume = volume;
|
||||||
|
this.pitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the pitch of the played sound
|
||||||
|
*
|
||||||
|
* @return <p>The pitch of the played sound</p>
|
||||||
|
*/
|
||||||
|
public float getPitch() {
|
||||||
|
return this.pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the volume of the played sound
|
||||||
|
*
|
||||||
|
* @return <p>The volume of the played sound</p>
|
||||||
|
*/
|
||||||
|
public float getVolume() {
|
||||||
|
return this.volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the category the sound is played in
|
||||||
|
*
|
||||||
|
* @return <p>The sound category used</p>
|
||||||
|
*/
|
||||||
|
public @NotNull SoundCategory getSoundCategory() {
|
||||||
|
return this.soundCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the sound to play
|
||||||
|
*
|
||||||
|
* @return <p>The sound to play</p>
|
||||||
|
*/
|
||||||
|
public @NotNull Sound getSound() {
|
||||||
|
return this.sound;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the pitch of the played sound
|
||||||
|
*
|
||||||
|
* @param pitch <p>The new pitch</p>
|
||||||
|
*/
|
||||||
|
public void setPitch(float pitch) {
|
||||||
|
this.pitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the volume of the played sound
|
||||||
|
*
|
||||||
|
* @param volume <p>The new volume</p>
|
||||||
|
*/
|
||||||
|
public void setVolume(float volume) {
|
||||||
|
this.volume = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the sound to play
|
||||||
|
*
|
||||||
|
* @param sound <p>The new sound to play</p>
|
||||||
|
*/
|
||||||
|
public void setSound(@NotNull Sound sound) {
|
||||||
|
this.sound = sound;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the category the sound is played in
|
||||||
|
*
|
||||||
|
* @param soundCategory <p>The new sound category</p>
|
||||||
|
*/
|
||||||
|
public void setSoundCategory(@NotNull SoundCategory soundCategory) {
|
||||||
|
this.soundCategory = soundCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return this.cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCancelled(boolean cancelled) {
|
||||||
|
this.cancelled = cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a handler-list containing all event handlers
|
||||||
|
*
|
||||||
|
* @return <p>A handler-list with all event handlers</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event triggered when a reforge finishes
|
||||||
|
*/
|
||||||
|
public interface ReforgeEndEvent extends BlacksmithPluginEvent {
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event triggered when a salvaging finishes
|
||||||
|
*/
|
||||||
|
public interface SalvageEndEvent extends BlacksmithPluginEvent {
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event triggered when a scrapper salvaging fails
|
||||||
|
*/
|
||||||
|
public class ScrapperSalvageFailEvent extends AbstractBlacksmithPluginEvent implements SalvageEndEvent {
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new scrapper salvage fail event
|
||||||
|
*
|
||||||
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param player <p>The player involved in the event</p>
|
||||||
|
*/
|
||||||
|
public ScrapperSalvageFailEvent(@NotNull NPC npc, @NotNull Player player) {
|
||||||
|
super(npc, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a handler-list containing all event handlers
|
||||||
|
*
|
||||||
|
* @return <p>A handler-list with all event handlers</p>
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@NotNull
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event triggered when a scrapper salvaging starts
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class ScrapperSalvageStartEvent extends AbstractBlacksmithPluginEvent implements ActionStartEvent {
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
private final long durationTicks;
|
||||||
|
private final Material craftingStation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new scrapper salvage start event
|
||||||
|
*
|
||||||
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param player <p>The player involved in the event</p>
|
||||||
|
* @param durationTicks <p>The duration of the salvage</p>
|
||||||
|
* @param craftingStation <p>The appropriate crafting station for this salvaging</p>
|
||||||
|
*/
|
||||||
|
public ScrapperSalvageStartEvent(@NotNull NPC npc, @NotNull Player player, long durationTicks,
|
||||||
|
@NotNull Material craftingStation) {
|
||||||
|
super(npc, player);
|
||||||
|
this.durationTicks = durationTicks;
|
||||||
|
this.craftingStation = craftingStation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getActionDurationTicks() {
|
||||||
|
return this.durationTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Material getCraftingStation() {
|
||||||
|
return this.craftingStation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a handler-list containing all event handlers
|
||||||
|
*
|
||||||
|
* @return <p>A handler-list with all event handlers</p>
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@NotNull
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event triggered when a scrapper salvaging succeeds
|
||||||
|
*/
|
||||||
|
public class ScrapperSalvageSucceedEvent extends AbstractBlacksmithPluginEvent implements SalvageEndEvent {
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new scrapper salvage succeed event
|
||||||
|
*
|
||||||
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param player <p>The player involved in the event</p>
|
||||||
|
*/
|
||||||
|
public ScrapperSalvageSucceedEvent(@NotNull NPC npc, @NotNull Player player) {
|
||||||
|
super(npc, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a handler-list containing all event handlers
|
||||||
|
*
|
||||||
|
* @return <p>A handler-list with all event handlers</p>
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@NotNull
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package net.knarcraft.blacksmith.formatting;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.knarlib.property.ColorConversion;
|
||||||
|
import net.knarcraft.knarlib.util.ColorHelper;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A formatter for formatting displayed messages
|
||||||
|
*/
|
||||||
|
public final class BlacksmithStringFormatter {
|
||||||
|
|
||||||
|
private BlacksmithStringFormatter() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a message from a blacksmith NPC to a player
|
||||||
|
*
|
||||||
|
* @param npc <p>The NPC sending the message</p>
|
||||||
|
* @param player <p>The player to send the message to</p>
|
||||||
|
* @param message <p>The message to send</p>
|
||||||
|
*/
|
||||||
|
public static void sendNPCMessage(NPC npc, Player player, String message) {
|
||||||
|
player.sendMessage(BlacksmithPlugin.getStringFormatter().replacePlaceholders(
|
||||||
|
BlacksmithTranslatableMessage.NPC_TALK_FORMAT, List.of("{npc}", "{message}"),
|
||||||
|
List.of(npc.getName(), ColorHelper.translateColorCodes(message, ColorConversion.RGB))));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,11 @@
|
|||||||
package net.knarcraft.blacksmith.formatting;
|
package net.knarcraft.blacksmith.formatting;
|
||||||
|
|
||||||
import static net.knarcraft.blacksmith.formatting.StringFormatter.replacePlaceholders;
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.knarlib.formatting.StringReplacer;
|
||||||
|
import net.knarcraft.knarlib.formatting.TranslatableMessage;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An enum containing all translatable global messages
|
* An enum containing all translatable global messages
|
||||||
@ -8,7 +13,7 @@ import static net.knarcraft.blacksmith.formatting.StringFormatter.replacePlaceho
|
|||||||
* <p>This does not include NPC messages as they are configurable per-npc, and can be translated by changing the
|
* <p>This does not include NPC messages as they are configurable per-npc, and can be translated by changing the
|
||||||
* default message values in the main config file.</p>
|
* default message values in the main config file.</p>
|
||||||
*/
|
*/
|
||||||
public enum TranslatableMessage {
|
public enum BlacksmithTranslatableMessage implements TranslatableMessage {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message displayed when a configuration value has been successfully changed
|
* The message displayed when a configuration value has been successfully changed
|
||||||
@ -25,6 +30,11 @@ public enum TranslatableMessage {
|
|||||||
*/
|
*/
|
||||||
CURRENT_VALUE,
|
CURRENT_VALUE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when showing the default value of a configuration option
|
||||||
|
*/
|
||||||
|
DEFAULT_VALUE,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message displayed when showing the current value of a configuration option for one material or enchantment
|
* The message displayed when showing the current value of a configuration option for one material or enchantment
|
||||||
*/
|
*/
|
||||||
@ -50,11 +60,6 @@ public enum TranslatableMessage {
|
|||||||
*/
|
*/
|
||||||
NO_NPC_SELECTED,
|
NO_NPC_SELECTED,
|
||||||
|
|
||||||
/**
|
|
||||||
* The message displayed if trying to change the default value of reforge-able item using commands
|
|
||||||
*/
|
|
||||||
DEFAULT_REFORGE_ABLE_ITEMS_UNCHANGEABLE,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message displayed if a string list is required, but something else is given
|
* The message displayed if a string list is required, but something else is given
|
||||||
*/
|
*/
|
||||||
@ -105,36 +110,6 @@ public enum TranslatableMessage {
|
|||||||
*/
|
*/
|
||||||
PRESET_MATERIALS,
|
PRESET_MATERIALS,
|
||||||
|
|
||||||
/**
|
|
||||||
* The format for displaying the exact duration of a blacksmith's cool-down or delay
|
|
||||||
*/
|
|
||||||
DURATION_FORMAT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The text to display for 0 seconds
|
|
||||||
*/
|
|
||||||
UNIT_NOW,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The text to display for 1 second
|
|
||||||
*/
|
|
||||||
UNIT_SECOND,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The text to display for a number of seconds
|
|
||||||
*/
|
|
||||||
UNIT_SECONDS,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The text to display for 1 minute
|
|
||||||
*/
|
|
||||||
UNIT_MINUTE,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The text to display for a number of minutes
|
|
||||||
*/
|
|
||||||
UNIT_MINUTES,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The text to display when describing less than 10 seconds remaining
|
* The text to display when describing less than 10 seconds remaining
|
||||||
*/
|
*/
|
||||||
@ -163,7 +138,12 @@ public enum TranslatableMessage {
|
|||||||
/**
|
/**
|
||||||
* The marker used for displaying that a given setting has been overridden for the selected NPC
|
* The marker used for displaying that a given setting has been overridden for the selected NPC
|
||||||
*/
|
*/
|
||||||
SETTING_OVERRIDDEN_MARKER;
|
SETTING_OVERRIDDEN_MARKER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The format to use for formatting any message spoken by a blacksmith NPC
|
||||||
|
*/
|
||||||
|
NPC_TALK_FORMAT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the message to display when displaying the raw value of messages
|
* Gets the message to display when displaying the raw value of messages
|
||||||
@ -171,8 +151,9 @@ public enum TranslatableMessage {
|
|||||||
* @param rawValue <p>The raw value to display</p>
|
* @param rawValue <p>The raw value to display</p>
|
||||||
* @return <p>The message to display</p>
|
* @return <p>The message to display</p>
|
||||||
*/
|
*/
|
||||||
public static String getRawValueMessage(String rawValue) {
|
@NotNull
|
||||||
return StringFormatter.replacePlaceholder(Translator.getTranslatedMessage(TranslatableMessage.RAW_VALUE),
|
public static String getRawValueMessage(@NotNull String rawValue) {
|
||||||
|
return BlacksmithPlugin.getStringFormatter().replacePlaceholder(BlacksmithTranslatableMessage.RAW_VALUE,
|
||||||
"{rawValue}", rawValue);
|
"{rawValue}", rawValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,9 +164,10 @@ public enum TranslatableMessage {
|
|||||||
* @param newValue <p>The new value of the setting</p>
|
* @param newValue <p>The new value of the setting</p>
|
||||||
* @return <p>The string to display to a user</p>
|
* @return <p>The string to display to a user</p>
|
||||||
*/
|
*/
|
||||||
public static String getValueChangedMessage(String setting, String newValue) {
|
@NotNull
|
||||||
return replacePlaceholders(Translator.getTranslatedMessage(TranslatableMessage.VALUE_CHANGED),
|
public static String getValueChangedMessage(@NotNull String setting, @NotNull String newValue) {
|
||||||
new String[]{"{setting}", "{newValue}"}, new String[]{setting, newValue});
|
return BlacksmithPlugin.getStringFormatter().replacePlaceholders(BlacksmithTranslatableMessage.VALUE_CHANGED,
|
||||||
|
List.of("{setting}", "{newValue}"), List.of(setting, newValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -197,10 +179,30 @@ public enum TranslatableMessage {
|
|||||||
* @param newValue <p>The new value of the setting</p>
|
* @param newValue <p>The new value of the setting</p>
|
||||||
* @return <p>The string to display to a user</p>
|
* @return <p>The string to display to a user</p>
|
||||||
*/
|
*/
|
||||||
public static String getItemValueChangedMessage(String setting, ItemType itemType, String item, String newValue) {
|
@NotNull
|
||||||
return replacePlaceholders(Translator.getTranslatedMessage(TranslatableMessage.VALUE_FOR_ITEM_CHANGED),
|
public static String getItemValueChangedMessage(@NotNull String setting, @NotNull ItemType itemType,
|
||||||
new String[]{"{setting}", "{itemType}", "{item}", "{newValue}"},
|
@NotNull String item, @NotNull String newValue) {
|
||||||
new String[]{setting, itemType.getItemTypeName(), item, newValue});
|
StringReplacer stringReplacer = new StringReplacer(BlacksmithPlugin.getStringFormatter().getUnFormattedMessage(
|
||||||
|
BlacksmithTranslatableMessage.VALUE_FOR_ITEM_CHANGED));
|
||||||
|
stringReplacer.add("{setting}", setting);
|
||||||
|
stringReplacer.add("{itemType}", itemType.getItemTypeName());
|
||||||
|
stringReplacer.add("{item}", item);
|
||||||
|
stringReplacer.add("{newValue}", newValue);
|
||||||
|
return stringReplacer.replace();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when displaying a setting's default value
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting whose value is shown</p>
|
||||||
|
* @param defaultValue <p>The default value of the setting</p>
|
||||||
|
* @return <p>The string to display to a user</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public static String getDefaultValueMessage(@NotNull String setting, @NotNull String defaultValue) {
|
||||||
|
return BlacksmithPlugin.getStringFormatter().replacePlaceholders(BlacksmithTranslatableMessage.DEFAULT_VALUE,
|
||||||
|
List.of("{setting}", "{defaultValue}"),
|
||||||
|
List.of(setting, defaultValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -210,9 +212,11 @@ public enum TranslatableMessage {
|
|||||||
* @param currentValue <p>The current value of the setting</p>
|
* @param currentValue <p>The current value of the setting</p>
|
||||||
* @return <p>The string to display to a user</p>
|
* @return <p>The string to display to a user</p>
|
||||||
*/
|
*/
|
||||||
public static String getCurrentValueMessage(String setting, String currentValue) {
|
@NotNull
|
||||||
return replacePlaceholders(Translator.getTranslatedMessage(TranslatableMessage.CURRENT_VALUE),
|
public static String getCurrentValueMessage(@NotNull String setting, @NotNull String currentValue) {
|
||||||
new String[]{"{setting}", "{currentValue}"}, new String[]{setting, currentValue});
|
return BlacksmithPlugin.getStringFormatter().replacePlaceholders(BlacksmithTranslatableMessage.CURRENT_VALUE,
|
||||||
|
List.of("{setting}", "{currentValue}"),
|
||||||
|
List.of(setting, currentValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -224,10 +228,22 @@ public enum TranslatableMessage {
|
|||||||
* @param currentValue <p>The current value of the setting</p>
|
* @param currentValue <p>The current value of the setting</p>
|
||||||
* @return <p>The string to display to a user</p>
|
* @return <p>The string to display to a user</p>
|
||||||
*/
|
*/
|
||||||
public static String getItemCurrentValueMessage(String setting, ItemType itemType, String item, String currentValue) {
|
@NotNull
|
||||||
return replacePlaceholders(Translator.getTranslatedMessage(TranslatableMessage.CURRENT_VALUE_FOR_ITEM),
|
public static String getItemCurrentValueMessage(@NotNull String setting, @NotNull ItemType itemType,
|
||||||
new String[]{"{setting}", "{itemType}", "{item}", "{currentValue}"},
|
@NotNull String item, @NotNull String currentValue) {
|
||||||
new String[]{setting, itemType.getItemTypeName(), item, currentValue});
|
StringReplacer stringReplacer = new StringReplacer(BlacksmithPlugin.getStringFormatter().getUnFormattedMessage(
|
||||||
|
BlacksmithTranslatableMessage.CURRENT_VALUE_FOR_ITEM));
|
||||||
|
stringReplacer.add("{setting}", setting);
|
||||||
|
stringReplacer.add("{itemType}", itemType.getItemTypeName());
|
||||||
|
stringReplacer.add("{item}", item);
|
||||||
|
stringReplacer.add("{currentValue}", currentValue);
|
||||||
|
return stringReplacer.replace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public TranslatableMessage[] getAllMessages() {
|
||||||
|
return BlacksmithTranslatableMessage.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,5 +1,8 @@
|
|||||||
package net.knarcraft.blacksmith.formatting;
|
package net.knarcraft.blacksmith.formatting;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.knarlib.formatting.StringFormatter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An enum representing all item types used in messages
|
* An enum representing all item types used in messages
|
||||||
*/
|
*/
|
||||||
@ -14,9 +17,11 @@ public enum ItemType {
|
|||||||
* @return <p>The name of this item type</p>
|
* @return <p>The name of this item type</p>
|
||||||
*/
|
*/
|
||||||
public String getItemTypeName() {
|
public String getItemTypeName() {
|
||||||
|
StringFormatter stringFormatter = BlacksmithPlugin.getStringFormatter();
|
||||||
return switch (this) {
|
return switch (this) {
|
||||||
case MATERIAL -> Translator.getTranslatedMessage(TranslatableMessage.ITEM_TYPE_MATERIAL);
|
case MATERIAL -> stringFormatter.getUnFormattedMessage(BlacksmithTranslatableMessage.ITEM_TYPE_MATERIAL);
|
||||||
case ENCHANTMENT -> Translator.getTranslatedMessage(TranslatableMessage.ITEM_TYPE_ENCHANTMENT);
|
case ENCHANTMENT ->
|
||||||
|
stringFormatter.getUnFormattedMessage(BlacksmithTranslatableMessage.ITEM_TYPE_ENCHANTMENT);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,128 +0,0 @@
|
|||||||
package net.knarcraft.blacksmith.formatting;
|
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
|
||||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A formatter for formatting displayed messages
|
|
||||||
*/
|
|
||||||
public final class StringFormatter {
|
|
||||||
|
|
||||||
private final static String pluginName = BlacksmithPlugin.getInstance().getDescription().getName();
|
|
||||||
|
|
||||||
private StringFormatter() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a message from a blacksmith NPC to a player
|
|
||||||
*
|
|
||||||
* @param npc <p>The NPC sending the message</p>
|
|
||||||
* @param player <p>The player to send the message to</p>
|
|
||||||
* @param message <p>The message to send</p>
|
|
||||||
*/
|
|
||||||
public static void sendNPCMessage(NPC npc, Player player, String message) {
|
|
||||||
player.sendMessage(ChatColor.GREEN + "[" + npc.getName() + "] -> You:" + ChatColor.RESET + " " +
|
|
||||||
translateColors(message));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays a message signifying a successful action
|
|
||||||
*
|
|
||||||
* @param sender <p>The command sender to display the message to</p>
|
|
||||||
* @param message <p>The translatable message to display</p>
|
|
||||||
*/
|
|
||||||
public static void displaySuccessMessage(CommandSender sender, TranslatableMessage message) {
|
|
||||||
sender.sendMessage(ChatColor.GREEN + getFormattedMessage(Translator.getTranslatedMessage(message)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays a message signifying a successful action
|
|
||||||
*
|
|
||||||
* @param sender <p>The command sender to display the message to</p>
|
|
||||||
* @param message <p>The raw message to display</p>
|
|
||||||
*/
|
|
||||||
public static void displaySuccessMessage(CommandSender sender, String message) {
|
|
||||||
sender.sendMessage(ChatColor.GREEN + getFormattedMessage(message));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays a message signifying an unsuccessful action
|
|
||||||
*
|
|
||||||
* @param sender <p>The command sender to display the message to</p>
|
|
||||||
* @param message <p>The translatable message to display</p>
|
|
||||||
*/
|
|
||||||
public static void displayErrorMessage(CommandSender sender, TranslatableMessage message) {
|
|
||||||
sender.sendMessage(ChatColor.DARK_RED + getFormattedMessage(Translator.getTranslatedMessage(message)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the formatted version of any chat message
|
|
||||||
*
|
|
||||||
* @param message <p>The message to format</p>
|
|
||||||
* @return <p>The formatted message</p>
|
|
||||||
*/
|
|
||||||
private static String getFormattedMessage(String message) {
|
|
||||||
return "[" + pluginName + "] " + ChatColor.RESET + translateColors(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translates & color codes to proper colors
|
|
||||||
*
|
|
||||||
* @param input <p>The input string to translate colors for</p>
|
|
||||||
* @return <p>The input with color codes translated</p>
|
|
||||||
*/
|
|
||||||
private static String translateColors(String input) {
|
|
||||||
return ChatColor.translateAlternateColorCodes('&', input);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replaces a placeholder in a string
|
|
||||||
*
|
|
||||||
* @param input <p>The input string to replace in</p>
|
|
||||||
* @param placeholder <p>The placeholder to replace</p>
|
|
||||||
* @param replacement <p>The replacement value</p>
|
|
||||||
* @return <p>The input string with the placeholder replaced</p>
|
|
||||||
*/
|
|
||||||
public static String replacePlaceholder(String input, String placeholder, String replacement) {
|
|
||||||
return input.replace(placeholder, replacement);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replaces placeholders in a string
|
|
||||||
*
|
|
||||||
* @param input <p>The input string to replace in</p>
|
|
||||||
* @param placeholders <p>The placeholders to replace</p>
|
|
||||||
* @param replacements <p>The replacement values</p>
|
|
||||||
* @return <p>The input string with placeholders replaced</p>
|
|
||||||
*/
|
|
||||||
public static String replacePlaceholders(String input, String[] placeholders, String[] replacements) {
|
|
||||||
for (int i = 0; i < Math.min(placeholders.length, replacements.length); i++) {
|
|
||||||
input = replacePlaceholder(input, placeholders[i], replacements[i]);
|
|
||||||
}
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translates all found color codes to formatting in a string
|
|
||||||
*
|
|
||||||
* @param message <p>The string to search for color codes</p>
|
|
||||||
* @return <p>The message with color codes translated</p>
|
|
||||||
*/
|
|
||||||
public static String translateAllColorCodes(String message) {
|
|
||||||
message = ChatColor.translateAlternateColorCodes('&', message);
|
|
||||||
Pattern pattern = Pattern.compile("(#[a-fA-F0-9]{6})");
|
|
||||||
Matcher matcher = pattern.matcher(message);
|
|
||||||
while (matcher.find()) {
|
|
||||||
message = message.replace(matcher.group(), "" + ChatColor.of(matcher.group()));
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,23 +1,16 @@
|
|||||||
package net.knarcraft.blacksmith.formatting;
|
package net.knarcraft.blacksmith.formatting;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import static net.knarcraft.blacksmith.formatting.StringFormatter.replacePlaceholder;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility for formatting a string specifying an amount of time
|
* A utility for formatting a string specifying an amount of time
|
||||||
*/
|
*/
|
||||||
public final class TimeFormatter {
|
public final class TimeFormatter {
|
||||||
|
|
||||||
private static Map<Double, TranslatableMessage[]> timeUnits;
|
|
||||||
private static List<Double> sortedUnits;
|
|
||||||
|
|
||||||
private TimeFormatter() {
|
private TimeFormatter() {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -31,7 +24,7 @@ public final class TimeFormatter {
|
|||||||
*/
|
*/
|
||||||
public static String formatTime(boolean exact, int seconds) {
|
public static String formatTime(boolean exact, int seconds) {
|
||||||
if (exact) {
|
if (exact) {
|
||||||
return getDurationString(seconds);
|
return net.knarcraft.knarlib.formatting.TimeFormatter.getDurationString(BlacksmithPlugin.getTranslator(), seconds);
|
||||||
} else {
|
} else {
|
||||||
return formatUnclearTime(seconds);
|
return formatUnclearTime(seconds);
|
||||||
}
|
}
|
||||||
@ -60,10 +53,11 @@ public final class TimeFormatter {
|
|||||||
* @return <p>Text describing the time interval</p>
|
* @return <p>Text describing the time interval</p>
|
||||||
*/
|
*/
|
||||||
private static String getMessageFromInterval(TimeInterval interval) {
|
private static String getMessageFromInterval(TimeInterval interval) {
|
||||||
String text = Translator.getTranslatedMessage(TranslatableMessage.valueOf(interval.name()));
|
String text = BlacksmithPlugin.getStringFormatter().getUnFormattedMessage(
|
||||||
|
BlacksmithTranslatableMessage.valueOf(interval.name()));
|
||||||
|
|
||||||
//Choose a random entry if a comma-separated list is provided
|
//Choose a random entry if a comma-separated list is provided
|
||||||
if (text != null && text.contains(",")) {
|
if (text.contains(",")) {
|
||||||
String[] parts = text.split(",");
|
String[] parts = text.split(",");
|
||||||
String randomPart = parts[new Random().nextInt(parts.length)];
|
String randomPart = parts[new Random().nextInt(parts.length)];
|
||||||
if (randomPart != null) {
|
if (randomPart != null) {
|
||||||
@ -72,75 +66,11 @@ public final class TimeFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Use the set message, or use the default
|
//Use the set message, or use the default
|
||||||
if (text != null && !text.trim().isEmpty()) {
|
if (!text.trim().isEmpty()) {
|
||||||
return text;
|
return text;
|
||||||
} else {
|
} else {
|
||||||
return interval.getDefaultText();
|
return interval.getDefaultText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the string used for displaying this sign's duration
|
|
||||||
*
|
|
||||||
* @return <p>The string used for displaying this sign's duration</p>
|
|
||||||
*/
|
|
||||||
public static String getDurationString(int duration) {
|
|
||||||
if (duration == 0) {
|
|
||||||
return Translator.getTranslatedMessage(TranslatableMessage.UNIT_NOW);
|
|
||||||
} else {
|
|
||||||
if (sortedUnits == null) {
|
|
||||||
initializeUnits();
|
|
||||||
}
|
|
||||||
for (Double unit : sortedUnits) {
|
|
||||||
if (duration / unit >= 1) {
|
|
||||||
double units = round(duration / unit);
|
|
||||||
return formatDurationString(units, timeUnits.get(unit)[units == 1 ? 0 : 1],
|
|
||||||
(units * 10) % 10 == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return formatDurationString(duration, TranslatableMessage.UNIT_SECONDS, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rounds a number to its last two digits
|
|
||||||
*
|
|
||||||
* @param number <p>The number to round</p>
|
|
||||||
* @return <p>The rounded number</p>
|
|
||||||
*/
|
|
||||||
private static double round(double number) {
|
|
||||||
return Math.round(number * 100.0) / 100.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats a duration string
|
|
||||||
*
|
|
||||||
* @param duration <p>The duration to display</p>
|
|
||||||
* @param translatableMessage <p>The time unit to display</p>
|
|
||||||
* @param castToInt <p>Whether to cast the duration to an int</p>
|
|
||||||
* @return <p>The formatted duration string</p>
|
|
||||||
*/
|
|
||||||
private static String formatDurationString(double duration, TranslatableMessage translatableMessage, boolean castToInt) {
|
|
||||||
String durationFormat = Translator.getTranslatedMessage(TranslatableMessage.DURATION_FORMAT);
|
|
||||||
durationFormat = replacePlaceholder(durationFormat, "{unit}",
|
|
||||||
Translator.getTranslatedMessage(translatableMessage));
|
|
||||||
return replacePlaceholder(durationFormat, "{time}", castToInt ? String.valueOf((int) duration) :
|
|
||||||
String.valueOf(duration));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the mapping of available time units for formatting permission sign duration
|
|
||||||
*/
|
|
||||||
private static void initializeUnits() {
|
|
||||||
double minute = 60;
|
|
||||||
|
|
||||||
timeUnits = new HashMap<>();
|
|
||||||
timeUnits.put(minute, new TranslatableMessage[]{TranslatableMessage.UNIT_MINUTE, TranslatableMessage.UNIT_MINUTES});
|
|
||||||
timeUnits.put(1D, new TranslatableMessage[]{TranslatableMessage.UNIT_SECOND, TranslatableMessage.UNIT_SECONDS});
|
|
||||||
|
|
||||||
sortedUnits = new ArrayList<>(timeUnits.keySet());
|
|
||||||
Collections.sort(sortedUnits);
|
|
||||||
Collections.reverse(sortedUnits);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,120 +0,0 @@
|
|||||||
package net.knarcraft.blacksmith.formatting;
|
|
||||||
|
|
||||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
|
||||||
import net.knarcraft.blacksmith.util.FileHelper;
|
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A tool to get strings translated to the correct language
|
|
||||||
*/
|
|
||||||
public final class Translator {
|
|
||||||
|
|
||||||
private static Map<TranslatableMessage, String> translatedMessages;
|
|
||||||
private static Map<TranslatableMessage, String> backupTranslatedMessages;
|
|
||||||
|
|
||||||
private Translator() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the languages used by this translator
|
|
||||||
*/
|
|
||||||
public static void loadLanguages(String selectedLanguage) {
|
|
||||||
backupTranslatedMessages = loadTranslatedMessages("en");
|
|
||||||
translatedMessages = loadCustomTranslatedMessages(selectedLanguage);
|
|
||||||
if (translatedMessages == null) {
|
|
||||||
translatedMessages = loadTranslatedMessages(selectedLanguage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a translated version of the given translatable message
|
|
||||||
*
|
|
||||||
* @param translatableMessage <p>The message to translate</p>
|
|
||||||
* @return <p>The translated message</p>
|
|
||||||
*/
|
|
||||||
public static String getTranslatedMessage(TranslatableMessage translatableMessage) {
|
|
||||||
if (translatedMessages == null) {
|
|
||||||
return "Translated strings not loaded";
|
|
||||||
}
|
|
||||||
String translatedMessage;
|
|
||||||
if (translatedMessages.containsKey(translatableMessage)) {
|
|
||||||
translatedMessage = translatedMessages.get(translatableMessage);
|
|
||||||
} else if (backupTranslatedMessages.containsKey(translatableMessage)) {
|
|
||||||
translatedMessage = backupTranslatedMessages.get(translatableMessage);
|
|
||||||
} else {
|
|
||||||
translatedMessage = translatableMessage.toString();
|
|
||||||
}
|
|
||||||
return StringFormatter.translateAllColorCodes(translatedMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads all translated messages for the given language
|
|
||||||
*
|
|
||||||
* @param language <p>The language chosen by the user</p>
|
|
||||||
* @return <p>A mapping of all strings for the given language</p>
|
|
||||||
*/
|
|
||||||
public static Map<TranslatableMessage, String> loadTranslatedMessages(String language) {
|
|
||||||
try {
|
|
||||||
BufferedReader reader = FileHelper.getBufferedReaderForInternalFile("/strings.yml");
|
|
||||||
return loadTranslatableMessages(language, reader);
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
BlacksmithPlugin.getInstance().getLogger().log(Level.SEVERE, "Unable to load translated messages");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to load translated messages from a custom strings.yml file
|
|
||||||
*
|
|
||||||
* @param language <p>The selected language</p>
|
|
||||||
* @return <p>The loaded translated strings, or null if no custom language file exists</p>
|
|
||||||
*/
|
|
||||||
public static Map<TranslatableMessage, String> loadCustomTranslatedMessages(String language) {
|
|
||||||
BlacksmithPlugin instance = BlacksmithPlugin.getInstance();
|
|
||||||
|
|
||||||
File strings = new File(instance.getDataFolder(), "strings.yml");
|
|
||||||
if (!strings.exists()) {
|
|
||||||
instance.getLogger().log(Level.FINEST, "Strings file not found");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
instance.getLogger().log(Level.INFO, "Loading custom strings...");
|
|
||||||
return loadTranslatableMessages(language, new BufferedReader(new InputStreamReader(new FileInputStream(strings))));
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
instance.getLogger().log(Level.WARNING, "Unable to load custom messages");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads translatable messages from the given reader
|
|
||||||
*
|
|
||||||
* @param language <p>The selected language</p>
|
|
||||||
* @param reader <p>The buffered reader to read from</p>
|
|
||||||
* @return <p>The loaded translated strings</p>
|
|
||||||
*/
|
|
||||||
private static Map<TranslatableMessage, String> loadTranslatableMessages(String language, BufferedReader reader) {
|
|
||||||
Map<TranslatableMessage, String> translatedMessages = new HashMap<>();
|
|
||||||
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(reader);
|
|
||||||
|
|
||||||
for (TranslatableMessage message : TranslatableMessage.values()) {
|
|
||||||
String translated = configuration.getString(language + "." + message.toString());
|
|
||||||
if (translated != null) {
|
|
||||||
translatedMessages.put(message, translated);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return translatedMessages;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,11 +1,16 @@
|
|||||||
package net.knarcraft.blacksmith.listener;
|
package net.knarcraft.blacksmith.listener;
|
||||||
|
|
||||||
import net.knarcraft.blacksmith.formatting.StringFormatter;
|
import net.citizensnpcs.api.event.NPCRightClickEvent;
|
||||||
import net.knarcraft.blacksmith.formatting.TranslatableMessage;
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
|
||||||
import net.knarcraft.blacksmith.trait.BlacksmithTrait;
|
import net.knarcraft.blacksmith.trait.BlacksmithTrait;
|
||||||
|
import net.knarcraft.blacksmith.trait.CustomTrait;
|
||||||
|
import net.knarcraft.blacksmith.trait.ScrapperTrait;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A listener for detecting and handling a Blacksmith being right-clicked
|
* A listener for detecting and handling a Blacksmith being right-clicked
|
||||||
@ -13,32 +18,47 @@ import org.bukkit.event.Listener;
|
|||||||
public class NPCClickListener implements Listener {
|
public class NPCClickListener implements Listener {
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onRightClick(net.citizensnpcs.api.event.NPCRightClickEvent event) {
|
public void onRightClick(@NotNull NPCRightClickEvent event) {
|
||||||
//We only care about blacksmiths
|
//We only care about blacksmiths and scrappers
|
||||||
if (!event.getNPC().hasTrait(BlacksmithTrait.class)) {
|
if (event.getNPC().hasTrait(BlacksmithTrait.class)) {
|
||||||
|
handleNPCClick(event, event.getNPC().getTraitNullable(BlacksmithTrait.class));
|
||||||
|
} else if (event.getNPC().hasTrait(ScrapperTrait.class)) {
|
||||||
|
handleNPCClick(event, event.getNPC().getTraitNullable(ScrapperTrait.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a player clicking on a blacksmith or a scrapper NPC
|
||||||
|
*
|
||||||
|
* @param event <p>The NPC click event performed</p>
|
||||||
|
* @param customTrait <p>The NPC's custom trait</p>
|
||||||
|
*/
|
||||||
|
private void handleNPCClick(@NotNull NPCRightClickEvent event, @Nullable CustomTrait<?> customTrait) {
|
||||||
|
if (customTrait == null) {
|
||||||
|
BlacksmithPlugin.warn("Could not get trait from NPC!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BlacksmithTrait blacksmithTrait = event.getNPC().getTraitNullable(BlacksmithTrait.class);
|
|
||||||
|
|
||||||
//Perform any necessary pre-session work
|
//Perform any necessary pre-session work
|
||||||
Player player = event.getClicker();
|
Player player = event.getClicker();
|
||||||
|
|
||||||
//Permission check
|
//Permission check
|
||||||
if (!player.hasPermission("blacksmith.use")) {
|
if (!player.hasPermission("blacksmith.use")) {
|
||||||
StringFormatter.displayErrorMessage(player, TranslatableMessage.PERMISSION_DENIED);
|
BlacksmithPlugin.getStringFormatter().displayErrorMessage(player,
|
||||||
|
BlacksmithTranslatableMessage.PERMISSION_DENIED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!blacksmithTrait.prepareForSession(player)) {
|
if (!customTrait.prepareForSession(player)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blacksmithTrait.hasSession()) {
|
if (customTrait.hasSession()) {
|
||||||
//Continue the existing session
|
//Continue the existing session
|
||||||
blacksmithTrait.continueSession(player);
|
customTrait.continueSession(player);
|
||||||
} else {
|
} else {
|
||||||
//Start a new session
|
//Start a new session
|
||||||
blacksmithTrait.startSession(player);
|
customTrait.startSession(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package net.knarcraft.blacksmith.listener;
|
package net.knarcraft.blacksmith.listener;
|
||||||
|
|
||||||
import net.citizensnpcs.api.CitizensAPI;
|
import net.citizensnpcs.api.CitizensAPI;
|
||||||
|
import net.citizensnpcs.api.npc.NPCRegistry;
|
||||||
import net.knarcraft.blacksmith.trait.BlacksmithTrait;
|
import net.knarcraft.blacksmith.trait.BlacksmithTrait;
|
||||||
|
import net.knarcraft.blacksmith.trait.ScrapperTrait;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.enchantments.EnchantmentTarget;
|
import org.bukkit.enchantments.EnchantmentTarget;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
@ -13,6 +15,8 @@ import org.bukkit.event.block.Action;
|
|||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public class PlayerListener implements Listener {
|
public class PlayerListener implements Listener {
|
||||||
|
|
||||||
@ -22,23 +26,24 @@ public class PlayerListener implements Listener {
|
|||||||
* @param event <p>The triggered event</p>
|
* @param event <p>The triggered event</p>
|
||||||
*/
|
*/
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
public void onClick(PlayerInteractEvent event) {
|
public void onClick(@NotNull PlayerInteractEvent event) {
|
||||||
if (event.getHand() == null || (event.getAction() != Action.RIGHT_CLICK_AIR && event.getAction() !=
|
if (event.getHand() == null || (event.getAction() != Action.RIGHT_CLICK_AIR && event.getAction() !=
|
||||||
Action.RIGHT_CLICK_BLOCK)) {
|
Action.RIGHT_CLICK_BLOCK)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//If the player is not looking at a blacksmith, there is no need to do anything
|
//If the player is not looking at a blacksmith or scrapper, there is no need to do anything
|
||||||
Entity target = getTarget(event.getPlayer(), event.getPlayer().getNearbyEntities(15, 10, 15));
|
Entity target = getTarget(event.getPlayer(), event.getPlayer().getNearbyEntities(15, 10, 15));
|
||||||
if (!CitizensAPI.getNPCRegistry().isNPC(target) ||
|
NPCRegistry registry = CitizensAPI.getNPCRegistry();
|
||||||
!CitizensAPI.getNPCRegistry().getNPC(target).hasTrait(BlacksmithTrait.class)) {
|
if (!registry.isNPC(target) ||
|
||||||
|
(!registry.getNPC(target).hasTrait(BlacksmithTrait.class) &&
|
||||||
|
!registry.getNPC(target).hasTrait(ScrapperTrait.class))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Block armor equip if interacting with a blacksmith
|
//Block armor equip if interacting with a blacksmith or a scrapper
|
||||||
ItemStack usedItem = event.getPlayer().getInventory().getItem(event.getHand());
|
ItemStack usedItem = event.getPlayer().getInventory().getItem(event.getHand());
|
||||||
if (usedItem != null && isArmor(usedItem)) {
|
if (usedItem != null && isArmor(usedItem)) {
|
||||||
event.setUseItemInHand(Event.Result.DENY);
|
event.setUseItemInHand(Event.Result.DENY);
|
||||||
event.getPlayer().updateInventory();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +53,7 @@ public class PlayerListener implements Listener {
|
|||||||
* @param item <p>The item to check if is armor or not</p>
|
* @param item <p>The item to check if is armor or not</p>
|
||||||
* @return <p>True if the given item is a type of armor</p>
|
* @return <p>True if the given item is a type of armor</p>
|
||||||
*/
|
*/
|
||||||
public static boolean isArmor(ItemStack item) {
|
public static boolean isArmor(@NotNull ItemStack item) {
|
||||||
return EnchantmentTarget.WEARABLE.includes(item) || item.getType() == Material.ELYTRA;
|
return EnchantmentTarget.WEARABLE.includes(item) || item.getType() == Material.ELYTRA;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +65,8 @@ public class PlayerListener implements Listener {
|
|||||||
* @param <T> <p>The type of entity the player is looking at</p>
|
* @param <T> <p>The type of entity the player is looking at</p>
|
||||||
* @return <p>The entity the player is looking at, or null if no such entity exists</p>
|
* @return <p>The entity the player is looking at, or null if no such entity exists</p>
|
||||||
*/
|
*/
|
||||||
private static <T extends Entity> T getTarget(final Entity entity, final Iterable<T> entities) {
|
@Nullable
|
||||||
|
private static <T extends Entity> T getTarget(final @Nullable Entity entity, final @NotNull Iterable<T> entities) {
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -68,8 +74,10 @@ public class PlayerListener implements Listener {
|
|||||||
final double threshold = 1;
|
final double threshold = 1;
|
||||||
for (final T other : entities) {
|
for (final T other : entities) {
|
||||||
final Vector n = other.getLocation().toVector().subtract(entity.getLocation().toVector());
|
final Vector n = other.getLocation().toVector().subtract(entity.getLocation().toVector());
|
||||||
|
|
||||||
if (entity.getLocation().getDirection().normalize().crossProduct(n).lengthSquared() < threshold &&
|
if (entity.getLocation().getDirection().normalize().crossProduct(n).lengthSquared() < threshold &&
|
||||||
n.normalize().dot(entity.getLocation().getDirection().normalize()) >= 0) {
|
n.normalize().dot(entity.getLocation().getDirection().normalize()) >= 0) {
|
||||||
|
// Replace if the other entity is nearer, or no target has been found
|
||||||
if (target == null ||
|
if (target == null ||
|
||||||
target.getLocation().distanceSquared(entity.getLocation()) >
|
target.getLocation().distanceSquared(entity.getLocation()) >
|
||||||
other.getLocation().distanceSquared(entity.getLocation())) {
|
other.getLocation().distanceSquared(entity.getLocation())) {
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package net.knarcraft.blacksmith.manager;
|
package net.knarcraft.blacksmith.manager;
|
||||||
|
|
||||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
import net.knarcraft.blacksmith.config.GlobalSettings;
|
import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSettings;
|
||||||
|
import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings;
|
||||||
|
import net.knarcraft.blacksmith.property.SalvageMethod;
|
||||||
import net.knarcraft.blacksmith.util.ItemHelper;
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
import net.milkbowl.vault.economy.Economy;
|
import net.milkbowl.vault.economy.Economy;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@ -10,9 +12,7 @@ import org.bukkit.entity.Player;
|
|||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||||
import org.bukkit.plugin.ServicesManager;
|
import org.bukkit.plugin.ServicesManager;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class which deals with everything economy
|
* A class which deals with everything economy
|
||||||
@ -29,25 +29,35 @@ public class EconomyManager {
|
|||||||
* Sets up Vault economy support
|
* Sets up Vault economy support
|
||||||
*
|
*
|
||||||
* @param servicesManager <p>The services manager to use for finding a Vault provider</p>
|
* @param servicesManager <p>The services manager to use for finding a Vault provider</p>
|
||||||
* @param logger <p>The logger to use for logging</p>
|
|
||||||
* @return <p>True if Vault was successfully set up</p>
|
* @return <p>True if Vault was successfully set up</p>
|
||||||
*/
|
*/
|
||||||
public static boolean setUp(ServicesManager servicesManager, Logger logger) {
|
public static boolean setUp(@NotNull ServicesManager servicesManager) {
|
||||||
//If already set up, there is nothing to do
|
//If already set up, there is nothing to do
|
||||||
if (economy != null) {
|
if (economy != null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return setupVault(servicesManager, logger);
|
return setupVault(servicesManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets whether the given player can pay for re-forging their held item
|
* Gets whether the given player cannot pay for re-forging their held item
|
||||||
*
|
*
|
||||||
* @param player <p>The player holding an item</p>
|
* @param player <p>The player holding an item</p>
|
||||||
* @return <p>Whether the player can pay for the reforge</p>
|
* @return <p>Whether the player cannot pay for the reforge</p>
|
||||||
*/
|
*/
|
||||||
public static boolean canPay(Player player) {
|
public static boolean cannotPayForHeldItemReforge(@NotNull Player player) {
|
||||||
return economy.getBalance(player) - getHeldItemCost(player) >= 0;
|
return economy.getBalance(player) - getHeldItemCost(player) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether the given player cannot pay for salvaging an item
|
||||||
|
*
|
||||||
|
* @param player <p>The player holding an item</p>
|
||||||
|
* @param salvageMethod <p>The salvage method to check</p>
|
||||||
|
* @return <p>Whether the player cannot pay for the salvage</p>
|
||||||
|
*/
|
||||||
|
public static boolean cannotPayForSalvage(@NotNull Player player, @NotNull SalvageMethod salvageMethod) {
|
||||||
|
return economy.getBalance(player) - getSalvageCost(salvageMethod) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,11 +66,38 @@ public class EconomyManager {
|
|||||||
* @param player <p>The player holding an item</p>
|
* @param player <p>The player holding an item</p>
|
||||||
* @return <p>The formatted cost</p>
|
* @return <p>The formatted cost</p>
|
||||||
*/
|
*/
|
||||||
public static String formatCost(Player player) {
|
@NotNull
|
||||||
|
public static String formatBlacksmithCost(@NotNull Player player) {
|
||||||
double cost = getHeldItemCost(player);
|
double cost = getHeldItemCost(player);
|
||||||
return economy.format(cost);
|
return economy.format(cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the human-readable cost of salvaging an item
|
||||||
|
*
|
||||||
|
* @param salvageMethod <p>The salvage method to get the cost for</p>
|
||||||
|
* @return <p>The formatted cost</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public static String formatSalvageCost(@NotNull SalvageMethod salvageMethod) {
|
||||||
|
return economy.format(getSalvageCost(salvageMethod));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cost of salvaging using the specified method
|
||||||
|
*
|
||||||
|
* @param salvageMethod <p>The salvage method to get cost for</p>
|
||||||
|
* @return <p>The salvage cost</p>
|
||||||
|
*/
|
||||||
|
private static double getSalvageCost(@NotNull SalvageMethod salvageMethod) {
|
||||||
|
GlobalScrapperSettings settings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings();
|
||||||
|
return switch (salvageMethod) {
|
||||||
|
case SALVAGE, EXTENDED_SALVAGE -> settings.getSalvageCost();
|
||||||
|
case NETHERITE -> settings.getNetheriteSalvageCost();
|
||||||
|
case ARMOR_TRIM -> settings.getArmorTrimSalvageCost();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Withdraws the reforging cost from the given player
|
* Withdraws the reforging cost from the given player
|
||||||
*
|
*
|
||||||
@ -68,8 +105,24 @@ public class EconomyManager {
|
|||||||
*
|
*
|
||||||
* @param player <p>The player to withdraw from</p>
|
* @param player <p>The player to withdraw from</p>
|
||||||
*/
|
*/
|
||||||
public static void withdraw(Player player) {
|
public static void withdrawBlacksmith(@NotNull Player player) {
|
||||||
economy.withdrawPlayer(player, getHeldItemCost(player));
|
double cost = getHeldItemCost(player);
|
||||||
|
if (cost > 0) {
|
||||||
|
economy.withdrawPlayer(player, cost);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Withdraws the salvaging cost from the given player
|
||||||
|
*
|
||||||
|
* @param player <p>The player to withdraw from</p>
|
||||||
|
* @param salvageMethod <p>The salvage method to withdraw for</p>
|
||||||
|
*/
|
||||||
|
public static void withdrawScrapper(@NotNull Player player, @NotNull SalvageMethod salvageMethod) {
|
||||||
|
double cost = getSalvageCost(salvageMethod);
|
||||||
|
if (cost > 0) {
|
||||||
|
economy.withdrawPlayer(player, cost);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,7 +131,7 @@ public class EconomyManager {
|
|||||||
* @param player <p>The player to calculate the cost for</p>
|
* @param player <p>The player to calculate the cost for</p>
|
||||||
* @return <p>The calculated cost</p>
|
* @return <p>The calculated cost</p>
|
||||||
*/
|
*/
|
||||||
private static double getHeldItemCost(Player player) {
|
private static double getHeldItemCost(@NotNull Player player) {
|
||||||
return getCost(player.getInventory().getItemInMainHand());
|
return getCost(player.getInventory().getItemInMainHand());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,15 +141,16 @@ public class EconomyManager {
|
|||||||
* @param item <p>The item to be repaired</p>
|
* @param item <p>The item to be repaired</p>
|
||||||
* @return <p>The cost of the repair</p>
|
* @return <p>The cost of the repair</p>
|
||||||
*/
|
*/
|
||||||
private static double getCost(ItemStack item) {
|
private static double getCost(@NotNull ItemStack item) {
|
||||||
GlobalSettings globalSettings = BlacksmithPlugin.getInstance().getSettings();
|
GlobalBlacksmithSettings globalBlacksmithSettings = BlacksmithPlugin.getInstance().getGlobalBlacksmithSettings();
|
||||||
Material material = item.getType();
|
Material material = item.getType();
|
||||||
|
|
||||||
//Calculate the base price
|
//Calculate the base price
|
||||||
double price = globalSettings.getBasePrice(material);
|
double price = globalBlacksmithSettings.getBasePrice(material);
|
||||||
|
|
||||||
// Adjust price based on durability
|
// Adjust price based on durability
|
||||||
double pricePerDurabilityPoint = globalSettings.getPricePerDurabilityPoint(material);
|
double pricePerDurabilityPoint = globalBlacksmithSettings.getPricePerDurabilityPoint(material);
|
||||||
if (globalSettings.getUseNaturalCost()) {
|
if (globalBlacksmithSettings.getUseNaturalCost()) {
|
||||||
//Cost increases with damage
|
//Cost increases with damage
|
||||||
price += ((double) ItemHelper.getDamage(item)) * pricePerDurabilityPoint;
|
price += ((double) ItemHelper.getDamage(item)) * pricePerDurabilityPoint;
|
||||||
} else {
|
} else {
|
||||||
@ -106,6 +160,11 @@ public class EconomyManager {
|
|||||||
|
|
||||||
//Increase price for any enchantments
|
//Increase price for any enchantments
|
||||||
price += getEnchantmentCost(item);
|
price += getEnchantmentCost(item);
|
||||||
|
|
||||||
|
//Override the cost for anvils
|
||||||
|
if (ItemHelper.isAnvil(material, true)) {
|
||||||
|
price = globalBlacksmithSettings.getAnvilCost(material);
|
||||||
|
}
|
||||||
return price;
|
return price;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,8 +174,8 @@ public class EconomyManager {
|
|||||||
* @param item <p>The item to calculate enchantment cost for</p>
|
* @param item <p>The item to calculate enchantment cost for</p>
|
||||||
* @return <p>The resulting enchantment cost</p>
|
* @return <p>The resulting enchantment cost</p>
|
||||||
*/
|
*/
|
||||||
private static double getEnchantmentCost(ItemStack item) {
|
private static double getEnchantmentCost(@NotNull ItemStack item) {
|
||||||
GlobalSettings settings = BlacksmithPlugin.getInstance().getSettings();
|
GlobalBlacksmithSettings settings = BlacksmithPlugin.getInstance().getGlobalBlacksmithSettings();
|
||||||
double price = 0;
|
double price = 0;
|
||||||
for (Enchantment enchantment : item.getEnchantments().keySet()) {
|
for (Enchantment enchantment : item.getEnchantments().keySet()) {
|
||||||
price += settings.getEnchantmentCost(enchantment) * item.getEnchantmentLevel(enchantment);
|
price += settings.getEnchantmentCost(enchantment) * item.getEnchantmentLevel(enchantment);
|
||||||
@ -128,10 +187,9 @@ public class EconomyManager {
|
|||||||
* Sets up Vault for economy
|
* Sets up Vault for economy
|
||||||
*
|
*
|
||||||
* @param servicesManager <p>The services manager to use for finding a Vault provider</p>
|
* @param servicesManager <p>The services manager to use for finding a Vault provider</p>
|
||||||
* @param logger <p>The logger to use for logging</p>
|
|
||||||
* @return <p>True if Vault was successfully set up</p>
|
* @return <p>True if Vault was successfully set up</p>
|
||||||
*/
|
*/
|
||||||
private static boolean setupVault(ServicesManager servicesManager, Logger logger) {
|
private static boolean setupVault(@NotNull ServicesManager servicesManager) {
|
||||||
// Setup Vault
|
// Setup Vault
|
||||||
RegisteredServiceProvider<Economy> economyProvider = servicesManager.getRegistration(Economy.class);
|
RegisteredServiceProvider<Economy> economyProvider = servicesManager.getRegistration(Economy.class);
|
||||||
if (economyProvider != null) {
|
if (economyProvider != null) {
|
||||||
@ -139,7 +197,7 @@ public class EconomyManager {
|
|||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// Disable if no economy plugin was found
|
// Disable if no economy plugin was found
|
||||||
logger.log(Level.SEVERE, "Failed to load an economy plugin. Disabling...");
|
BlacksmithPlugin.error("Failed to load an economy plugin. Disabling...");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
package net.knarcraft.blacksmith.property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A representation of the different ways an item can be salvaged
|
||||||
|
*/
|
||||||
|
public enum SalvageMethod {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Salvaging the item normally by returning the item's crafting recipe
|
||||||
|
*/
|
||||||
|
SALVAGE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Salvaging unrepairable items normally by returning the item's crafting recipe, but with unrestricted
|
||||||
|
*/
|
||||||
|
EXTENDED_SALVAGE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removing the armor trim from an item
|
||||||
|
*/
|
||||||
|
ARMOR_TRIM,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Un-doing netherite application for an item
|
||||||
|
*/
|
||||||
|
NETHERITE,
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package net.knarcraft.blacksmith.property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The state of trying to find salvage for an item
|
||||||
|
*/
|
||||||
|
public enum SalvageState {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Found useful salvage that can be given to a player
|
||||||
|
*/
|
||||||
|
FOUND_SALVAGE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The item cannot be salvaged using the used method
|
||||||
|
*/
|
||||||
|
INCORRECT_METHOD,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* While the method was correct, no useful salvage was created
|
||||||
|
*/
|
||||||
|
NO_SALVAGE,
|
||||||
|
|
||||||
|
}
|
@ -1,40 +1,28 @@
|
|||||||
package net.knarcraft.blacksmith.trait;
|
package net.knarcraft.blacksmith.trait;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
|
||||||
import net.citizensnpcs.api.trait.Trait;
|
|
||||||
import net.citizensnpcs.api.util.DataKey;
|
import net.citizensnpcs.api.util.DataKey;
|
||||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
import net.knarcraft.blacksmith.config.NPCSettings;
|
import net.knarcraft.blacksmith.config.blacksmith.BlacksmithNPCSettings;
|
||||||
import net.knarcraft.blacksmith.formatting.TimeFormatter;
|
import net.knarcraft.blacksmith.config.blacksmith.BlacksmithSetting;
|
||||||
import net.knarcraft.blacksmith.manager.EconomyManager;
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
||||||
import net.knarcraft.blacksmith.util.ItemHelper;
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
|
import net.knarcraft.knarlib.formatting.StringFormatter;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.enchantments.EnchantmentTarget;
|
|
||||||
import org.bukkit.entity.LivingEntity;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.Damageable;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import static net.knarcraft.blacksmith.formatting.StringFormatter.replacePlaceholder;
|
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
||||||
import static net.knarcraft.blacksmith.formatting.StringFormatter.sendNPCMessage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class representing the Blacksmith NPC trait
|
* The class representing the Blacksmith NPC trait
|
||||||
*/
|
*/
|
||||||
public class BlacksmithTrait extends Trait {
|
public class BlacksmithTrait extends CustomTrait<BlacksmithSetting> {
|
||||||
|
|
||||||
private final Map<UUID, Calendar> coolDowns = new HashMap<>();
|
private final BlacksmithNPCSettings config;
|
||||||
private ReforgeSession session;
|
|
||||||
private final NPCSettings config;
|
|
||||||
private long _sessionStart = System.currentTimeMillis();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new blacksmith trait
|
* Instantiates a new blacksmith trait
|
||||||
@ -43,7 +31,8 @@ public class BlacksmithTrait extends Trait {
|
|||||||
super("blacksmith");
|
super("blacksmith");
|
||||||
//This should crash if the blacksmith plugin hasn't been properly registered
|
//This should crash if the blacksmith plugin hasn't been properly registered
|
||||||
Bukkit.getServer().getPluginManager().getPlugin("Blacksmith");
|
Bukkit.getServer().getPluginManager().getPlugin("Blacksmith");
|
||||||
this.config = new NPCSettings(BlacksmithPlugin.getInstance().getSettings());
|
this.config = new BlacksmithNPCSettings(BlacksmithPlugin.getInstance().getGlobalBlacksmithSettings());
|
||||||
|
super.setTraitSettings(this.config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,43 +40,18 @@ public class BlacksmithTrait extends Trait {
|
|||||||
*
|
*
|
||||||
* @return <p>The current settings for this NPC</p>
|
* @return <p>The current settings for this NPC</p>
|
||||||
*/
|
*/
|
||||||
public NPCSettings getSettings() {
|
@NotNull
|
||||||
|
public BlacksmithNPCSettings getSettings() {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether this blacksmith is already in a reforging session
|
|
||||||
*
|
|
||||||
* @return <p>Whether already in a reforge session</p>
|
|
||||||
*/
|
|
||||||
public boolean hasSession() {
|
|
||||||
return this.session != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a cool-down for the given player's next blacksmith reforge
|
|
||||||
*
|
|
||||||
* @param playerUUID <p>The ID of the player to add the cool-down for</p>
|
|
||||||
* @param waitUntil <p>The time when the player can interact again</p>
|
|
||||||
*/
|
|
||||||
public void addCoolDown(UUID playerUUID, Calendar waitUntil) {
|
|
||||||
coolDowns.put(playerUUID, waitUntil);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unsets the session of this blacksmith, making it ready for another round
|
|
||||||
*/
|
|
||||||
public void unsetSession() {
|
|
||||||
this.session = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all config values stored in citizens' config file for this NPC
|
* Loads all config values stored in citizens' config file for this NPC
|
||||||
*
|
*
|
||||||
* @param key <p>The data key used for the config root</p>
|
* @param key <p>The data key used for the config root</p>
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void load(DataKey key) {
|
public void load(@NotNull DataKey key) {
|
||||||
config.loadVariables(key);
|
config.loadVariables(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,141 +61,51 @@ public class BlacksmithTrait extends Trait {
|
|||||||
* @param key <p>The data key used for the config root</p>
|
* @param key <p>The data key used for the config root</p>
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void save(DataKey key) {
|
public void save(@NotNull DataKey key) {
|
||||||
config.saveVariables(key);
|
config.saveVariables(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Performs necessary work before the session is started or continued
|
public void startSession(@NotNull Player player) {
|
||||||
*
|
|
||||||
* @param player <p>The player to prepare the session for</p>
|
|
||||||
* @return <p>True if preparations were successful. False if a session shouldn't be started</p>
|
|
||||||
*/
|
|
||||||
public boolean prepareForSession(Player player) {
|
|
||||||
UUID playerId = player.getUniqueId();
|
|
||||||
//If cool-down has been disabled after it was set for this player, remove the cool-down
|
|
||||||
if (config.getDisableCoolDown() && coolDowns.get(playerId) != null) {
|
|
||||||
coolDowns.remove(playerId);
|
|
||||||
}
|
|
||||||
//Deny if permission is missing
|
|
||||||
if (!player.hasPermission("blacksmith.reforge")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Deny if on cool-down, or remove cool-down if expired
|
|
||||||
if (coolDowns.get(playerId) != null) {
|
|
||||||
Calendar calendar = Calendar.getInstance();
|
|
||||||
if (!calendar.after(coolDowns.get(playerId))) {
|
|
||||||
int secondDifference = (int) (coolDowns.get(playerId).getTimeInMillis() - calendar.getTimeInMillis()) / 1000;
|
|
||||||
boolean exactTime = BlacksmithPlugin.getInstance().getSettings().getShowExactTime();
|
|
||||||
sendNPCMessage(this.npc, player, replacePlaceholder(config.getCoolDownUnexpiredMessage(),
|
|
||||||
"{time}", TimeFormatter.formatTime(exactTime, secondDifference)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
coolDowns.remove(playerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
//If already in a session, but the player has failed to interact, and left the blacksmith, allow a new session
|
|
||||||
if (session != null) {
|
|
||||||
if (!session.isRunning() && (System.currentTimeMillis() > _sessionStart + 10 * 1000 ||
|
|
||||||
this.npc.getEntity().getLocation().distance(session.getPlayer().getLocation()) > 20)) {
|
|
||||||
session = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to continue the session for the given player
|
|
||||||
*
|
|
||||||
* @param player <p>The player to continue the session for</p>
|
|
||||||
*/
|
|
||||||
public void continueSession(Player player) {
|
|
||||||
//Another player is using the blacksmith
|
|
||||||
if (!session.isInSession(player)) {
|
|
||||||
sendNPCMessage(this.npc, player, config.getBusyWithPlayerMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//The blacksmith is already reforging for the player
|
|
||||||
if (session.isRunning()) {
|
|
||||||
int timeRemaining = (int) ((session.getFinishTime() - System.currentTimeMillis()) / 1000);
|
|
||||||
boolean showExactTime = BlacksmithPlugin.getInstance().getSettings().getShowExactTime();
|
|
||||||
sendNPCMessage(this.npc, player, replacePlaceholder(config.getBusyReforgingMessage(), "{time}",
|
|
||||||
TimeFormatter.formatTime(showExactTime, timeRemaining)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (session.endSession()) {
|
|
||||||
//Quit if the player cannot afford, or has changed their item
|
|
||||||
session = null;
|
|
||||||
} else {
|
|
||||||
//Start reforging for the player
|
|
||||||
reforge(npc, player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a new session, and prepares to repair the player's item
|
|
||||||
*
|
|
||||||
* @param player <p>The player to start the session for</p>
|
|
||||||
*/
|
|
||||||
public void startSession(Player player) {
|
|
||||||
ItemStack hand = player.getInventory().getItemInMainHand();
|
ItemStack hand = player.getInventory().getItemInMainHand();
|
||||||
|
if (hand.getType().isAir()) {
|
||||||
|
sendNPCMessage(this.npc, player, config.getNoItemMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//Refuse if not repairable, or if reforge-able items is set, but doesn't include the held item
|
//Refuse if not repairable, or if reforge-able items is set, but doesn't include the held item
|
||||||
List<Material> reforgeAbleItems = config.getReforgeAbleItems();
|
List<Material> reforgeAbleItems = config.getReforgeAbleItems();
|
||||||
if (!isRepairable(hand) || (!reforgeAbleItems.isEmpty() && !reforgeAbleItems.contains(hand.getType()))) {
|
|
||||||
String invalidMessage = replacePlaceholder(config.getInvalidItemMessage(),
|
boolean notHoldingAnvil = !this.config.getRepairAnvils() || !ItemHelper.isAnvil(hand.getType(), false);
|
||||||
|
boolean notHoldingRepairable = !ItemHelper.isRepairable(hand) ||
|
||||||
|
(!reforgeAbleItems.isEmpty() && !reforgeAbleItems.contains(hand.getType()));
|
||||||
|
|
||||||
|
if (notHoldingAnvil && notHoldingRepairable) {
|
||||||
|
String invalidMessage = StringFormatter.replacePlaceholder(config.getInvalidItemMessage(),
|
||||||
"{title}", config.getBlacksmithTitle());
|
"{title}", config.getBlacksmithTitle());
|
||||||
sendNPCMessage(this.npc, player, invalidMessage);
|
sendNPCMessage(this.npc, player, invalidMessage);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ItemHelper.getDamage(hand) == 0) {
|
if (ItemHelper.getDamage(hand) == 0 && !ItemHelper.isAnvil(hand.getType(), true)) {
|
||||||
sendNPCMessage(this.npc, player, config.getNotDamagedMessage());
|
sendNPCMessage(this.npc, player, config.getNotDamagedMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Start a new reforge session for the player
|
//Start a new reforge session for the player
|
||||||
_sessionStart = System.currentTimeMillis();
|
currentSessionStartTime = System.currentTimeMillis();
|
||||||
session = new ReforgeSession(this, player, npc, config);
|
session = new ReforgeSession(this, player, npc, config);
|
||||||
|
|
||||||
//Tell the player the cost of repairing the item
|
//Tell the player the cost of repairing the item
|
||||||
String cost = EconomyManager.formatCost(player);
|
String cost = EconomyManager.formatBlacksmithCost(player);
|
||||||
String itemName = hand.getType().name().toLowerCase().replace('_', ' ');
|
String itemName = hand.getType().name().toLowerCase().replace('_', ' ');
|
||||||
sendNPCMessage(this.npc, player, config.getCostMessage().replace("{cost}", cost).replace("{item}",
|
sendNPCMessage(this.npc, player, config.getCostMessage().replace("{cost}", cost).replace("{item}",
|
||||||
itemName));
|
itemName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Starts reforging the player's item
|
protected boolean showExactTime() {
|
||||||
*
|
return BlacksmithPlugin.getInstance().getGlobalBlacksmithSettings().getShowExactTime();
|
||||||
* @param npc <p>The NPC performing the reforge</p>
|
|
||||||
* @param player <p>The player that initiated the reforge</p>
|
|
||||||
*/
|
|
||||||
private void reforge(NPC npc, Player player) {
|
|
||||||
sendNPCMessage(this.npc, player, config.getStartReforgeMessage());
|
|
||||||
EconomyManager.withdraw(player);
|
|
||||||
session.beginReforge();
|
|
||||||
ItemStack heldItem = player.getInventory().getItemInMainHand();
|
|
||||||
|
|
||||||
//Display the item in the NPC's hand
|
|
||||||
if (npc.getEntity() instanceof Player) {
|
|
||||||
((Player) npc.getEntity()).getInventory().setItemInMainHand(heldItem);
|
|
||||||
} else {
|
|
||||||
Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(heldItem);
|
|
||||||
}
|
|
||||||
//Remove the item from the player's inventory
|
|
||||||
player.getInventory().setItemInMainHand(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether the given item is repairable
|
|
||||||
*
|
|
||||||
* @param item <p>The item to check</p>
|
|
||||||
* @return <p>True if the item is repairable</p>
|
|
||||||
*/
|
|
||||||
public static boolean isRepairable(ItemStack item) {
|
|
||||||
return item.getItemMeta() instanceof Damageable && EnchantmentTarget.BREAKABLE.includes(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
210
src/main/java/net/knarcraft/blacksmith/trait/CustomTrait.java
Normal file
210
src/main/java/net/knarcraft/blacksmith/trait/CustomTrait.java
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
package net.knarcraft.blacksmith.trait;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import net.citizensnpcs.api.trait.Trait;
|
||||||
|
import net.knarcraft.blacksmith.config.Setting;
|
||||||
|
import net.knarcraft.blacksmith.config.Settings;
|
||||||
|
import net.knarcraft.blacksmith.config.TraitSettings;
|
||||||
|
import net.knarcraft.blacksmith.formatting.TimeFormatter;
|
||||||
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
||||||
|
import net.knarcraft.knarlib.formatting.StringFormatter;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.PlayerInventory;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A custom trait that utilizes sessions
|
||||||
|
*/
|
||||||
|
public abstract class CustomTrait<K extends Setting> extends Trait {
|
||||||
|
|
||||||
|
protected Session session;
|
||||||
|
protected TraitSettings<K> config;
|
||||||
|
protected final Map<UUID, Calendar> coolDowns = new HashMap<>();
|
||||||
|
protected long currentSessionStartTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new custom trait
|
||||||
|
*
|
||||||
|
* @param name <p>The name of the new trait</p>
|
||||||
|
*/
|
||||||
|
protected CustomTrait(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the trait settings object containing this trait's configuration
|
||||||
|
*
|
||||||
|
* @param config <p>The trait settings to use</p>
|
||||||
|
*/
|
||||||
|
protected void setTraitSettings(TraitSettings<K> config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the settings used by this trait
|
||||||
|
*
|
||||||
|
* @return <p>The settings used by this trait</p>
|
||||||
|
*/
|
||||||
|
public @Nullable Settings<K> getTraitSettings() {
|
||||||
|
return this.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a new session, and prepares to repair the player's item
|
||||||
|
*
|
||||||
|
* @param player <p>The player to start the session for</p>
|
||||||
|
*/
|
||||||
|
public abstract void startSession(@NotNull Player player);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to continue the session for the given player
|
||||||
|
*
|
||||||
|
* @param player <p>The player to continue the session for</p>
|
||||||
|
*/
|
||||||
|
public void continueSession(@NotNull Player player) {
|
||||||
|
//Another player is using the blacksmith
|
||||||
|
if (session.isNotInSession(player)) {
|
||||||
|
sendNPCMessage(this.npc, player, config.getBusyWithPlayerMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//The blacksmith is already reforging for the player
|
||||||
|
if (session.isRunning()) {
|
||||||
|
int timeRemaining = (int) ((session.getFinishTime() - System.currentTimeMillis()) / 1000);
|
||||||
|
boolean showExactTime = showExactTime();
|
||||||
|
sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(config.getBusyWorkingMessage(),
|
||||||
|
"{time}", TimeFormatter.formatTime(showExactTime, timeRemaining)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (session.isSessionInvalid()) {
|
||||||
|
//Quit if the player cannot afford, or has changed their item
|
||||||
|
session = null;
|
||||||
|
} else {
|
||||||
|
//Start reforging for the player
|
||||||
|
startMainAction(npc, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this blacksmith is already in a reforging session
|
||||||
|
*
|
||||||
|
* @return <p>Whether already in a salvage session</p>
|
||||||
|
*/
|
||||||
|
public boolean hasSession() {
|
||||||
|
return this.session != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a cool-down for the given player's next blacksmith reforge
|
||||||
|
*
|
||||||
|
* @param playerUUID <p>The ID of the player to add the cool-down for</p>
|
||||||
|
* @param waitUntil <p>The time when the player can interact again</p>
|
||||||
|
*/
|
||||||
|
public void addCoolDown(@NotNull UUID playerUUID, @NotNull Calendar waitUntil) {
|
||||||
|
coolDowns.put(playerUUID, waitUntil);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsets the session of this scrapper, making it ready for another round
|
||||||
|
*/
|
||||||
|
public void unsetSession() {
|
||||||
|
this.session = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs necessary work before the session is started or continued
|
||||||
|
*
|
||||||
|
* @param player <p>The player to prepare the session for</p>
|
||||||
|
* @return <p>True if preparations were successful. False if a session shouldn't be started</p>
|
||||||
|
*/
|
||||||
|
public boolean prepareForSession(@NotNull Player player) {
|
||||||
|
UUID playerId = player.getUniqueId();
|
||||||
|
//If cool-down has been disabled after it was set for this player, remove the cool-down
|
||||||
|
if (config.getDisableCoolDown() && coolDowns.get(playerId) != null) {
|
||||||
|
coolDowns.remove(playerId);
|
||||||
|
}
|
||||||
|
//Deny if permission is missing
|
||||||
|
if (!player.hasPermission("blacksmith.use")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Deny if on cool-down, or remove cool-down if expired
|
||||||
|
if (coolDowns.get(playerId) != null) {
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
if (!calendar.after(coolDowns.get(playerId))) {
|
||||||
|
int secondDifference = (int) (coolDowns.get(playerId).getTimeInMillis() - calendar.getTimeInMillis()) / 1000;
|
||||||
|
boolean exactTime = showExactTime();
|
||||||
|
sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(config.getCoolDownUnexpiredMessage(),
|
||||||
|
"{time}", TimeFormatter.formatTime(exactTime, secondDifference)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
coolDowns.remove(playerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
//If already in a session, but the player has failed to interact, and left the blacksmith, allow a new session
|
||||||
|
if (session != null && !session.isRunning() && (System.currentTimeMillis() > currentSessionStartTime + 10 * 1000 ||
|
||||||
|
this.npc.getEntity().getLocation().distance(session.getPlayer().getLocation()) > 20)) {
|
||||||
|
session = null;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether to show exact time when displaying the remaining time left
|
||||||
|
*
|
||||||
|
* @return <p>Whether to show exact time, or vague words</p>
|
||||||
|
*/
|
||||||
|
protected abstract boolean showExactTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts reforging the player's item
|
||||||
|
*
|
||||||
|
* @param npc <p>The NPC performing the reforge</p>
|
||||||
|
* @param player <p>The player that initiated the reforge</p>
|
||||||
|
*/
|
||||||
|
private void startMainAction(@NotNull NPC npc, @NotNull Player player) {
|
||||||
|
sendNPCMessage(this.npc, player, config.getStartWorkingMessage());
|
||||||
|
|
||||||
|
boolean isBlacksmith = this instanceof BlacksmithTrait;
|
||||||
|
|
||||||
|
if (isBlacksmith) {
|
||||||
|
EconomyManager.withdrawBlacksmith(player);
|
||||||
|
} else if (this.session instanceof SalvageSession salvageSession) {
|
||||||
|
EconomyManager.withdrawScrapper(player, salvageSession.salvageMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
session.scheduleAction();
|
||||||
|
PlayerInventory playerInventory = player.getInventory();
|
||||||
|
ItemStack heldItem = player.getInventory().getItemInMainHand();
|
||||||
|
|
||||||
|
//Display the item in the NPC's hand
|
||||||
|
if (npc.getEntity() instanceof Player) {
|
||||||
|
((Player) npc.getEntity()).getInventory().setItemInMainHand(heldItem);
|
||||||
|
} else {
|
||||||
|
Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(heldItem);
|
||||||
|
}
|
||||||
|
//Remove the item from the player's inventory
|
||||||
|
if (this.session instanceof SalvageSession salvageSession) {
|
||||||
|
// For scrappers, just reduce the amounts of items, unless the remaining stack is salvaged
|
||||||
|
int amount = salvageSession.getItemsConsumed();
|
||||||
|
if (amount != heldItem.getAmount()) {
|
||||||
|
heldItem.setAmount(heldItem.getAmount() - amount);
|
||||||
|
playerInventory.setItemInMainHand(heldItem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
playerInventory.setItemInMainHand(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,41 +2,39 @@ package net.knarcraft.blacksmith.trait;
|
|||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
import net.knarcraft.blacksmith.config.NPCSettings;
|
import net.knarcraft.blacksmith.config.blacksmith.BlacksmithNPCSettings;
|
||||||
|
import net.knarcraft.blacksmith.event.BlacksmithReforgeFailEvent;
|
||||||
|
import net.knarcraft.blacksmith.event.BlacksmithReforgeSucceedEvent;
|
||||||
import net.knarcraft.blacksmith.manager.EconomyManager;
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
||||||
import net.knarcraft.blacksmith.util.InputParsingHelper;
|
import net.knarcraft.blacksmith.util.InputParsingHelper;
|
||||||
import net.knarcraft.blacksmith.util.ItemHelper;
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Registry;
|
||||||
|
import org.bukkit.Sound;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.entity.LivingEntity;
|
import org.bukkit.entity.LivingEntity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.Damageable;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
|
||||||
import org.bukkit.scheduler.BukkitScheduler;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import static net.knarcraft.blacksmith.formatting.StringFormatter.sendNPCMessage;
|
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A representation of the session between a player and a blacksmith
|
* A representation of the session between a player and a blacksmith
|
||||||
*/
|
*/
|
||||||
public class ReforgeSession implements Runnable {
|
public class ReforgeSession extends Session implements Runnable {
|
||||||
|
|
||||||
private final BlacksmithTrait blacksmithTrait;
|
private final BlacksmithTrait blacksmithTrait;
|
||||||
private final Player player;
|
|
||||||
private final NPC npc;
|
|
||||||
private final ItemStack itemToReforge;
|
private final ItemStack itemToReforge;
|
||||||
private int taskId;
|
private final BlacksmithNPCSettings config;
|
||||||
private long finishTime = 0;
|
private static List<String> enchantments = null;
|
||||||
private final NPCSettings config;
|
|
||||||
private static final String[] enchantments = new String[Enchantment.values().length];
|
|
||||||
private static final Random random = new Random();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new session
|
* Instantiates a new session
|
||||||
@ -46,29 +44,57 @@ public class ReforgeSession implements Runnable {
|
|||||||
* @param npc <p>The Blacksmith NPC involved in the session</p>
|
* @param npc <p>The Blacksmith NPC involved in the session</p>
|
||||||
* @param config <p>The config to use for the session</p>
|
* @param config <p>The config to use for the session</p>
|
||||||
*/
|
*/
|
||||||
ReforgeSession(BlacksmithTrait blacksmithTrait, Player player, NPC npc, NPCSettings config) {
|
ReforgeSession(@NotNull BlacksmithTrait blacksmithTrait, @NotNull Player player, @NotNull NPC npc,
|
||||||
|
@NotNull BlacksmithNPCSettings config) {
|
||||||
|
super(player, npc);
|
||||||
this.blacksmithTrait = blacksmithTrait;
|
this.blacksmithTrait = blacksmithTrait;
|
||||||
this.player = player;
|
|
||||||
this.npc = npc;
|
|
||||||
this.itemToReforge = player.getInventory().getItemInMainHand();
|
this.itemToReforge = player.getInventory().getItemInMainHand();
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
|
||||||
//Populate enchantments the first time this is run
|
//Populate enchantments the first time this is run
|
||||||
if (enchantments[0] == null) {
|
if (enchantments == null) {
|
||||||
int i = 0;
|
Registry<Enchantment> enchantmentRegistry = Bukkit.getRegistry(Enchantment.class);
|
||||||
for (Enchantment enchantment : Enchantment.values()) {
|
if (enchantmentRegistry == null) {
|
||||||
enchantments[i++] = enchantment.getKey().getKey();
|
throw new RuntimeException("Unable to get enchantment registry");
|
||||||
|
}
|
||||||
|
|
||||||
|
enchantments = new ArrayList<>();
|
||||||
|
for (Enchantment enchantment : enchantmentRegistry) {
|
||||||
|
enchantments.add(enchantment.getKey().getKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Gets the time in milliseconds when this reforging session will finish
|
public boolean isSessionInvalid() {
|
||||||
*
|
// Prevent player from switching items during session
|
||||||
* @return <p>The time the reforging will finish</p>
|
ItemStack itemInHand = this.player.getInventory().getItemInMainHand();
|
||||||
*/
|
if (!itemToReforge.equals(itemInHand)) {
|
||||||
public long getFinishTime() {
|
sendNPCMessage(this.npc, this.player, this.config.getItemChangedMessage());
|
||||||
return this.finishTime;
|
return true;
|
||||||
|
}
|
||||||
|
// The player is unable to pay
|
||||||
|
if (EconomyManager.cannotPayForHeldItemReforge(this.player)) {
|
||||||
|
sendNPCMessage(this.npc, this.player, this.config.getInsufficientFundsMessage());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getActionDelay() {
|
||||||
|
if (this.config.getMaxReforgeDelay() > 0) {
|
||||||
|
//Finish the reforging after a random delay between the max and min
|
||||||
|
return new Random().nextInt(this.config.getMaxReforgeDelay()) + this.config.getMinReforgeDelay();
|
||||||
|
} else {
|
||||||
|
//Finish the salvaging as soon as possible
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull Material getCraftingStation() {
|
||||||
|
return Material.ANVIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,35 +102,35 @@ public class ReforgeSession implements Runnable {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
sendNPCMessage(this.npc, player, reforgeItem() ? config.getSuccessMessage() : config.getFailMessage());
|
boolean success = reforgeItem();
|
||||||
|
sendNPCMessage(this.npc, this.player, success ? this.config.getSuccessMessage() : this.config.getFailMessage());
|
||||||
|
playSound(success ? Sound.BLOCK_ANVIL_USE : Sound.ENTITY_VILLAGER_NO);
|
||||||
|
|
||||||
//Stop the reforged item from displaying in the blacksmith's hand
|
//Stop the reforged item from displaying in the blacksmith's hand
|
||||||
if (npc.getEntity() instanceof Player) {
|
if (this.npc.getEntity() instanceof Player) {
|
||||||
((Player) npc.getEntity()).getInventory().setItemInMainHand(null);
|
((Player) this.npc.getEntity()).getInventory().setItemInMainHand(null);
|
||||||
} else {
|
} else {
|
||||||
Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(null);
|
Objects.requireNonNull(((LivingEntity) this.npc.getEntity()).getEquipment()).setItemInMainHand(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Give the item back to the player
|
//Give the item back to the player
|
||||||
if (!config.getDisableDelay()) {
|
giveReforgedItem();
|
||||||
//If the player isn't online, or the player cannot fit the item, drop the item to prevent it from disappearing
|
|
||||||
if (config.getDropItem() || !player.isOnline() || player.getInventory().firstEmpty() == -1) {
|
|
||||||
player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), itemToReforge);
|
|
||||||
} else {
|
|
||||||
player.getInventory().addItem(itemToReforge);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//It can be assumed as this happens instantly, that the player still has the item's previous slot selected
|
|
||||||
player.getInventory().setItemInMainHand(itemToReforge);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Mark this blacksmith as available
|
//Mark this blacksmith as available
|
||||||
blacksmithTrait.unsetSession();
|
this.blacksmithTrait.unsetSession();
|
||||||
|
|
||||||
// Start cool-down
|
// Start cool-down
|
||||||
Calendar wait = Calendar.getInstance();
|
Calendar wait = Calendar.getInstance();
|
||||||
wait.add(Calendar.SECOND, config.getReforgeCoolDown());
|
wait.add(Calendar.SECOND, this.config.getReforgeCoolDown());
|
||||||
blacksmithTrait.addCoolDown(player.getUniqueId(), wait);
|
this.blacksmithTrait.addCoolDown(this.player.getUniqueId(), wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives the reforged item back to the player
|
||||||
|
*/
|
||||||
|
private void giveReforgedItem() {
|
||||||
|
giveResultingItem(this.config.getMaxReforgeDelay() > 0, this.config.getDropItem(), this.npc,
|
||||||
|
this.itemToReforge);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -113,11 +139,13 @@ public class ReforgeSession implements Runnable {
|
|||||||
* @return <p>Whether the reforge was successful. False if the blacksmith failed to fully repair the item.</p>
|
* @return <p>Whether the reforge was successful. False if the blacksmith failed to fully repair the item.</p>
|
||||||
*/
|
*/
|
||||||
private boolean reforgeItem() {
|
private boolean reforgeItem() {
|
||||||
if (random.nextInt(100) < config.getFailChance()) {
|
if (random.nextInt(100) < this.config.getFailChance()) {
|
||||||
failReforge();
|
failReforge();
|
||||||
|
BlacksmithPlugin.getInstance().callEvent(new BlacksmithReforgeFailEvent(this.npc, this.player));
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
succeedReforge();
|
succeedReforge();
|
||||||
|
BlacksmithPlugin.getInstance().callEvent(new BlacksmithReforgeSucceedEvent(this.npc, this.player));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,26 +155,38 @@ public class ReforgeSession implements Runnable {
|
|||||||
*/
|
*/
|
||||||
private void succeedReforge() {
|
private void succeedReforge() {
|
||||||
// Remove any damage done to the item
|
// Remove any damage done to the item
|
||||||
updateDamage(itemToReforge, 0);
|
if (ItemHelper.updateDamage(this.itemToReforge, 0)) {
|
||||||
|
BlacksmithPlugin.warn("Unable to update damage for " + this.itemToReforge);
|
||||||
// Add random enchantments
|
|
||||||
int roll = random.nextInt(100);
|
|
||||||
if (!(roll < config.getExtraEnchantmentChance() &&
|
|
||||||
itemToReforge.getEnchantments().keySet().size() < config.getMaxEnchantments())) {
|
|
||||||
// Abort if randomness isn't on our side, or if max enchantments has been reached
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Replace damaged anvils with a normal anvil
|
||||||
|
if (ItemHelper.isAnvil(this.itemToReforge.getType(), true)) {
|
||||||
|
this.itemToReforge.setType(Material.ANVIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
//See if a random roll (0-99) is less than extraEnchantmentChance, and add a random enchantment
|
||||||
|
int roll = random.nextInt(100);
|
||||||
|
if (roll < this.config.getExtraEnchantmentChance() &&
|
||||||
|
this.itemToReforge.getEnchantments().keySet().size() < this.config.getMaxEnchantments() &&
|
||||||
|
!ItemHelper.isAnvil(this.itemToReforge.getType(), false)) {
|
||||||
|
addRandomEnchantment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a random enchantment to the currently reforged item
|
||||||
|
*/
|
||||||
|
private void addRandomEnchantment() {
|
||||||
//Find usable enchantments first
|
//Find usable enchantments first
|
||||||
List<Enchantment> usableEnchantments = new ArrayList<>();
|
List<Enchantment> usableEnchantments = new ArrayList<>();
|
||||||
for (String enchantmentName : enchantments) {
|
for (String enchantmentName : enchantments) {
|
||||||
Enchantment enchantment = InputParsingHelper.matchEnchantment(enchantmentName);
|
Enchantment enchantment = InputParsingHelper.matchEnchantment(enchantmentName);
|
||||||
if (enchantment != null && enchantment.canEnchantItem(itemToReforge)) {
|
if (enchantment != null && enchantment.canEnchantItem(this.itemToReforge)) {
|
||||||
usableEnchantments.add(enchantment);
|
usableEnchantments.add(enchantment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Remove any enchantments in the block list
|
//Remove any enchantments in the block list
|
||||||
usableEnchantments.removeAll(blacksmithTrait.getSettings().getEnchantmentBlocklist());
|
usableEnchantments.removeAll(this.blacksmithTrait.getSettings().getEnchantmentBlockList());
|
||||||
|
|
||||||
//In case all usable enchantments have been blocked, abort
|
//In case all usable enchantments have been blocked, abort
|
||||||
if (usableEnchantments.isEmpty()) {
|
if (usableEnchantments.isEmpty()) {
|
||||||
@ -159,10 +199,10 @@ public class ReforgeSession implements Runnable {
|
|||||||
int randomBound = randomEnchantment.getMaxLevel() + 1;
|
int randomBound = randomEnchantment.getMaxLevel() + 1;
|
||||||
//A workaround for the random method's bound sometimes being negative
|
//A workaround for the random method's bound sometimes being negative
|
||||||
if (randomBound >= 0) {
|
if (randomBound >= 0) {
|
||||||
int existingLevel = itemToReforge.getEnchantmentLevel(randomEnchantment);
|
int existingLevel = this.itemToReforge.getEnchantmentLevel(randomEnchantment);
|
||||||
/* Add a random enchantment whose level is no lower than the start level, and no lower than the
|
/* Add a random enchantment whose level is no lower than the start level, and no lower than the
|
||||||
existing level (to prevent making the item worse) */
|
existing level (to prevent making the item worse) */
|
||||||
itemToReforge.addEnchantment(randomEnchantment, Math.max(Math.max(random.nextInt(randomBound),
|
this.itemToReforge.addEnchantment(randomEnchantment, Math.max(Math.max(random.nextInt(randomBound),
|
||||||
randomEnchantment.getStartLevel()), existingLevel));
|
randomEnchantment.getStartLevel()), existingLevel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,112 +212,28 @@ public class ReforgeSession implements Runnable {
|
|||||||
* The method to run when a blacksmith fails re-forging an item
|
* The method to run when a blacksmith fails re-forging an item
|
||||||
*/
|
*/
|
||||||
private void failReforge() {
|
private void failReforge() {
|
||||||
// Remove or downgrade existing enchantments
|
if (this.config.getFailRemovesEnchantments()) {
|
||||||
for (Enchantment enchantment : itemToReforge.getEnchantments().keySet()) {
|
removeOrDowngradeEnchantments();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Damage the item
|
||||||
|
damageItemRandomly(this.itemToReforge);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes or downgrades all enchantments for the currently reforged item
|
||||||
|
*/
|
||||||
|
private void removeOrDowngradeEnchantments() {
|
||||||
|
//Remove or downgrade existing enchantments
|
||||||
|
for (Enchantment enchantment : this.itemToReforge.getEnchantments().keySet()) {
|
||||||
|
//Completely remove the enchantment, downgrade it, or keep it if lucky and already level 1
|
||||||
if (random.nextBoolean()) {
|
if (random.nextBoolean()) {
|
||||||
itemToReforge.removeEnchantment(enchantment);
|
this.itemToReforge.removeEnchantment(enchantment);
|
||||||
} else {
|
} else if (this.itemToReforge.getEnchantmentLevel(enchantment) > 1) {
|
||||||
if (itemToReforge.getEnchantmentLevel(enchantment) > 1) {
|
this.itemToReforge.removeEnchantment(enchantment);
|
||||||
itemToReforge.removeEnchantment(enchantment);
|
this.itemToReforge.addEnchantment(enchantment, 1);
|
||||||
itemToReforge.addEnchantment(enchantment, 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Damage the item
|
|
||||||
short currentItemDurability = ItemHelper.getDurability(itemToReforge);
|
|
||||||
short newDurability = (short) (currentItemDurability + (currentItemDurability * random.nextInt(8)));
|
|
||||||
short maxDurability = itemToReforge.getType().getMaxDurability();
|
|
||||||
if (newDurability <= 0) {
|
|
||||||
newDurability = (short) (maxDurability / 3);
|
|
||||||
} else if (currentItemDurability + newDurability > maxDurability) {
|
|
||||||
newDurability = (short) (maxDurability - random.nextInt(maxDurability - 25));
|
|
||||||
}
|
|
||||||
updateDamage(itemToReforge, maxDurability - newDurability);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the damage done to an item
|
|
||||||
*
|
|
||||||
* @param item <p>The item to update damage for</p>
|
|
||||||
* @param newDamage <p>The new damage done</p>
|
|
||||||
*/
|
|
||||||
private void updateDamage(ItemStack item, int newDamage) {
|
|
||||||
ItemMeta meta = item.getItemMeta();
|
|
||||||
Damageable damageable = (Damageable) meta;
|
|
||||||
if (damageable != null) {
|
|
||||||
damageable.setDamage(newDamage);
|
|
||||||
} else {
|
|
||||||
BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING, "Unable to change damage of " + item);
|
|
||||||
}
|
|
||||||
item.setItemMeta(meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether to end the current session
|
|
||||||
*
|
|
||||||
* <p>If the player has switched their item, or the player cannot pay, this returns true.</p>
|
|
||||||
*
|
|
||||||
* @return <p>True if the current session should end</p>
|
|
||||||
*/
|
|
||||||
public boolean endSession() {
|
|
||||||
// Prevent player from switching items during session
|
|
||||||
ItemStack itemInHand = player.getInventory().getItemInMainHand();
|
|
||||||
if (!itemToReforge.equals(itemInHand)) {
|
|
||||||
sendNPCMessage(this.npc, player, config.getItemChangedMessage());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// The player is unable to pay
|
|
||||||
if (!EconomyManager.canPay(player)) {
|
|
||||||
sendNPCMessage(this.npc, player, config.getInsufficientFundsMessage());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether the current session is still running
|
|
||||||
*
|
|
||||||
* @return <p>True if the current session is still running</p>
|
|
||||||
*/
|
|
||||||
public boolean isRunning() {
|
|
||||||
return BlacksmithPlugin.getInstance().getServer().getScheduler().isQueued(taskId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether the given player is currently in a reforging session
|
|
||||||
*
|
|
||||||
* @param other <p>The player to check if is in session</p>
|
|
||||||
* @return <p>True if the given player is in a reforge session</p>
|
|
||||||
*/
|
|
||||||
public boolean isInSession(Player other) {
|
|
||||||
return player.getName().equals(other.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Begins the actual item reforging
|
|
||||||
*/
|
|
||||||
public void beginReforge() {
|
|
||||||
BukkitScheduler scheduler = BlacksmithPlugin.getInstance().getServer().getScheduler();
|
|
||||||
int reforgeDelay;
|
|
||||||
if (!config.getDisableCoolDown()) {
|
|
||||||
//Finish the reforging after a random delay between the max and min
|
|
||||||
reforgeDelay = new Random().nextInt(config.getMaxReforgeDelay()) + config.getMinReforgeDelay();
|
|
||||||
} else {
|
|
||||||
//Finish the reforging as soon as possible
|
|
||||||
reforgeDelay = 0;
|
|
||||||
}
|
|
||||||
this.finishTime = System.currentTimeMillis() + (reforgeDelay * 1000L);
|
|
||||||
taskId = scheduler.scheduleSyncDelayedTask(BlacksmithPlugin.getInstance(), this, reforgeDelay * 20L);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the player currently in this reforge session
|
|
||||||
*
|
|
||||||
* @return <p>The player currently in this reforge session</p>
|
|
||||||
*/
|
|
||||||
public Player getPlayer() {
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
184
src/main/java/net/knarcraft/blacksmith/trait/SalvageSession.java
Normal file
184
src/main/java/net/knarcraft/blacksmith/trait/SalvageSession.java
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
package net.knarcraft.blacksmith.trait;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings;
|
||||||
|
import net.knarcraft.blacksmith.event.ScrapperSalvageFailEvent;
|
||||||
|
import net.knarcraft.blacksmith.event.ScrapperSalvageSucceedEvent;
|
||||||
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
||||||
|
import net.knarcraft.blacksmith.property.SalvageMethod;
|
||||||
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
|
import net.knarcraft.blacksmith.util.SalvageHelper;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A representation of the session between a player and a scrapper
|
||||||
|
*/
|
||||||
|
public class SalvageSession extends Session implements Runnable {
|
||||||
|
|
||||||
|
private final ScrapperTrait scrapperTrait;
|
||||||
|
private final ItemStack itemToSalvage;
|
||||||
|
private final ScrapperNPCSettings config;
|
||||||
|
private final List<ItemStack> salvage;
|
||||||
|
private final int itemsConsumed;
|
||||||
|
private final int enchantmentLevels;
|
||||||
|
protected final SalvageMethod salvageMethod;
|
||||||
|
private static final Random random = new Random();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new session
|
||||||
|
*
|
||||||
|
* @param scrapperTrait <p>A reference to the scrapper trait</p>
|
||||||
|
* @param player <p>The player initiating the session</p>
|
||||||
|
* @param npc <p>The scrapper NPC involved in the session</p>
|
||||||
|
* @param config <p>The config to use for the session</p>
|
||||||
|
* @param salvageMethod <p>The salvage method performed in this session</p>
|
||||||
|
* @param itemsConsumed <p>The number of items actually consumed, in case a salvaging fails</p>
|
||||||
|
*/
|
||||||
|
public SalvageSession(@NotNull ScrapperTrait scrapperTrait, @NotNull Player player, @NotNull NPC npc,
|
||||||
|
@NotNull ScrapperNPCSettings config, @NotNull List<ItemStack> salvage,
|
||||||
|
@NotNull SalvageMethod salvageMethod, int itemsConsumed) {
|
||||||
|
super(player, npc);
|
||||||
|
this.scrapperTrait = scrapperTrait;
|
||||||
|
this.itemToSalvage = player.getInventory().getItemInMainHand().clone();
|
||||||
|
this.config = config;
|
||||||
|
this.salvage = salvage;
|
||||||
|
this.enchantmentLevels = SalvageHelper.getTotalEnchantmentLevels(this.itemToSalvage);
|
||||||
|
this.salvageMethod = salvageMethod;
|
||||||
|
this.itemsConsumed = itemsConsumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSessionInvalid() {
|
||||||
|
// Prevent player from switching items during session
|
||||||
|
ItemStack itemInHand = this.player.getInventory().getItemInMainHand();
|
||||||
|
if (!itemToSalvage.equals(itemInHand)) {
|
||||||
|
sendNPCMessage(this.npc, this.player, this.config.getItemChangedMessage());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EconomyManager.cannotPayForSalvage(this.player, this.salvageMethod)) {
|
||||||
|
sendNPCMessage(this.npc, this.player, this.config.getInsufficientFundsMessage());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getActionDelay() {
|
||||||
|
if (this.config.getMaxSalvageDelay() > 0) {
|
||||||
|
//Finish the salvaging after a random delay between the max and min
|
||||||
|
return new Random().nextInt(this.config.getMaxSalvageDelay()) + this.config.getMinSalvageDelay();
|
||||||
|
} else {
|
||||||
|
//Finish the salvaging as soon as possible
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull Material getCraftingStation() {
|
||||||
|
return switch (this.salvageMethod) {
|
||||||
|
case EXTENDED_SALVAGE -> Material.CRAFTING_TABLE;
|
||||||
|
case SALVAGE -> Material.ANVIL;
|
||||||
|
case NETHERITE, ARMOR_TRIM -> Material.SMITHING_TABLE;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the actual salvage which fixes the item and gives it back to the player
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
salvageItem();
|
||||||
|
|
||||||
|
//Stop the reforged item from displaying in the scrapper's hand
|
||||||
|
if (this.npc.getEntity() instanceof Player) {
|
||||||
|
((Player) this.npc.getEntity()).getInventory().setItemInMainHand(null);
|
||||||
|
} else {
|
||||||
|
Objects.requireNonNull(((LivingEntity) this.npc.getEntity()).getEquipment()).setItemInMainHand(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Mark this scrapper as available
|
||||||
|
this.scrapperTrait.unsetSession();
|
||||||
|
|
||||||
|
// Start cool-down
|
||||||
|
Calendar wait = Calendar.getInstance();
|
||||||
|
wait.add(Calendar.SECOND, this.config.getSalvageCoolDown());
|
||||||
|
this.scrapperTrait.addCoolDown(this.player.getUniqueId(), wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of items consumed in order to perform the salvage
|
||||||
|
*
|
||||||
|
* @return <p>The number of items consumed as part of this salvage</p>
|
||||||
|
*/
|
||||||
|
public int getItemsConsumed() {
|
||||||
|
return this.itemsConsumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trues to salvage an item, and gives the return item
|
||||||
|
*/
|
||||||
|
private void salvageItem() {
|
||||||
|
if (random.nextInt(100) < this.config.getFailChance()) {
|
||||||
|
playSound(Sound.ENTITY_VILLAGER_NO);
|
||||||
|
failSalvage();
|
||||||
|
BlacksmithPlugin.getInstance().callEvent(new ScrapperSalvageFailEvent(this.npc, this.player));
|
||||||
|
} else {
|
||||||
|
playSound(Sound.BLOCK_ANVIL_USE);
|
||||||
|
giveSalvage();
|
||||||
|
BlacksmithPlugin.getInstance().callEvent(new ScrapperSalvageSucceedEvent(this.npc, this.player));
|
||||||
|
sendNPCMessage(this.npc, this.player, this.config.getSuccessMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The method to run when a crapper fails salvaging an item
|
||||||
|
*/
|
||||||
|
private void failSalvage() {
|
||||||
|
// Make sure the given amount is the same amount taken for salvage to avoid duplication
|
||||||
|
this.itemToSalvage.setAmount(itemsConsumed);
|
||||||
|
|
||||||
|
if (ItemHelper.getMaxDurability(this.itemToSalvage) > 0) {
|
||||||
|
//Damage the item if possible
|
||||||
|
damageItemRandomly(this.itemToSalvage);
|
||||||
|
giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), this.npc,
|
||||||
|
this.itemToSalvage);
|
||||||
|
sendNPCMessage(this.npc, this.player, this.config.getFailSalvageMessage());
|
||||||
|
} else {
|
||||||
|
// Give half the salvage
|
||||||
|
List<ItemStack> halfSalvage = SalvageHelper.pickRandomSalvage(this.salvage, new ArrayList<>(), 0.5);
|
||||||
|
for (ItemStack item : halfSalvage) {
|
||||||
|
giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), this.npc, item);
|
||||||
|
}
|
||||||
|
sendNPCMessage(this.npc, this.player, this.config.getFailExtendedSalvageMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives the player the calculated salvage
|
||||||
|
*/
|
||||||
|
private void giveSalvage() {
|
||||||
|
// TODO: Find a better calculation than 1 enchantment level = 1 exp level
|
||||||
|
// Gives the player back some of the EXP used on an item
|
||||||
|
this.player.giveExpLevels(this.enchantmentLevels);
|
||||||
|
BlacksmithPlugin.debug("Giving salvage " + this.salvage);
|
||||||
|
for (ItemStack item : this.salvage) {
|
||||||
|
giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), this.npc, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
313
src/main/java/net/knarcraft/blacksmith/trait/ScrapperTrait.java
Normal file
313
src/main/java/net/knarcraft/blacksmith/trait/ScrapperTrait.java
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
package net.knarcraft.blacksmith.trait;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.util.DataKey;
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.config.SmithPreset;
|
||||||
|
import net.knarcraft.blacksmith.config.SmithPresetFilter;
|
||||||
|
import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings;
|
||||||
|
import net.knarcraft.blacksmith.config.scrapper.ScrapperSetting;
|
||||||
|
import net.knarcraft.blacksmith.container.RecipeResult;
|
||||||
|
import net.knarcraft.blacksmith.container.SalvageResult;
|
||||||
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
||||||
|
import net.knarcraft.blacksmith.property.SalvageMethod;
|
||||||
|
import net.knarcraft.blacksmith.property.SalvageState;
|
||||||
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
|
import net.knarcraft.blacksmith.util.SalvageHelper;
|
||||||
|
import net.knarcraft.knarlib.formatting.StringFormatter;
|
||||||
|
import net.knarcraft.knarlib.formatting.StringReplacer;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ArmorMeta;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class representing a scrapper NPC trait
|
||||||
|
*/
|
||||||
|
public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
|
||||||
|
|
||||||
|
private final ScrapperNPCSettings config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new blacksmith trait
|
||||||
|
*/
|
||||||
|
public ScrapperTrait() {
|
||||||
|
super("scrapper");
|
||||||
|
//This should crash if the blacksmith plugin hasn't been properly registered
|
||||||
|
Bukkit.getServer().getPluginManager().getPlugin("Blacksmith");
|
||||||
|
this.config = new ScrapperNPCSettings(BlacksmithPlugin.getInstance().getGlobalScrapperSettings());
|
||||||
|
super.setTraitSettings(this.config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current settings for this NPC
|
||||||
|
*
|
||||||
|
* @return <p>The current settings for this NPC</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public ScrapperNPCSettings getSettings() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all config values stored in citizens' config file for this NPC
|
||||||
|
*
|
||||||
|
* @param key <p>The data key used for the config root</p>
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void load(@NotNull DataKey key) {
|
||||||
|
getSettings().loadVariables(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves all config values for this NPC
|
||||||
|
*
|
||||||
|
* @param key <p>The data key used for the config root</p>
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void save(@NotNull DataKey key) {
|
||||||
|
getSettings().saveVariables(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a new session, and prepares to repair the player's item
|
||||||
|
*
|
||||||
|
* @param player <p>The player to start the session for</p>
|
||||||
|
*/
|
||||||
|
public void startSession(@NotNull Player player) {
|
||||||
|
ItemStack itemInHand = player.getInventory().getItemInMainHand().clone();
|
||||||
|
if (itemInHand.getType().isAir()) {
|
||||||
|
sendNPCMessage(this.npc, player, config.getNoItemMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Material> salvageAbleItems = getSettings().getSalvageAbleItems();
|
||||||
|
boolean extended = getSettings().extendedSalvageEnabled();
|
||||||
|
|
||||||
|
// Check if the item can be salvaged
|
||||||
|
if (!canBeSalvaged(itemInHand, salvageAbleItems, extended)) {
|
||||||
|
sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(getSettings().getInvalidItemMessage(),
|
||||||
|
"{title}", getSettings().getScrapperTitle()));
|
||||||
|
BlacksmithPlugin.debug("Cannot salvage provided item: " + itemInHand);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SalvageResult result = getBestResult(player, itemInHand, extended);
|
||||||
|
|
||||||
|
if (result == null || result.salvage().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Start a new scrapper session for the player
|
||||||
|
currentSessionStartTime = System.currentTimeMillis();
|
||||||
|
session = new SalvageSession(this, player, npc, getSettings(), result.salvage(),
|
||||||
|
result.salvageMethod(), result.requiredAmount());
|
||||||
|
// Print the cost to the player
|
||||||
|
printCostMessage(player, itemInHand, EconomyManager.formatSalvageCost(result.salvageMethod()),
|
||||||
|
result.salvageMethod());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the best available salvage result
|
||||||
|
*
|
||||||
|
* @param player <p>The player attempting to salvage an item</p>
|
||||||
|
* @param itemInHand <p>The item the player is attempting to salvage</p>
|
||||||
|
* @param extended <p>Whether extended salvage is enabled</p>
|
||||||
|
* @return <p>The best result, or null if no valid result exists</p>
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private SalvageResult getBestResult(@NotNull Player player, @NotNull ItemStack itemInHand, boolean extended) {
|
||||||
|
SalvageResult result = isArmorTrimSalvage(player, itemInHand);
|
||||||
|
if (result.salvageState() == SalvageState.NO_SALVAGE) {
|
||||||
|
return null;
|
||||||
|
} else if (result.salvageState() == SalvageState.FOUND_SALVAGE) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = isNetheriteSalvage(player, itemInHand);
|
||||||
|
if (result.salvageState() == SalvageState.NO_SALVAGE) {
|
||||||
|
return null;
|
||||||
|
} else if (result.salvageState() == SalvageState.FOUND_SALVAGE) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = isNormalSalvage(player, itemInHand, extended);
|
||||||
|
if (result.salvageState() == SalvageState.NO_SALVAGE) {
|
||||||
|
return null;
|
||||||
|
} else if (result.salvageState() == SalvageState.FOUND_SALVAGE) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the result of trying to salvage the item normally
|
||||||
|
*
|
||||||
|
* @param player <p>The player trying to salvage the item</p>
|
||||||
|
* @param itemInHand <p>The item to be salvaged</p>
|
||||||
|
* @param extended <p>Whether extended salvage is enabled</p>
|
||||||
|
* @return <p>The result of attempting the salvage</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private SalvageResult isNormalSalvage(@NotNull Player player, @NotNull ItemStack itemInHand, boolean extended) {
|
||||||
|
|
||||||
|
// As there is no recipe for netherite items, the check needs to be after the netherite salvage check
|
||||||
|
if (!SalvageHelper.isSalvageable(player.getServer(), itemInHand)) {
|
||||||
|
sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(getSettings().getInvalidItemMessage(),
|
||||||
|
"{title}", getSettings().getScrapperTitle()));
|
||||||
|
BlacksmithPlugin.debug("Provided with non-salvage-able item " + itemInHand);
|
||||||
|
return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the item is enchanted, and whether this blacksmith can salvage it
|
||||||
|
if (!itemInHand.getEnchantments().isEmpty() && !getSettings().salvageEnchanted()) {
|
||||||
|
sendNPCMessage(this.npc, player, getSettings().getCannotSalvageEnchantedMessage());
|
||||||
|
return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if any salvage will be produced
|
||||||
|
RecipeResult recipeResult = getSalvage(itemInHand, extended);
|
||||||
|
SalvageMethod method = ItemHelper.isRepairable(itemInHand) ? SalvageMethod.SALVAGE : SalvageMethod.EXTENDED_SALVAGE;
|
||||||
|
boolean noUsefulSalvage = recipeResult == null || recipeResult.salvage().isEmpty();
|
||||||
|
if (noUsefulSalvage) {
|
||||||
|
sendNPCMessage(this.npc, player, getSettings().getTooDamagedMessage());
|
||||||
|
return new SalvageResult(method, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
|
} else {
|
||||||
|
return new SalvageResult(method, recipeResult.salvage(), SalvageState.FOUND_SALVAGE,
|
||||||
|
recipeResult.recipe().getResult().getAmount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the result of trying to salvage the item as a netherite applied item
|
||||||
|
*
|
||||||
|
* @param player <p>The player trying to salvage the item</p>
|
||||||
|
* @param itemInHand <p>The item to be salvaged</p>
|
||||||
|
* @return <p>The result of attempting the salvage</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private SalvageResult isNetheriteSalvage(@NotNull Player player, @NotNull ItemStack itemInHand) {
|
||||||
|
if (!SmithPreset.BLACKSMITH.getFilteredMaterials(SmithPresetFilter.NETHERITE).contains(itemInHand.getType())) {
|
||||||
|
return new SalvageResult(SalvageMethod.NETHERITE, new ArrayList<>(), SalvageState.INCORRECT_METHOD, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!getSettings().salvageNetherite()) {
|
||||||
|
sendNPCMessage(this.npc, player, getSettings().getCannotSalvageNetheriteMessage());
|
||||||
|
return new SalvageResult(SalvageMethod.NETHERITE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ItemStack> salvage = SalvageHelper.getNetheriteSalvage(itemInHand);
|
||||||
|
if (salvage == null || salvage.isEmpty()) {
|
||||||
|
return new SalvageResult(SalvageMethod.NETHERITE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SalvageResult(SalvageMethod.NETHERITE, salvage, SalvageState.FOUND_SALVAGE, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the result of trying to salvage the item as an armor trim
|
||||||
|
*
|
||||||
|
* @param player <p>The player trying to salvage the item</p>
|
||||||
|
* @param itemInHand <p>The item to be salvaged</p>
|
||||||
|
* @return <p>The result of attempting the salvage</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private SalvageResult isArmorTrimSalvage(@NotNull Player player, @NotNull ItemStack itemInHand) {
|
||||||
|
if (!(itemInHand.getItemMeta() instanceof ArmorMeta armorMeta) || !armorMeta.hasTrim()) {
|
||||||
|
return new SalvageResult(SalvageMethod.ARMOR_TRIM, new ArrayList<>(), SalvageState.INCORRECT_METHOD, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!getSettings().salvageArmorTrims()) {
|
||||||
|
sendNPCMessage(this.npc, player, getSettings().getCannotSalvageArmorTrimMessage());
|
||||||
|
return new SalvageResult(SalvageMethod.ARMOR_TRIM, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ItemStack> salvage = SalvageHelper.getArmorTrimSalvage(itemInHand, armorMeta);
|
||||||
|
if (salvage == null || salvage.isEmpty()) {
|
||||||
|
sendNPCMessage(this.npc, player, getSettings().getArmorTrimSalvageNotFoundMessage());
|
||||||
|
return new SalvageResult(SalvageMethod.ARMOR_TRIM, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SalvageResult(SalvageMethod.ARMOR_TRIM, salvage, SalvageState.FOUND_SALVAGE, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a message to the given player, explaining the cost of salvaging the held item
|
||||||
|
*
|
||||||
|
* @param player <p>The player that interacted with the scrapper</p>
|
||||||
|
* @param itemInHand <p>The item the player wants to salvage</p>
|
||||||
|
* @param cost <p>The cost of salvaging the item</p>
|
||||||
|
* @param salvageMethod <p>The type of salvage performed</p>
|
||||||
|
*/
|
||||||
|
private void printCostMessage(@NotNull Player player, @NotNull ItemStack itemInHand, @NotNull String cost,
|
||||||
|
@NotNull SalvageMethod salvageMethod) {
|
||||||
|
StringReplacer replacer = new StringReplacer();
|
||||||
|
replacer.add("{cost}", cost);
|
||||||
|
replacer.add("{item}", itemInHand.getType().name().toLowerCase().replace('_', ' '));
|
||||||
|
if (salvageMethod == SalvageMethod.ARMOR_TRIM) {
|
||||||
|
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getArmorTrimCostMessage()));
|
||||||
|
} else if (salvageMethod == SalvageMethod.SALVAGE || salvageMethod == SalvageMethod.EXTENDED_SALVAGE) {
|
||||||
|
String expectedYield;
|
||||||
|
if (ItemHelper.getDamage(itemInHand) <= 0) {
|
||||||
|
expectedYield = getSettings().getFullSalvageMessage();
|
||||||
|
} else {
|
||||||
|
expectedYield = getSettings().getPartialSalvageMessage();
|
||||||
|
}
|
||||||
|
replacer.add("{yield}", expectedYield);
|
||||||
|
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getCostMessage()));
|
||||||
|
} else if (salvageMethod == SalvageMethod.NETHERITE) {
|
||||||
|
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getNetheriteCostMessage()));
|
||||||
|
} else {
|
||||||
|
BlacksmithPlugin.error("Unrecognized salvage method " + salvageMethod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean showExactTime() {
|
||||||
|
return BlacksmithPlugin.getInstance().getGlobalScrapperSettings().showExactTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this scrapper can salvage the given item
|
||||||
|
*
|
||||||
|
* @param item <p>The item to check</p>
|
||||||
|
* @param salvageAbleItems <p>The items this scrapper can salvage</p>
|
||||||
|
* @param extended <p>Whether extended salvage is enabled</p>
|
||||||
|
* @return <p>True if the item can be theoretically salvaged</p>
|
||||||
|
*/
|
||||||
|
private boolean canBeSalvaged(@NotNull ItemStack item, @NotNull List<Material> salvageAbleItems, boolean extended) {
|
||||||
|
return (extended || ItemHelper.isRepairable(item)) &&
|
||||||
|
(salvageAbleItems.isEmpty() || salvageAbleItems.contains(item.getType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets salvage for an item, if it's salvage-able
|
||||||
|
*
|
||||||
|
* @param item <p>The item to calculate salvage for</p>
|
||||||
|
* @param extended <p>Whether extended salvage is enabled</p>
|
||||||
|
* @return <p>The possible salvage, or null if not salvage-able</p>
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private RecipeResult getSalvage(@NotNull ItemStack item, boolean extended) {
|
||||||
|
// Get the salvage, for the item, but ignore some materials if set, and the item isn't at full durability
|
||||||
|
Set<Material> trashSalvage = BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getTrashSalvage(
|
||||||
|
item.getType());
|
||||||
|
// Don't ignore salvage for fully repaired items
|
||||||
|
if (trashSalvage == null || ItemHelper.getDamage(item) == 0) {
|
||||||
|
trashSalvage = new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return SalvageHelper.getSalvage(BlacksmithPlugin.getInstance().getServer(), item, trashSalvage, extended);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
200
src/main/java/net/knarcraft/blacksmith/trait/Session.java
Normal file
200
src/main/java/net/knarcraft/blacksmith/trait/Session.java
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
package net.knarcraft.blacksmith.trait;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.event.BlacksmithReforgeStartEvent;
|
||||||
|
import net.knarcraft.blacksmith.event.NPCSoundEvent;
|
||||||
|
import net.knarcraft.blacksmith.event.ScrapperSalvageStartEvent;
|
||||||
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.SoundCategory;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.scheduler.BukkitScheduler;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A runnable session for performing a reforging/salvage task
|
||||||
|
*/
|
||||||
|
public abstract class Session implements Runnable {
|
||||||
|
|
||||||
|
protected static final Random random = new Random();
|
||||||
|
protected final Player player;
|
||||||
|
protected final NPC npc;
|
||||||
|
protected long finishTime;
|
||||||
|
protected int taskId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new session
|
||||||
|
*
|
||||||
|
* @param player <p>The player the session belongs to</p>
|
||||||
|
* @param npc <p>The NPC involved in the session</p>
|
||||||
|
*/
|
||||||
|
public Session(@NotNull Player player, @NotNull NPC npc) {
|
||||||
|
this.player = player;
|
||||||
|
this.npc = npc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether the given player is currently in a reforging session
|
||||||
|
*
|
||||||
|
* @param other <p>The player to check if is in session</p>
|
||||||
|
* @return <p>False if the given player is in a reforge session</p>
|
||||||
|
*/
|
||||||
|
public boolean isNotInSession(@NotNull Player other) {
|
||||||
|
return !player.getUniqueId().equals(other.getUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the player currently in this reforge session
|
||||||
|
*
|
||||||
|
* @return <p>The player currently in this reforge session</p>
|
||||||
|
*/
|
||||||
|
public @NotNull Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether the current session is invalid, and should be ended
|
||||||
|
*
|
||||||
|
* <p>If the player has switched their item, the player cannot pay, or some other condition fails,
|
||||||
|
* this returns true.</p>
|
||||||
|
*
|
||||||
|
* @return <p>True if the current session should end</p>
|
||||||
|
*/
|
||||||
|
public abstract boolean isSessionInvalid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether the current session is still running
|
||||||
|
*
|
||||||
|
* @return <p>True if the current session is still running</p>
|
||||||
|
*/
|
||||||
|
public boolean isRunning() {
|
||||||
|
return BlacksmithPlugin.getInstance().getServer().getScheduler().isQueued(taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the time in milliseconds when this session's action will finish
|
||||||
|
*
|
||||||
|
* <p>This returns 0 if the action hasn't been run yet.</p>
|
||||||
|
*
|
||||||
|
* @return <p>The timestamp for when the action will finish</p>
|
||||||
|
*/
|
||||||
|
public long getFinishTime() {
|
||||||
|
return this.finishTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules this session's main task for after the action delay has passed
|
||||||
|
*/
|
||||||
|
public void scheduleAction() {
|
||||||
|
if (isRunning()) {
|
||||||
|
throw new IllegalStateException("Session action tried to run twice!");
|
||||||
|
}
|
||||||
|
BukkitScheduler scheduler = BlacksmithPlugin.getInstance().getServer().getScheduler();
|
||||||
|
int actionDelay = getActionDelay();
|
||||||
|
this.finishTime = System.currentTimeMillis() + (actionDelay * 1000L);
|
||||||
|
long actionDelayTicks = actionDelay * 20L;
|
||||||
|
|
||||||
|
BlacksmithPlugin instance = BlacksmithPlugin.getInstance();
|
||||||
|
if (this instanceof ReforgeSession) {
|
||||||
|
instance.callEvent(new BlacksmithReforgeStartEvent(npc, player, actionDelayTicks, getCraftingStation()));
|
||||||
|
} else if (this instanceof SalvageSession) {
|
||||||
|
instance.callEvent(new ScrapperSalvageStartEvent(npc, player, actionDelayTicks, getCraftingStation()));
|
||||||
|
}
|
||||||
|
|
||||||
|
taskId = scheduler.scheduleSyncDelayedTask(BlacksmithPlugin.getInstance(), this, actionDelayTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives the resulting item to the player
|
||||||
|
*
|
||||||
|
* @param hasDelay <p>Whether the session was delayed, or if the item was processed instantly</p>
|
||||||
|
* @param dropItem <p>Whether the item should be dropped on the ground</p>
|
||||||
|
* @param npc <p>The NPC holding the item</p>
|
||||||
|
* @param itemToReturn <p>The item to return to the player</p>
|
||||||
|
*/
|
||||||
|
protected void giveResultingItem(boolean hasDelay, boolean dropItem, @NotNull NPC npc, @NotNull ItemStack itemToReturn) {
|
||||||
|
if (hasDelay) {
|
||||||
|
//If the player isn't online, or the player cannot fit the item, drop the item to prevent it from disappearing
|
||||||
|
if (dropItem || !this.player.isOnline() || !ItemHelper.canFitItem(this.player.getInventory(), itemToReturn)) {
|
||||||
|
this.player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), itemToReturn);
|
||||||
|
} else {
|
||||||
|
this.player.getInventory().addItem(itemToReturn);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//It can be assumed as this happens instantly, that the player still has the item's previous slot selected
|
||||||
|
this.player.getInventory().setItemInMainHand(itemToReturn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Randomly damages the given item
|
||||||
|
*
|
||||||
|
* @param item <p>The item to damage</p>
|
||||||
|
*/
|
||||||
|
protected void damageItemRandomly(@NotNull ItemStack item) {
|
||||||
|
short currentItemDurability = ItemHelper.getDurability(item);
|
||||||
|
short newDurability = (short) (currentItemDurability + (currentItemDurability * random.nextInt(8)));
|
||||||
|
short maxDurability = item.getType().getMaxDurability();
|
||||||
|
if (newDurability <= 0) {
|
||||||
|
newDurability = (short) (maxDurability / 3);
|
||||||
|
} else if (currentItemDurability + newDurability > maxDurability) {
|
||||||
|
newDurability = (short) (maxDurability - random.nextInt(maxDurability - 25));
|
||||||
|
}
|
||||||
|
if (ItemHelper.updateDamage(item, maxDurability - newDurability)) {
|
||||||
|
BlacksmithPlugin.warn("Unable to update damage for " + item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the delay for this session's action to finish
|
||||||
|
*
|
||||||
|
* @return <p>The delay to wait for this session's action to finish</p>
|
||||||
|
*/
|
||||||
|
protected abstract int getActionDelay();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the appropriate crafting station for this session
|
||||||
|
*
|
||||||
|
* @return <p>The appropriate crafting station</p>
|
||||||
|
*/
|
||||||
|
protected abstract @NotNull Material getCraftingStation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plays an NPC sound
|
||||||
|
*
|
||||||
|
* @param sound <p>The sound to play</p>
|
||||||
|
*/
|
||||||
|
protected void playSound(Sound sound) {
|
||||||
|
playSound(this.npc.getEntity(), sound);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plays a npc sound using a cancellable event
|
||||||
|
*
|
||||||
|
* @param entity <p>The entity that should play the sound</p>
|
||||||
|
* @param sound <p>The sound to play</p>
|
||||||
|
*/
|
||||||
|
private void playSound(@NotNull Entity entity, @NotNull Sound sound) {
|
||||||
|
World world = entity.getLocation().getWorld();
|
||||||
|
if (world == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NPCSoundEvent event = new NPCSoundEvent(this.npc, this.player, SoundCategory.AMBIENT, sound, 0.5f, 1.0f);
|
||||||
|
BlacksmithPlugin.getInstance().callEvent(event);
|
||||||
|
if (event.isCancelled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
world.playSound(event.getNpc().getEntity(), event.getSound(), event.getSoundCategory(), event.getVolume(),
|
||||||
|
event.getPitch());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
package net.knarcraft.blacksmith.util;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.config.Setting;
|
||||||
|
import net.knarcraft.blacksmith.config.SettingValueType;
|
||||||
|
import net.knarcraft.blacksmith.config.Settings;
|
||||||
|
import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
|
||||||
|
import net.knarcraft.knarlib.formatting.StringFormatter;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage.getCurrentValueMessage;
|
||||||
|
import static net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage.getDefaultValueMessage;
|
||||||
|
import static net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage.getValueChangedMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper class for the configuration command
|
||||||
|
*/
|
||||||
|
public final class ConfigCommandHelper {
|
||||||
|
|
||||||
|
private ConfigCommandHelper() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the value of the setting defined in the user's input
|
||||||
|
*
|
||||||
|
* @param args <p>The arguments given by the user</p>
|
||||||
|
* @param detectedSetting <p>The setting recognized from the input, if any</p>
|
||||||
|
* @param settings <p>The global settings object to get settings from</p>
|
||||||
|
* @param sender <p>The command sender to display any output to</p>
|
||||||
|
*/
|
||||||
|
public static <K extends Setting> void changeValue(@NotNull String[] args,
|
||||||
|
@NotNull K detectedSetting,
|
||||||
|
@NotNull Settings<K> settings,
|
||||||
|
@NotNull CommandSender sender) {
|
||||||
|
String newValue = args[1];
|
||||||
|
//This makes sure all arguments are treated as a sentence
|
||||||
|
if (detectedSetting.getValueType() == SettingValueType.STRING) {
|
||||||
|
newValue = String.join(" ", Arrays.asList(args).subList(1, args.length));
|
||||||
|
}
|
||||||
|
settings.changeValue(detectedSetting, newValue);
|
||||||
|
BlacksmithPlugin.getStringFormatter().displaySuccessMessage(sender,
|
||||||
|
getValueChangedMessage(detectedSetting.getCommandName(), newValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the current value of the selected setting
|
||||||
|
*
|
||||||
|
* @param setting <p>The global setting recognized from the input</p>
|
||||||
|
* @param settings <p>The global settings object to get settings from</p>
|
||||||
|
* @param sender <p>The command sender to display any output to</p>
|
||||||
|
*/
|
||||||
|
public static <K extends Setting> void displayCurrentValue(@NotNull K setting,
|
||||||
|
@NotNull Settings<K> settings,
|
||||||
|
@NotNull CommandSender sender) {
|
||||||
|
StringFormatter formatter = BlacksmithPlugin.getStringFormatter();
|
||||||
|
boolean printRawValue = false;
|
||||||
|
|
||||||
|
//Find the value of the specified setting
|
||||||
|
String currentValue = String.valueOf(settings.getRawValue(setting));
|
||||||
|
String defaultValue = String.valueOf(setting.getDefaultValue());
|
||||||
|
|
||||||
|
//For messages, print an additional raw value showing which color codes are used
|
||||||
|
if (setting.isPerNPC() && setting.isMessage()) {
|
||||||
|
printRawValue = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the description of the setting
|
||||||
|
formatter.displaySuccessMessage(sender, setting.getDescription());
|
||||||
|
|
||||||
|
// Display the setting's default value
|
||||||
|
formatter.displayNeutralMessage(sender, getDefaultValueMessage(setting.getCommandName(), defaultValue));
|
||||||
|
if (printRawValue) {
|
||||||
|
displayRaw(sender, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the current value of the setting
|
||||||
|
formatter.displayNeutralMessage(sender, getCurrentValueMessage(setting.getCommandName(), currentValue));
|
||||||
|
if (printRawValue) {
|
||||||
|
displayRaw(sender, currentValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a message with formatting codes shown
|
||||||
|
*
|
||||||
|
* @param sender <p>The sender to display the raw value to</p>
|
||||||
|
* @param value <p>The value to display raw</p>
|
||||||
|
*/
|
||||||
|
public static void displayRaw(@NotNull CommandSender sender, @NotNull String value) {
|
||||||
|
sender.sendMessage(BlacksmithTranslatableMessage.getRawValueMessage(
|
||||||
|
value.replace(ChatColor.COLOR_CHAR, '&')));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,22 @@
|
|||||||
package net.knarcraft.blacksmith.util;
|
package net.knarcraft.blacksmith.util;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.config.StargateYamlConfiguration;
|
||||||
|
import net.knarcraft.knarlib.property.ColorConversion;
|
||||||
|
import net.knarcraft.knarlib.util.FileHelper;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.configuration.MemorySection;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper class for getting an object value as the correct type
|
* A helper class for getting an object value as the correct type
|
||||||
@ -16,18 +31,22 @@ public final class ConfigHelper {
|
|||||||
* Gets the given value as a string list
|
* Gets the given value as a string list
|
||||||
*
|
*
|
||||||
* @param value <p>The raw string list value</p>
|
* @param value <p>The raw string list value</p>
|
||||||
* @return <p>The value as a string list</p>
|
* @return <p>The value as a string list, or null if not compatible</p>
|
||||||
*/
|
*/
|
||||||
public static List<String> asStringList(Object value) {
|
public static @Nullable List<String> asStringList(@Nullable Object value) {
|
||||||
if (value instanceof String) {
|
if (value == null) {
|
||||||
return List.of(((String) value).split(","));
|
return new ArrayList<>();
|
||||||
} else {
|
}
|
||||||
|
if (value instanceof String string) {
|
||||||
|
return List.of((string).split(","));
|
||||||
|
} else if (value instanceof List<?> list) {
|
||||||
List<String> strings = new ArrayList<>();
|
List<String> strings = new ArrayList<>();
|
||||||
List<?> list = (List<?>) value;
|
|
||||||
for (Object object : list) {
|
for (Object object : list) {
|
||||||
strings.add(String.valueOf(object));
|
strings.add(String.valueOf(object));
|
||||||
}
|
}
|
||||||
return strings;
|
return strings;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,8 +57,10 @@ public final class ConfigHelper {
|
|||||||
*
|
*
|
||||||
* @param value <p>The object value to get</p>
|
* @param value <p>The object value to get</p>
|
||||||
* @return <p>The value of the given object as a double</p>
|
* @return <p>The value of the given object as a double</p>
|
||||||
|
* @throws ClassCastException <p>If a non-double is given as input</p>
|
||||||
|
* @throws NumberFormatException <p>If a non-double is given as input</p>
|
||||||
*/
|
*/
|
||||||
public static double asDouble(Object value) {
|
public static double asDouble(@NotNull Object value) throws ClassCastException, NumberFormatException {
|
||||||
if (value instanceof String) {
|
if (value instanceof String) {
|
||||||
return Double.parseDouble((String) value);
|
return Double.parseDouble((String) value);
|
||||||
} else if (value instanceof Integer) {
|
} else if (value instanceof Integer) {
|
||||||
@ -56,12 +77,15 @@ public final class ConfigHelper {
|
|||||||
*
|
*
|
||||||
* @param value <p>The object value to get</p>
|
* @param value <p>The object value to get</p>
|
||||||
* @return <p>The value of the given object as a boolean</p>
|
* @return <p>The value of the given object as a boolean</p>
|
||||||
|
* @throws ClassCastException <p>If the given value is not a boolean</p>
|
||||||
*/
|
*/
|
||||||
public static boolean asBoolean(Object value) {
|
public static boolean asBoolean(@NotNull Object value) throws ClassCastException {
|
||||||
if (value instanceof String) {
|
if (value instanceof Boolean booleanValue) {
|
||||||
|
return booleanValue;
|
||||||
|
} else if (value instanceof String) {
|
||||||
return Boolean.parseBoolean((String) value);
|
return Boolean.parseBoolean((String) value);
|
||||||
} else {
|
} else {
|
||||||
return (Boolean) value;
|
throw new ClassCastException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,8 +96,9 @@ public final class ConfigHelper {
|
|||||||
*
|
*
|
||||||
* @param value <p>The object value to get</p>
|
* @param value <p>The object value to get</p>
|
||||||
* @return <p>The value of the given object as an integer</p>
|
* @return <p>The value of the given object as an integer</p>
|
||||||
|
* @throws ClassCastException <p>If the given value is not an integer</p>
|
||||||
*/
|
*/
|
||||||
public static int asInt(Object value) {
|
public static int asInt(@NotNull Object value) throws ClassCastException {
|
||||||
if (value instanceof String) {
|
if (value instanceof String) {
|
||||||
return Integer.parseInt((String) value);
|
return Integer.parseInt((String) value);
|
||||||
} else {
|
} else {
|
||||||
@ -81,4 +106,103 @@ public final class ConfigHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes all configuration values from the old name to the new name
|
||||||
|
*
|
||||||
|
* @param dataFolderPath <p>The path to this plugin's data</p>
|
||||||
|
* @param currentConfiguration <p>The current config to back up</p>
|
||||||
|
*/
|
||||||
|
public static void migrateConfig(@NotNull String dataFolderPath, @NotNull FileConfiguration currentConfiguration) {
|
||||||
|
BlacksmithPlugin instance = BlacksmithPlugin.getInstance();
|
||||||
|
|
||||||
|
//Save the old config just in case something goes wrong
|
||||||
|
try {
|
||||||
|
currentConfiguration.save(new File(dataFolderPath, "config.yml.old"));
|
||||||
|
} catch (IOException exception) {
|
||||||
|
BlacksmithPlugin.warn("Unable to save old backup and do migration");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Load old and new configuration
|
||||||
|
instance.reloadConfig();
|
||||||
|
FileConfiguration oldConfiguration = instance.getConfig();
|
||||||
|
InputStream configStream = FileHelper.getInputStreamForInternalFile("/config.yml");
|
||||||
|
if (configStream == null) {
|
||||||
|
BlacksmithPlugin.error("Could not migrate the configuration, as the internal configuration could not be read!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
YamlConfiguration newConfiguration = StargateYamlConfiguration.loadConfiguration(
|
||||||
|
FileHelper.getBufferedReaderFromInputStream(configStream));
|
||||||
|
|
||||||
|
//Read all available config migrations
|
||||||
|
Map<String, String> migrationFields;
|
||||||
|
try {
|
||||||
|
InputStream migrationStream = FileHelper.getInputStreamForInternalFile("/config-migrations.txt");
|
||||||
|
if (migrationStream == null) {
|
||||||
|
BlacksmithPlugin.error("Could not migrate the configuration, as the internal migration paths could not be read!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
migrationFields = FileHelper.readKeyValuePairs(FileHelper.getBufferedReaderFromInputStream(migrationStream),
|
||||||
|
"=", ColorConversion.NORMAL);
|
||||||
|
} catch (IOException exception) {
|
||||||
|
BlacksmithPlugin.warn("Unable to load config migration file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Replace old config names with the new ones
|
||||||
|
for (String key : migrationFields.keySet()) {
|
||||||
|
if (oldConfiguration.contains(key)) {
|
||||||
|
migrateProperty(migrationFields, key, oldConfiguration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy all keys to the new config
|
||||||
|
for (String key : StargateYamlConfiguration.getKeysWithoutComments(oldConfiguration, true)) {
|
||||||
|
if (oldConfiguration.get(key) instanceof MemorySection) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
newConfiguration.set(key, oldConfiguration.get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
newConfiguration.save(new File(dataFolderPath, "config.yml"));
|
||||||
|
} catch (IOException exception) {
|
||||||
|
BlacksmithPlugin.warn("Unable to save migrated config");
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.reloadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrates one configuration property
|
||||||
|
*
|
||||||
|
* @param migrationFields <p>The configuration fields to be migrated</p>
|
||||||
|
* @param key <p>The key/path of the property to migrate</p>
|
||||||
|
* @param oldConfiguration <p>The original pre-migration configuration</p>
|
||||||
|
*/
|
||||||
|
private static void migrateProperty(@NotNull Map<String, String> migrationFields, @NotNull String key,
|
||||||
|
@NotNull FileConfiguration oldConfiguration) {
|
||||||
|
String newPath = migrationFields.get(key);
|
||||||
|
Object oldValue = oldConfiguration.get(key);
|
||||||
|
if (!newPath.trim().isEmpty()) {
|
||||||
|
if (oldConfiguration.isConfigurationSection(key)) {
|
||||||
|
// Copy each value of a configuration section
|
||||||
|
ConfigurationSection sourceSection = oldConfiguration.getConfigurationSection(key);
|
||||||
|
ConfigurationSection destinationSection = oldConfiguration.createSection(newPath);
|
||||||
|
if (sourceSection == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (String path : StargateYamlConfiguration.getKeysWithoutComments(sourceSection, true)) {
|
||||||
|
destinationSection.set(path, sourceSection.get(path));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Copy the value to the new path
|
||||||
|
oldConfiguration.set(newPath, oldValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the old path's value
|
||||||
|
oldConfiguration.set(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
package net.knarcraft.blacksmith.util;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A helper class for dealing with files
|
|
||||||
*/
|
|
||||||
public final class FileHelper {
|
|
||||||
|
|
||||||
private FileHelper() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a buffered reader for
|
|
||||||
*
|
|
||||||
* @return <p>A buffered read for reading the file</p>
|
|
||||||
* @throws FileNotFoundException <p>If unable to get an input stream for the given file</p>
|
|
||||||
*/
|
|
||||||
public static BufferedReader getBufferedReaderForInternalFile(String file) throws FileNotFoundException {
|
|
||||||
InputStream inputStream = FileHelper.class.getResourceAsStream(file);
|
|
||||||
if (inputStream == null) {
|
|
||||||
throw new FileNotFoundException("Unable to read the given file");
|
|
||||||
}
|
|
||||||
return new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,8 +1,12 @@
|
|||||||
package net.knarcraft.blacksmith.util;
|
package net.knarcraft.blacksmith.util;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.Registry;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper class for parsing input into proper object types
|
* A helper class for parsing input into proper object types
|
||||||
@ -19,9 +23,9 @@ public final class InputParsingHelper {
|
|||||||
* @param input <p>The input to check</p>
|
* @param input <p>The input to check</p>
|
||||||
* @return <p>True if the value is empty</p>
|
* @return <p>True if the value is empty</p>
|
||||||
*/
|
*/
|
||||||
public static boolean isEmpty(String input) {
|
public static boolean isEmpty(@Nullable String input) {
|
||||||
return input == null || input.equalsIgnoreCase("null") || input.equals("\"\"") ||
|
return input == null || input.equalsIgnoreCase("null") || input.equals("\"\"") ||
|
||||||
input.trim().isEmpty() || input.equals("-1");
|
input.isBlank() || input.equals("-1");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,7 +34,7 @@ public final class InputParsingHelper {
|
|||||||
* @param input <p>The string to match to a material</p>
|
* @param input <p>The string to match to a material</p>
|
||||||
* @return <p>The material matching the string, or null if not found</p>
|
* @return <p>The material matching the string, or null if not found</p>
|
||||||
*/
|
*/
|
||||||
public static Material matchMaterial(String input) {
|
public static @Nullable Material matchMaterial(@NotNull String input) {
|
||||||
return Material.matchMaterial(input.replace("-", "_"));
|
return Material.matchMaterial(input.replace("-", "_"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,8 +44,28 @@ public final class InputParsingHelper {
|
|||||||
* @param input <p>The string to match to an enchantment</p>
|
* @param input <p>The string to match to an enchantment</p>
|
||||||
* @return <p>The enchantment matching the string, or null if not found</p>
|
* @return <p>The enchantment matching the string, or null if not found</p>
|
||||||
*/
|
*/
|
||||||
public static Enchantment matchEnchantment(String input) {
|
public static @Nullable Enchantment matchEnchantment(@NotNull String input) {
|
||||||
return Enchantment.getByKey(NamespacedKey.minecraft(input.replace("-", "_")));
|
try {
|
||||||
|
Registry<Enchantment> enchantments = Bukkit.getRegistry(Enchantment.class);
|
||||||
|
if (enchantments == null) {
|
||||||
|
throw new RuntimeException("Unable to get enchantment registry");
|
||||||
|
}
|
||||||
|
return enchantments.get(NamespacedKey.minecraft(
|
||||||
|
input.replace("-", "_").replace(" ", "_").toLowerCase()));
|
||||||
|
} catch (IllegalArgumentException exception) {
|
||||||
|
//Invalid characters, such as : will normally throw an illegal argument exception
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a material name like "*helmet" into a regular expression ".*HELMET"
|
||||||
|
*
|
||||||
|
* @param input <p>The input to RegExIfy</p>
|
||||||
|
* @return <p>The converted input</p>
|
||||||
|
*/
|
||||||
|
public static @NotNull String regExIfy(@NotNull String input) {
|
||||||
|
return input.replace("*", ".*").toUpperCase().replace("-", "_");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,65 @@
|
|||||||
package net.knarcraft.blacksmith.util;
|
package net.knarcraft.blacksmith.util;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.config.SmithPreset;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.Damageable;
|
import org.bukkit.inventory.meta.Damageable;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper class for getting information about items
|
||||||
|
*/
|
||||||
public final class ItemHelper {
|
public final class ItemHelper {
|
||||||
|
|
||||||
private ItemHelper() {
|
private ItemHelper() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether the given item is repairable
|
||||||
|
*
|
||||||
|
* @param item <p>The item to check</p>
|
||||||
|
* @return <p>True if the item is repairable</p>
|
||||||
|
*/
|
||||||
|
public static boolean isRepairable(@NotNull ItemStack item) {
|
||||||
|
return item.getItemMeta() instanceof Damageable && getMaxDurability(item) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the max durability of an item
|
||||||
|
*
|
||||||
|
* @param itemStack <p>The item to get the durability of</p>
|
||||||
|
* @return <p>The max durability of the item</p>
|
||||||
|
*/
|
||||||
|
public static short getMaxDurability(@NotNull ItemStack itemStack) {
|
||||||
|
if (itemStack.getItemMeta() instanceof Damageable) {
|
||||||
|
return itemStack.getType().getMaxDurability();
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current durability of the given item
|
* Gets the current durability of the given item
|
||||||
*
|
*
|
||||||
* @param itemStack <p>The item to get the durability of</p>
|
* @param itemStack <p>The item to get the durability of</p>
|
||||||
* @return <p>The durability of the item</p>
|
* @return <p>The durability of the item</p>
|
||||||
*/
|
*/
|
||||||
public static short getDurability(ItemStack itemStack) {
|
public static short getDurability(@NotNull ItemStack itemStack) {
|
||||||
Damageable damageable = (Damageable) itemStack.getItemMeta();
|
if (itemStack.getItemMeta() instanceof Damageable damageable) {
|
||||||
int maxDurability = itemStack.getType().getMaxDurability();
|
int maxDurability = getMaxDurability(itemStack);
|
||||||
if (damageable != null) {
|
|
||||||
return (short) (maxDurability - damageable.getDamage());
|
return (short) (maxDurability - damageable.getDamage());
|
||||||
} else {
|
} else {
|
||||||
return (short) maxDurability;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,13 +69,195 @@ public final class ItemHelper {
|
|||||||
* @param itemStack <p>The damage done to the item</p>
|
* @param itemStack <p>The damage done to the item</p>
|
||||||
* @return <p>The damage done to the item</p>
|
* @return <p>The damage done to the item</p>
|
||||||
*/
|
*/
|
||||||
public static short getDamage(ItemStack itemStack) {
|
public static short getDamage(@NotNull ItemStack itemStack) {
|
||||||
Damageable damageable = (Damageable) itemStack.getItemMeta();
|
if (itemStack.getItemMeta() instanceof Damageable damageable) {
|
||||||
if (damageable != null) {
|
|
||||||
return (short) damageable.getDamage();
|
return (short) damageable.getDamage();
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the damage done to an item
|
||||||
|
*
|
||||||
|
* @param item <p>The item to update damage for</p>
|
||||||
|
* @param newDamage <p>The new damage done</p>
|
||||||
|
* @return <p>False if the damage was updated. False if not damageable.</p>
|
||||||
|
*/
|
||||||
|
public static boolean updateDamage(@NotNull ItemStack item, int newDamage) {
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (!(meta instanceof Damageable damageable)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
damageable.setDamage(newDamage);
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a complete list of all reforge-able materials
|
||||||
|
*
|
||||||
|
* <p>Note: As this loops through all materials, the result should be cached</p>
|
||||||
|
*
|
||||||
|
* @return <p>A complete list of reforge-able materials</p>
|
||||||
|
*/
|
||||||
|
public static @NotNull Set<Material> getAllReforgeAbleMaterials() {
|
||||||
|
Set<Material> reforgeAbleMaterials = new HashSet<>();
|
||||||
|
for (Material material : Material.values()) {
|
||||||
|
if (!material.isItem()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ItemStack item = new ItemStack(material);
|
||||||
|
if (isRepairable(item)) {
|
||||||
|
reforgeAbleMaterials.add(material);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reforgeAbleMaterials;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given material is an anvil
|
||||||
|
*
|
||||||
|
* @param material <p>The material to check</p>
|
||||||
|
* @param requireDamaged <p>Whether only a damaged anvil should count</p>
|
||||||
|
* @return <p>True if the given material is an anvil</p>
|
||||||
|
*/
|
||||||
|
public static boolean isAnvil(@NotNull Material material, boolean requireDamaged) {
|
||||||
|
boolean isDamagedAnvil = material == Material.CHIPPED_ANVIL || material == Material.DAMAGED_ANVIL;
|
||||||
|
boolean isAnvil = isDamagedAnvil || material == Material.ANVIL;
|
||||||
|
return (requireDamaged && isDamagedAnvil) || (!requireDamaged && isAnvil);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given inventory is able to fit the given item
|
||||||
|
*
|
||||||
|
* @param inventory <p>The inventory to check</p>
|
||||||
|
* @param item <p>The item to check</p>
|
||||||
|
* @return <p>True if the inventory can fit the item</p>
|
||||||
|
*/
|
||||||
|
public static boolean canFitItem(@NotNull Inventory inventory, @NotNull ItemStack item) {
|
||||||
|
// If a slot is available, there is no problem
|
||||||
|
if (inventory.firstEmpty() != -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the inventory doesn't contain the correct type of item, stacking is impossible
|
||||||
|
if (!inventory.contains(item.getType())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the item stack can fit in the inventory if stacked with existing items
|
||||||
|
int availableSlots = 0;
|
||||||
|
for (ItemStack itemStack : inventory.getStorageContents()) {
|
||||||
|
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||||
|
ItemMeta targetMeta = item.getItemMeta();
|
||||||
|
// Skip items of a different type, or with metadata that would prevent stacking
|
||||||
|
if (itemStack.getType() != item.getType() ||
|
||||||
|
(itemMeta != null && targetMeta != null && !itemMeta.equals(targetMeta))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
availableSlots += itemStack.getMaxStackSize() - itemStack.getAmount();
|
||||||
|
|
||||||
|
if (availableSlots < item.getAmount()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all materials matching the given material wildcard
|
||||||
|
*
|
||||||
|
* @param materialName <p>The material name or material wildcard to match</p>
|
||||||
|
* @param extended <p>Whether to use an extended match, allowing any material</p>
|
||||||
|
* @return <p>The matched material(s)</p>
|
||||||
|
*/
|
||||||
|
public static @NotNull Set<Material> getWildcardMatch(@NotNull String materialName, boolean extended) {
|
||||||
|
String search = InputParsingHelper.regExIfy(materialName);
|
||||||
|
Set<Material> materials = new HashSet<>();
|
||||||
|
Set<Material> all;
|
||||||
|
if (extended) {
|
||||||
|
all = Set.of(Material.values());
|
||||||
|
} else {
|
||||||
|
all = ItemHelper.getAllReforgeAbleMaterials();
|
||||||
|
}
|
||||||
|
for (Material material : all) {
|
||||||
|
if (material.name().matches(search)) {
|
||||||
|
materials.add(material);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return materials;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of the items described in the given item list
|
||||||
|
*
|
||||||
|
* @param itemList <p>The list of items defined by the user</p>
|
||||||
|
* @param requireRepairable <p>Whether a material must be repairable to be valid.</p>
|
||||||
|
* @return <p>The materials contained in the item list</p>
|
||||||
|
*/
|
||||||
|
public static List<Material> getItems(@Nullable List<String> itemList, boolean requireRepairable) {
|
||||||
|
List<Material> items = new ArrayList<>();
|
||||||
|
if (itemList == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Convert any presets with a list of materials
|
||||||
|
itemList = replacePresets(itemList);
|
||||||
|
|
||||||
|
Set<Material> blacklisted = new HashSet<>();
|
||||||
|
//Parse every material, and add to reforgeAble items
|
||||||
|
for (String item : itemList) {
|
||||||
|
//Ignore ",,"
|
||||||
|
if (InputParsingHelper.isEmpty(item) || item.matches("\\[]")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean blacklist = false;
|
||||||
|
if (item.startsWith("-")) {
|
||||||
|
blacklist = true;
|
||||||
|
item = item.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Material material = InputParsingHelper.matchMaterial(item);
|
||||||
|
if (material != null && (!requireRepairable || ItemHelper.isRepairable(new ItemStack(material, 1)))) {
|
||||||
|
if (!blacklist) {
|
||||||
|
items.add(material);
|
||||||
|
} else {
|
||||||
|
blacklisted.add(material);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
BlacksmithPlugin.warn("Unable to verify " + item + " as a valid repairable item");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Remove any blacklisted materials at the end to make sure order of arguments won't matter
|
||||||
|
items.removeAll(blacklisted);
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces smith presets in the given list of strings
|
||||||
|
*
|
||||||
|
* @param stringList <p>The value specified by a user</p>
|
||||||
|
* @return <p>The value with smith presets replaced</p>
|
||||||
|
*/
|
||||||
|
private static @NotNull List<String> replacePresets(@NotNull List<String> stringList) {
|
||||||
|
List<String> newStrings = new ArrayList<>();
|
||||||
|
for (String item : stringList) {
|
||||||
|
if (item == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String replaced = SmithPreset.replacePreset(item);
|
||||||
|
if (!replaced.equals(item)) {
|
||||||
|
newStrings.addAll(List.of(replaced.split(",")));
|
||||||
|
} else {
|
||||||
|
newStrings.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newStrings;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
394
src/main/java/net/knarcraft/blacksmith/util/SalvageHelper.java
Normal file
394
src/main/java/net/knarcraft/blacksmith/util/SalvageHelper.java
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
package net.knarcraft.blacksmith.util;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.container.RecipeResult;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Server;
|
||||||
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.Recipe;
|
||||||
|
import org.bukkit.inventory.ShapedRecipe;
|
||||||
|
import org.bukkit.inventory.ShapelessRecipe;
|
||||||
|
import org.bukkit.inventory.meta.ArmorMeta;
|
||||||
|
import org.bukkit.inventory.meta.trim.ArmorTrim;
|
||||||
|
import org.bukkit.inventory.meta.trim.TrimMaterial;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper class for deciding the salvage returned if salvaging an item
|
||||||
|
*/
|
||||||
|
public final class SalvageHelper {
|
||||||
|
|
||||||
|
private static final Random random = new Random();
|
||||||
|
private static final Map<TrimMaterial, Material> trimMaterialToMaterial;
|
||||||
|
|
||||||
|
static {
|
||||||
|
trimMaterialToMaterial = new HashMap<>();
|
||||||
|
trimMaterialToMaterial.put(TrimMaterial.AMETHYST, Material.AMETHYST_SHARD);
|
||||||
|
trimMaterialToMaterial.put(TrimMaterial.COPPER, Material.COPPER_INGOT);
|
||||||
|
trimMaterialToMaterial.put(TrimMaterial.DIAMOND, Material.DIAMOND);
|
||||||
|
trimMaterialToMaterial.put(TrimMaterial.EMERALD, Material.EMERALD);
|
||||||
|
trimMaterialToMaterial.put(TrimMaterial.GOLD, Material.GOLD_INGOT);
|
||||||
|
trimMaterialToMaterial.put(TrimMaterial.IRON, Material.IRON_INGOT);
|
||||||
|
trimMaterialToMaterial.put(TrimMaterial.LAPIS, Material.LAPIS_LAZULI);
|
||||||
|
trimMaterialToMaterial.put(TrimMaterial.NETHERITE, Material.NETHERITE_INGOT);
|
||||||
|
trimMaterialToMaterial.put(TrimMaterial.QUARTZ, Material.QUARTZ);
|
||||||
|
trimMaterialToMaterial.put(TrimMaterial.REDSTONE, Material.REDSTONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets salvage for a given netherite item
|
||||||
|
*
|
||||||
|
* @param item <p>The netherite armor/tool to salvage</p>
|
||||||
|
* @return <p></p>
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static List<ItemStack> getNetheriteSalvage(@NotNull ItemStack item) {
|
||||||
|
Material newMaterial = Material.matchMaterial(item.getType().name().replace("NETHERITE", "DIAMOND"));
|
||||||
|
if (newMaterial == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ItemStack clone = item.clone();
|
||||||
|
clone.setType(newMaterial);
|
||||||
|
|
||||||
|
List<ItemStack> salvage = new ArrayList<>();
|
||||||
|
salvage.add(clone);
|
||||||
|
salvage.add(new ItemStack(Material.NETHERITE_INGOT, 1));
|
||||||
|
salvage.add(new ItemStack(Material.NETHERITE_UPGRADE_SMITHING_TEMPLATE, 1));
|
||||||
|
|
||||||
|
return salvage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets salvage for the given armor trim
|
||||||
|
*
|
||||||
|
* @param item <p>The item to have its armor trim salvaged</p>
|
||||||
|
* @param armorMeta <p>The armor meta of the item to salvage</p>
|
||||||
|
* @return <p>The salvage, or null if salvage could not be calculated</p>
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static List<ItemStack> getArmorTrimSalvage(@NotNull ItemStack item, @NotNull ArmorMeta armorMeta) {
|
||||||
|
ArmorTrim armorTrim = armorMeta.getTrim();
|
||||||
|
if (armorTrim == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ItemStack> result = new ArrayList<>();
|
||||||
|
Material trimMaterial = trimMaterialToMaterial.get(armorTrim.getMaterial());
|
||||||
|
if (trimMaterial != null) {
|
||||||
|
result.add(new ItemStack(trimMaterial, 1));
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Material patternMaterial = Material.matchMaterial(armorTrim.getPattern().getKey().getKey() +
|
||||||
|
"_ARMOR_TRIM_SMITHING_TEMPLATE");
|
||||||
|
if (patternMaterial != null) {
|
||||||
|
result.add(new ItemStack(patternMaterial, 1));
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a clone of the input item, with the armor trim removed
|
||||||
|
ItemStack strippedItem = item.clone();
|
||||||
|
armorMeta.setTrim(null);
|
||||||
|
strippedItem.setItemMeta(armorMeta);
|
||||||
|
result.add(strippedItem);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given item can be salvaged, assuming no restrictions apply
|
||||||
|
*
|
||||||
|
* @param server <p>The server to get recipes from</p>
|
||||||
|
* @param item <p>The item to check</p>
|
||||||
|
* @return <p>True if the item can be salvaged</p>
|
||||||
|
*/
|
||||||
|
public static boolean isSalvageable(@NotNull Server server, @NotNull ItemStack item) {
|
||||||
|
List<Recipe> recipes = server.getRecipesFor(new ItemStack(item.getType(), item.getAmount()));
|
||||||
|
for (Recipe recipe : recipes) {
|
||||||
|
// Only crafting recipes are allowed.
|
||||||
|
if ((recipe instanceof ShapedRecipe || recipe instanceof ShapelessRecipe) &&
|
||||||
|
item.getAmount() >= recipe.getResult().getAmount()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the sum of all enchantment levels for the given item
|
||||||
|
*
|
||||||
|
* @param item <p>The item to check</p>
|
||||||
|
* @return <p>The total amount of enchantment levels on the item</p>
|
||||||
|
*/
|
||||||
|
public static int getTotalEnchantmentLevels(@NotNull ItemStack item) {
|
||||||
|
int expLevels = 0;
|
||||||
|
for (Enchantment enchantment : item.getEnchantments().keySet()) {
|
||||||
|
expLevels += item.getEnchantmentLevel(enchantment);
|
||||||
|
}
|
||||||
|
return expLevels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the items to return if salvaging the given item stack
|
||||||
|
*
|
||||||
|
* <p>Note: Only items craft-able in a crafting table are salvageable. Netherite gear is therefore not salvageable.</p>
|
||||||
|
*
|
||||||
|
* @param server <p>The server to get recipes from</p>
|
||||||
|
* @param salvagedItem <p>The item stack to salvage</p>
|
||||||
|
* @param trashSalvage <p>Any material treated as trash salvage</p>
|
||||||
|
* @param extended <p>Whether to enable extended salvage, ignoring the repairable restriction</p>
|
||||||
|
* @return <p>The items to return to the user, or null if not salvageable</p>
|
||||||
|
*/
|
||||||
|
public static @Nullable RecipeResult getSalvage(@NotNull Server server, @Nullable ItemStack salvagedItem,
|
||||||
|
@NotNull Collection<Material> trashSalvage, boolean extended) {
|
||||||
|
if (salvagedItem == null || salvagedItem.getAmount() < 1 ||
|
||||||
|
(!extended && !ItemHelper.isRepairable(salvagedItem))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Recipe recipe : server.getRecipesFor(new ItemStack(salvagedItem.getType(), salvagedItem.getAmount()))) {
|
||||||
|
BlacksmithPlugin.debug("Considering recipe: " + recipe.getResult() + " -> " + getRawRecipeSalvage(recipe));
|
||||||
|
|
||||||
|
// Only consider crafting table recipes
|
||||||
|
if (!(recipe instanceof ShapedRecipe) && !(recipe instanceof ShapelessRecipe)) {
|
||||||
|
BlacksmithPlugin.debug("Recipe had invalid type");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the player has enough items
|
||||||
|
if (salvagedItem.getAmount() < recipe.getResult().getAmount()) {
|
||||||
|
BlacksmithPlugin.debug("Too few items for recipe");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get actual salvage, as long as any can be produced
|
||||||
|
List<ItemStack> salvage = getRecipeSalvage(recipe, salvagedItem, trashSalvage);
|
||||||
|
if (salvage != null && !salvage.isEmpty()) {
|
||||||
|
BlacksmithPlugin.debug("Valid recipe: " + recipe.getResult() + " -> " + getRawRecipeSalvage(recipe));
|
||||||
|
BlacksmithPlugin.debug("Actual salvage: " + salvage);
|
||||||
|
return new RecipeResult(recipe, salvage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the salvage resulting from the given recipe and the given item
|
||||||
|
*
|
||||||
|
* @param recipe <p>The recipe to get salvage for</p>
|
||||||
|
* @param salvagedItem <p>The item to be salvaged</p>
|
||||||
|
* @param trashSalvage <p>Any material treated as trash salvage</p>
|
||||||
|
* @return <p>A list of items, or null if not a valid type of recipe</p>
|
||||||
|
*/
|
||||||
|
private static @Nullable List<ItemStack> getRecipeSalvage(@NotNull Recipe recipe, @NotNull ItemStack salvagedItem,
|
||||||
|
@NotNull Collection<Material> trashSalvage) {
|
||||||
|
List<ItemStack> ingredients = getRawRecipeSalvage(recipe);
|
||||||
|
if (ingredients == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<ItemStack> copy = copyItems(ingredients);
|
||||||
|
BlacksmithPlugin.debug("Copied salvage: " + copy);
|
||||||
|
List<ItemStack> salvage = getSalvage(copy, salvagedItem, trashSalvage);
|
||||||
|
BlacksmithPlugin.debug("Combining salvage: " + salvage);
|
||||||
|
List<ItemStack> combined = combineStacks(salvage);
|
||||||
|
BlacksmithPlugin.debug("Combined : " + combined);
|
||||||
|
return combined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies a list of items
|
||||||
|
*
|
||||||
|
* <p>Note: This does not copy any metadata. It only copies the item type and the amount.</p>
|
||||||
|
*
|
||||||
|
* @param itemsToCopy <p>The items to make a copy of</p>
|
||||||
|
* @return <p>A copy of the given items</p>
|
||||||
|
*/
|
||||||
|
private static @NotNull List<ItemStack> copyItems(@NotNull List<ItemStack> itemsToCopy) {
|
||||||
|
List<ItemStack> copies = new ArrayList<>(itemsToCopy.size());
|
||||||
|
for (ItemStack itemStack : itemsToCopy) {
|
||||||
|
copies.add(new ItemStack(itemStack.getType(), itemStack.getAmount()));
|
||||||
|
}
|
||||||
|
return copies;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the salvage resulting from the given item, and the given recipe items
|
||||||
|
*
|
||||||
|
* @param recipeItems <p>All items required for crafting the item to salvage</p>
|
||||||
|
* @param salvagedItem <p>The item to be salvaged</p>
|
||||||
|
* @param trashSalvage <p>The types of materials considered trash for this recipe</p>
|
||||||
|
* @return <p>The items to be returned to the user as salvage</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private static List<ItemStack> getSalvage(@NotNull List<ItemStack> recipeItems,
|
||||||
|
@NotNull ItemStack salvagedItem,
|
||||||
|
@NotNull Collection<Material> trashSalvage) {
|
||||||
|
int durability = ItemHelper.getDurability(salvagedItem);
|
||||||
|
int maxDurability = ItemHelper.getMaxDurability(salvagedItem);
|
||||||
|
|
||||||
|
// Prevent divide by zero for items that don't have a set max durability
|
||||||
|
if (maxDurability <= 0) {
|
||||||
|
maxDurability = 1;
|
||||||
|
durability = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlacksmithPlugin.debug("Durability: " + durability + "/" + maxDurability);
|
||||||
|
|
||||||
|
double percentageRemaining = (double) durability / maxDurability;
|
||||||
|
BlacksmithPlugin.debug("Remaining: " + percentageRemaining);
|
||||||
|
return pickRandomSalvage(recipeItems, trashSalvage, percentageRemaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Picks random salvage from the given items
|
||||||
|
*
|
||||||
|
* @param itemsToChooseFrom <p>The salvage to choose from</p>
|
||||||
|
* @param trashSalvage <p>The salvage considered trash</p>
|
||||||
|
* @param percentageRemaining <p>The percentage remaining for the salvaged item (0-1)</p>
|
||||||
|
* @return <p>Random salvage</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public static List<ItemStack> pickRandomSalvage(@NotNull List<ItemStack> itemsToChooseFrom,
|
||||||
|
@NotNull Collection<Material> trashSalvage,
|
||||||
|
double percentageRemaining) {
|
||||||
|
// Avoid an infinite loop
|
||||||
|
if (percentageRemaining > 1 || percentageRemaining < 0) {
|
||||||
|
percentageRemaining = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not damaged, just give everything
|
||||||
|
if (percentageRemaining == 1) {
|
||||||
|
BlacksmithPlugin.debug("100% Remaining. Copying " + itemsToChooseFrom);
|
||||||
|
return copyItems(itemsToChooseFrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split into good items and trash items
|
||||||
|
List<ItemStack> goodItems = copyItems(itemsToChooseFrom);
|
||||||
|
goodItems.removeIf((item) -> trashSalvage.contains(item.getType()));
|
||||||
|
List<ItemStack> trashItems = copyItems(itemsToChooseFrom);
|
||||||
|
trashItems.removeIf((item) -> !trashSalvage.contains(item.getType()));
|
||||||
|
|
||||||
|
int itemsToReturn = (int) Math.floor(totalItemAmount(itemsToChooseFrom) * percentageRemaining);
|
||||||
|
int goodItemAmount = totalItemAmount(goodItems);
|
||||||
|
int pickedItems = 0;
|
||||||
|
List<ItemStack> salvage = new ArrayList<>(itemsToReturn);
|
||||||
|
|
||||||
|
while (pickedItems < itemsToReturn && pickedItems < goodItemAmount) {
|
||||||
|
int index = SalvageHelper.random.nextInt(goodItems.size());
|
||||||
|
ItemStack itemStack = goodItems.get(index);
|
||||||
|
if (itemStack.getType().isAir() || itemStack.getAmount() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
salvage.add(new ItemStack(itemStack.getType(), 1));
|
||||||
|
itemStack.setAmount(itemStack.getAmount() - 1);
|
||||||
|
pickedItems++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (pickedItems < itemsToReturn) {
|
||||||
|
int index = SalvageHelper.random.nextInt(trashItems.size());
|
||||||
|
ItemStack itemStack = trashItems.get(index);
|
||||||
|
if (itemStack.getType().isAir() || itemStack.getAmount() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
salvage.add(new ItemStack(itemStack.getType(), 1));
|
||||||
|
itemStack.setAmount(itemStack.getAmount() - 1);
|
||||||
|
pickedItems++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return salvage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the total sum of items in the given list of items
|
||||||
|
*
|
||||||
|
* @param items <p>The items to get the sum of</p>
|
||||||
|
* @return <p>The total number of items</p>
|
||||||
|
*/
|
||||||
|
public static int totalItemAmount(@NotNull List<ItemStack> items) {
|
||||||
|
int sum = 0;
|
||||||
|
for (ItemStack itemStack : items) {
|
||||||
|
sum += itemStack.getAmount();
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines all items of the same type in the given list
|
||||||
|
*
|
||||||
|
* <p>Basically, if the input is two item stacks containing one diamond each, the output will be an item stack with
|
||||||
|
* two diamonds instead.</p>
|
||||||
|
*
|
||||||
|
* @param items <p>The items to combine</p>
|
||||||
|
* @return <p>The given items, but combined</p>
|
||||||
|
*/
|
||||||
|
private static @NotNull List<ItemStack> combineStacks(@NotNull List<ItemStack> items) {
|
||||||
|
Map<Material, Integer> itemAmounts = new HashMap<>();
|
||||||
|
for (ItemStack item : items) {
|
||||||
|
Material itemType = item.getType();
|
||||||
|
itemAmounts.put(itemType, itemAmounts.getOrDefault(itemType, 0) + item.getAmount());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ItemStack> combined = new ArrayList<>();
|
||||||
|
for (Material material : itemAmounts.keySet()) {
|
||||||
|
combined.add(new ItemStack(material, itemAmounts.get(material)));
|
||||||
|
}
|
||||||
|
return combined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the raw salvage of a recipe, assuming full salvage would be possible
|
||||||
|
*
|
||||||
|
* @param recipe <p>The recipe to get salvage for</p>
|
||||||
|
* @return <p>The salvage resulting from the recipe</p>
|
||||||
|
*/
|
||||||
|
private static List<ItemStack> getRawRecipeSalvage(@NotNull Recipe recipe) {
|
||||||
|
List<ItemStack> ingredients;
|
||||||
|
if (recipe instanceof ShapedRecipe shapedRecipe) {
|
||||||
|
ingredients = getIngredients(shapedRecipe);
|
||||||
|
} else if (recipe instanceof ShapelessRecipe shapelessRecipe) {
|
||||||
|
ingredients = shapelessRecipe.getIngredientList();
|
||||||
|
} else {
|
||||||
|
//Recipes other than crafting shouldn't be considered for salvaging
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
//Make things easier by eliminating identical stacks
|
||||||
|
return combineStacks(ingredients);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all ingredients contained in the given shaped recipe
|
||||||
|
*
|
||||||
|
* @param shapedRecipe <p>The shaped recipe to get ingredients for</p>
|
||||||
|
* @return <p>The items contained in the recipe</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private static List<ItemStack> getIngredients(@NotNull ShapedRecipe shapedRecipe) {
|
||||||
|
List<ItemStack> ingredients = new ArrayList<>();
|
||||||
|
Map<Character, ItemStack> ingredientMap = shapedRecipe.getIngredientMap();
|
||||||
|
//The shape is a list of the three rows' strings. Each string contains 3 characters.
|
||||||
|
String[] shape = shapedRecipe.getShape();
|
||||||
|
for (String row : shape) {
|
||||||
|
for (int column = 0; column < row.length(); column++) {
|
||||||
|
ItemStack item = ingredientMap.get(row.charAt(column));
|
||||||
|
if (item != null && item.getType() != Material.AIR && item.getAmount() > 0) {
|
||||||
|
ingredients.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ingredients;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,11 +1,13 @@
|
|||||||
package net.knarcraft.blacksmith.util;
|
package net.knarcraft.blacksmith.util;
|
||||||
|
|
||||||
import net.knarcraft.blacksmith.config.SettingValueType;
|
import net.knarcraft.blacksmith.config.SettingValueType;
|
||||||
|
import net.knarcraft.blacksmith.config.SmithPreset;
|
||||||
|
import net.knarcraft.blacksmith.config.SmithPresetFilter;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Registry;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.enchantments.EnchantmentTarget;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.inventory.meta.Damageable;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -25,7 +27,7 @@ public final class TabCompleteValuesHelper {
|
|||||||
* @param valueType <p>The value type to get possible values for</p>
|
* @param valueType <p>The value type to get possible values for</p>
|
||||||
* @return <p>The values to show the user</p>
|
* @return <p>The values to show the user</p>
|
||||||
*/
|
*/
|
||||||
public static List<String> getTabCompletions(SettingValueType valueType) {
|
public static @NotNull List<String> getTabCompletions(@NotNull SettingValueType valueType) {
|
||||||
return switch (valueType) {
|
return switch (valueType) {
|
||||||
case POSITIVE_INTEGER -> getPositiveIntegers();
|
case POSITIVE_INTEGER -> getPositiveIntegers();
|
||||||
case BOOLEAN -> getBooleans();
|
case BOOLEAN -> getBooleans();
|
||||||
@ -33,39 +35,32 @@ public final class TabCompleteValuesHelper {
|
|||||||
case STRING -> getStrings();
|
case STRING -> getStrings();
|
||||||
case PERCENTAGE -> getPercentages();
|
case PERCENTAGE -> getPercentages();
|
||||||
case REFORGE_ABLE_ITEMS -> getReforgeAbleMaterials();
|
case REFORGE_ABLE_ITEMS -> getReforgeAbleMaterials();
|
||||||
case MATERIAL -> getAllReforgeAbleMaterials();
|
case MATERIAL -> getAllReforgeAbleMaterialNames();
|
||||||
case ENCHANTMENT -> getAllEnchantments();
|
case ENCHANTMENT, ENCHANTMENT_LIST -> getAllEnchantments();
|
||||||
case STRING_LIST -> getExampleEnchantmentBlockLists();
|
case STRING_LIST -> List.of("*_SHOVEL,*_PICKAXE,*_AXE,*_HOE,*_SWORD:STICK,SMITHING_TABLE:*_PLANKS");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets example enchantment block lists
|
|
||||||
*
|
|
||||||
* @return <p>Some example enchantment block lists</p>
|
|
||||||
*/
|
|
||||||
private static List<String> getExampleEnchantmentBlockLists() {
|
|
||||||
List<String> exampleBlockLists = new ArrayList<>();
|
|
||||||
exampleBlockLists.add(Enchantment.VANISHING_CURSE.getKey().getKey() + "," +
|
|
||||||
Enchantment.BINDING_CURSE.getKey().getKey() + "," + Enchantment.MENDING.getKey().getKey());
|
|
||||||
exampleBlockLists.add(Enchantment.VANISHING_CURSE.getKey().getKey() + "," +
|
|
||||||
Enchantment.BINDING_CURSE.getKey().getKey());
|
|
||||||
return exampleBlockLists;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a complete list of all reforge-able materials
|
* Gets a complete list of all reforge-able material names
|
||||||
*
|
*
|
||||||
* @return <p>A complete list of reforge-able materials</p>
|
* @return <p>A complete list of reforge-able material names</p>
|
||||||
*/
|
*/
|
||||||
private static List<String> getAllReforgeAbleMaterials() {
|
private static @NotNull List<String> getAllReforgeAbleMaterialNames() {
|
||||||
List<String> reforgeAbleMaterials = new ArrayList<>();
|
List<String> reforgeAbleMaterials = new ArrayList<>();
|
||||||
for (Material material : Material.values()) {
|
for (Material material : ItemHelper.getAllReforgeAbleMaterials()) {
|
||||||
ItemStack item = new ItemStack(material);
|
|
||||||
if (item.getItemMeta() instanceof Damageable && EnchantmentTarget.BREAKABLE.includes(item)) {
|
|
||||||
reforgeAbleMaterials.add(material.name());
|
reforgeAbleMaterials.add(material.name());
|
||||||
}
|
}
|
||||||
}
|
reforgeAbleMaterials.add("NETHERITE_*");
|
||||||
|
reforgeAbleMaterials.add("DIAMOND_*");
|
||||||
|
reforgeAbleMaterials.add("GOLDEN_*");
|
||||||
|
reforgeAbleMaterials.add("IRON_*");
|
||||||
|
reforgeAbleMaterials.add("CHAINMAIL_*");
|
||||||
|
reforgeAbleMaterials.add("STONE_*");
|
||||||
|
reforgeAbleMaterials.add("*BOW");
|
||||||
|
reforgeAbleMaterials.add("LEATHER_*");
|
||||||
|
reforgeAbleMaterials.add("WOODEN_*");
|
||||||
return reforgeAbleMaterials;
|
return reforgeAbleMaterials;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,9 +69,14 @@ public final class TabCompleteValuesHelper {
|
|||||||
*
|
*
|
||||||
* @return <p>A complete list of enchantments</p>
|
* @return <p>A complete list of enchantments</p>
|
||||||
*/
|
*/
|
||||||
private static List<String> getAllEnchantments() {
|
private static @NotNull List<String> getAllEnchantments() {
|
||||||
|
Registry<Enchantment> enchantmentRegistry = Bukkit.getRegistry(Enchantment.class);
|
||||||
|
if (enchantmentRegistry == null) {
|
||||||
|
throw new RuntimeException("Unable to get the enchantment registry");
|
||||||
|
}
|
||||||
|
|
||||||
List<String> enchantments = new ArrayList<>();
|
List<String> enchantments = new ArrayList<>();
|
||||||
for (Enchantment enchantment : Enchantment.values()) {
|
for (Enchantment enchantment : enchantmentRegistry) {
|
||||||
enchantments.add(enchantment.getKey().getKey());
|
enchantments.add(enchantment.getKey().getKey());
|
||||||
}
|
}
|
||||||
return enchantments;
|
return enchantments;
|
||||||
@ -87,14 +87,19 @@ public final class TabCompleteValuesHelper {
|
|||||||
*
|
*
|
||||||
* @return <p>Some example possible values for reforge-able materials</p>
|
* @return <p>Some example possible values for reforge-able materials</p>
|
||||||
*/
|
*/
|
||||||
private static List<String> getReforgeAbleMaterials() {
|
private static @NotNull List<String> getReforgeAbleMaterials() {
|
||||||
List<String> stringLists = new ArrayList<>();
|
List<String> stringLists = new ArrayList<>();
|
||||||
stringLists.add("preset:sword-smith");
|
for (SmithPreset preset : SmithPreset.values()) {
|
||||||
stringLists.add("preset:weapon-smith");
|
stringLists.add("preset:" + preset.name());
|
||||||
stringLists.add("preset:armor-smith");
|
for (SmithPresetFilter filter : preset.getSupportedFilters()) {
|
||||||
stringLists.add("preset:tool-smith");
|
stringLists.add("preset:" + preset.name() + ":" + filter.name());
|
||||||
stringLists.add("preset:ranged-smith");
|
}
|
||||||
stringLists.add("bow,crossbow,elytra");
|
}
|
||||||
|
stringLists.add("preset:WEAPON_SMITH:RANGED,SHIELD");
|
||||||
|
stringLists.add("preset:WEAPON_SMITH,preset:ARMOR_SMITH");
|
||||||
|
stringLists.add("preset:WEAPON_SMITH,preset:TOOL_SMITH");
|
||||||
|
stringLists.add("preset:ARMOR_SMITH,preset:TOOL_SMITH");
|
||||||
|
stringLists.add("BOW,CROSSBOW,ELYTRA");
|
||||||
return stringLists;
|
return stringLists;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +108,7 @@ public final class TabCompleteValuesHelper {
|
|||||||
*
|
*
|
||||||
* @return <p>Some example string values</p>
|
* @return <p>Some example string values</p>
|
||||||
*/
|
*/
|
||||||
private static List<String> getStrings() {
|
private static @NotNull List<String> getStrings() {
|
||||||
List<String> strings = new ArrayList<>(1);
|
List<String> strings = new ArrayList<>(1);
|
||||||
strings.add("&aExample message. Use & for color tags.");
|
strings.add("&aExample message. Use & for color tags.");
|
||||||
return strings;
|
return strings;
|
||||||
@ -114,7 +119,7 @@ public final class TabCompleteValuesHelper {
|
|||||||
*
|
*
|
||||||
* @return <p>Some example percentage values</p>
|
* @return <p>Some example percentage values</p>
|
||||||
*/
|
*/
|
||||||
private static List<String> getPercentages() {
|
private static @NotNull List<String> getPercentages() {
|
||||||
List<String> percentages = new ArrayList<>(6);
|
List<String> percentages = new ArrayList<>(6);
|
||||||
percentages.add("0");
|
percentages.add("0");
|
||||||
percentages.add("10");
|
percentages.add("10");
|
||||||
@ -130,7 +135,7 @@ public final class TabCompleteValuesHelper {
|
|||||||
*
|
*
|
||||||
* @return <p>Some possible positive doubles</p>
|
* @return <p>Some possible positive doubles</p>
|
||||||
*/
|
*/
|
||||||
private static List<String> getPositiveDoubles() {
|
private static @NotNull List<String> getPositiveDoubles() {
|
||||||
List<String> positiveDoubles = new ArrayList<>(4);
|
List<String> positiveDoubles = new ArrayList<>(4);
|
||||||
positiveDoubles.add("0.0");
|
positiveDoubles.add("0.0");
|
||||||
positiveDoubles.add("0.0001");
|
positiveDoubles.add("0.0001");
|
||||||
@ -145,7 +150,7 @@ public final class TabCompleteValuesHelper {
|
|||||||
*
|
*
|
||||||
* @return <p>Some example positive integers</p>
|
* @return <p>Some example positive integers</p>
|
||||||
*/
|
*/
|
||||||
private static List<String> getPositiveIntegers() {
|
private static @NotNull List<String> getPositiveIntegers() {
|
||||||
List<String> positiveIntegers = new ArrayList<>(6);
|
List<String> positiveIntegers = new ArrayList<>(6);
|
||||||
positiveIntegers.add("0");
|
positiveIntegers.add("0");
|
||||||
positiveIntegers.add("5");
|
positiveIntegers.add("5");
|
||||||
@ -162,7 +167,7 @@ public final class TabCompleteValuesHelper {
|
|||||||
*
|
*
|
||||||
* @return <p>The possible boolean values</p>
|
* @return <p>The possible boolean values</p>
|
||||||
*/
|
*/
|
||||||
private static List<String> getBooleans() {
|
private static @NotNull List<String> getBooleans() {
|
||||||
List<String> booleans = new ArrayList<>(2);
|
List<String> booleans = new ArrayList<>(2);
|
||||||
booleans.add("True");
|
booleans.add("True");
|
||||||
booleans.add("False");
|
booleans.add("False");
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
package net.knarcraft.blacksmith.util;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A helper class for tab-completion
|
|
||||||
*/
|
|
||||||
public final class TabCompletionHelper {
|
|
||||||
|
|
||||||
private TabCompletionHelper() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds tab complete values that contain the typed text
|
|
||||||
*
|
|
||||||
* @param values <p>The values to filter</p>
|
|
||||||
* @param typedText <p>The text the player has started typing</p>
|
|
||||||
* @return <p>The given string values that contain the player's typed text</p>
|
|
||||||
*/
|
|
||||||
public static List<String> filterMatchingContains(List<String> values, String typedText) {
|
|
||||||
List<String> configValues = new ArrayList<>();
|
|
||||||
for (String value : values) {
|
|
||||||
if (value.toLowerCase().contains(typedText.toLowerCase())) {
|
|
||||||
configValues.add(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return configValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,13 +1,16 @@
|
|||||||
package net.knarcraft.blacksmith.util;
|
package net.knarcraft.blacksmith.util;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
import net.knarcraft.blacksmith.config.SettingValueType;
|
import net.knarcraft.blacksmith.config.SettingValueType;
|
||||||
import net.knarcraft.blacksmith.formatting.TranslatableMessage;
|
import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
|
||||||
|
import org.bukkit.Material;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static net.knarcraft.blacksmith.formatting.StringFormatter.displayErrorMessage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper class for validating a value's type
|
* A helper class for validating a value's type
|
||||||
*/
|
*/
|
||||||
@ -25,7 +28,8 @@ public final class TypeValidationHelper {
|
|||||||
* @param sender <p>The command sender to use for printing error messages</p>
|
* @param sender <p>The command sender to use for printing error messages</p>
|
||||||
* @return <p>True if the value is valid</p>
|
* @return <p>True if the value is valid</p>
|
||||||
*/
|
*/
|
||||||
public static boolean isValid(SettingValueType valueType, Object value, CommandSender sender) {
|
public static boolean isValid(@NotNull SettingValueType valueType, @Nullable Object value,
|
||||||
|
@Nullable CommandSender sender) {
|
||||||
try {
|
try {
|
||||||
return switch (valueType) {
|
return switch (valueType) {
|
||||||
case POSITIVE_DOUBLE -> isPositiveDouble(value, sender);
|
case POSITIVE_DOUBLE -> isPositiveDouble(value, sender);
|
||||||
@ -33,8 +37,10 @@ public final class TypeValidationHelper {
|
|||||||
case POSITIVE_INTEGER -> isPositiveInteger(value, sender);
|
case POSITIVE_INTEGER -> isPositiveInteger(value, sender);
|
||||||
case PERCENTAGE -> isPercentage(value, sender);
|
case PERCENTAGE -> isPercentage(value, sender);
|
||||||
case BOOLEAN -> true;
|
case BOOLEAN -> true;
|
||||||
case STRING_LIST, REFORGE_ABLE_ITEMS -> isStringList(value, sender);
|
case REFORGE_ABLE_ITEMS, STRING_LIST -> isStringList(value, sender);
|
||||||
case MATERIAL, ENCHANTMENT -> false;
|
case MATERIAL -> isMaterial(value, sender);
|
||||||
|
case ENCHANTMENT -> isEnchantment(value, sender);
|
||||||
|
case ENCHANTMENT_LIST -> isEnchantmentList(value, sender);
|
||||||
};
|
};
|
||||||
} catch (ClassCastException exception) {
|
} catch (ClassCastException exception) {
|
||||||
//This error signifies that an object is not a string, and of the wrong class
|
//This error signifies that an object is not a string, and of the wrong class
|
||||||
@ -42,6 +48,68 @@ public final class TypeValidationHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given value is a material
|
||||||
|
*
|
||||||
|
* @param value <p>The value to check</p>
|
||||||
|
* @param sender <p>The command sender to use for printing error messages</p>
|
||||||
|
* @return <p>True if the value is a material</p>
|
||||||
|
*/
|
||||||
|
private static boolean isMaterial(@Nullable Object value, @Nullable CommandSender sender) {
|
||||||
|
boolean isMaterial = value instanceof Material || (value instanceof String string &&
|
||||||
|
InputParsingHelper.matchMaterial(string) != null);
|
||||||
|
if (!isMaterial && sender != null) {
|
||||||
|
BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender,
|
||||||
|
BlacksmithTranslatableMessage.ITEM_TYPE_MATERIAL);
|
||||||
|
}
|
||||||
|
return isMaterial;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given value is a list of enchantments
|
||||||
|
*
|
||||||
|
* @param value <p>The value to check</p>
|
||||||
|
* @param sender <p>The command sender to use for printing error messages</p>
|
||||||
|
* @return <p>True if the value is an enchantment list</p>
|
||||||
|
*/
|
||||||
|
private static boolean isEnchantmentList(@Nullable Object value, @Nullable CommandSender sender) {
|
||||||
|
// Check whether a string list is given
|
||||||
|
if (!isStringList(value, sender)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the input can be converted to a string list
|
||||||
|
List<String> strings = ConfigHelper.asStringList(value);
|
||||||
|
if (strings == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure each value is an enchantment
|
||||||
|
for (String string : strings) {
|
||||||
|
if (!isEnchantment(string, sender)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given value is an enchantment
|
||||||
|
*
|
||||||
|
* @param value <p>The value to check</p>
|
||||||
|
* @param sender <p>The command sender to use for printing error messages</p>
|
||||||
|
* @return <p>True if the value is an enchantment</p>
|
||||||
|
*/
|
||||||
|
private static boolean isEnchantment(@Nullable Object value, @Nullable CommandSender sender) {
|
||||||
|
boolean isEnchantment = value instanceof Enchantment || (value instanceof String string &&
|
||||||
|
InputParsingHelper.matchEnchantment(string) != null);
|
||||||
|
if (!isEnchantment && sender != null) {
|
||||||
|
BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender,
|
||||||
|
BlacksmithTranslatableMessage.ITEM_TYPE_ENCHANTMENT);
|
||||||
|
}
|
||||||
|
return isEnchantment;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the given value is a string list
|
* Checks whether the given value is a string list
|
||||||
*
|
*
|
||||||
@ -49,10 +117,11 @@ public final class TypeValidationHelper {
|
|||||||
* @param sender <p>The command sender to use for printing error messages</p>
|
* @param sender <p>The command sender to use for printing error messages</p>
|
||||||
* @return <p>True if the value is a string list</p>
|
* @return <p>True if the value is a string list</p>
|
||||||
*/
|
*/
|
||||||
private static boolean isStringList(Object value, CommandSender sender) {
|
private static boolean isStringList(@Nullable Object value, @Nullable CommandSender sender) {
|
||||||
boolean isStringList = value instanceof String[] || value instanceof List<?> || value instanceof String;
|
boolean isStringList = value instanceof String[] || value instanceof List<?> || value instanceof String;
|
||||||
if (!isStringList && sender != null) {
|
if (!isStringList && sender != null) {
|
||||||
displayErrorMessage(sender, TranslatableMessage.INPUT_STRING_LIST_REQUIRED);
|
BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender,
|
||||||
|
BlacksmithTranslatableMessage.INPUT_STRING_LIST_REQUIRED);
|
||||||
}
|
}
|
||||||
return isStringList;
|
return isStringList;
|
||||||
}
|
}
|
||||||
@ -64,16 +133,14 @@ public final class TypeValidationHelper {
|
|||||||
* @param sender <p>The command sender to use for printing error messages</p>
|
* @param sender <p>The command sender to use for printing error messages</p>
|
||||||
* @return <p>True if the value is a percentage</p>
|
* @return <p>True if the value is a percentage</p>
|
||||||
*/
|
*/
|
||||||
private static boolean isPercentage(Object value, CommandSender sender) {
|
private static boolean isPercentage(@Nullable Object value, @Nullable CommandSender sender) {
|
||||||
try {
|
boolean isPercentage = value != null && isPositiveInteger(value, null) &&
|
||||||
int intValue = ConfigHelper.asInt(value);
|
ConfigHelper.asInt(value) >= 0 && ConfigHelper.asInt(value) <= 100;
|
||||||
return intValue >= 0 && intValue <= 100;
|
if (!isPercentage && sender != null) {
|
||||||
} catch (NumberFormatException | NullPointerException exception) {
|
BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender,
|
||||||
if (sender != null) {
|
BlacksmithTranslatableMessage.INPUT_PERCENTAGE_REQUIRED);
|
||||||
displayErrorMessage(sender, TranslatableMessage.INPUT_PERCENTAGE_REQUIRED);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return isPercentage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -83,10 +150,11 @@ public final class TypeValidationHelper {
|
|||||||
* @param sender <p>The command sender to use for printing error messages</p>
|
* @param sender <p>The command sender to use for printing error messages</p>
|
||||||
* @return <p>True if the value is a non-empty string</p>
|
* @return <p>True if the value is a non-empty string</p>
|
||||||
*/
|
*/
|
||||||
private static boolean isNonEmptyString(Object value, CommandSender sender) {
|
private static boolean isNonEmptyString(@Nullable Object value, @Nullable CommandSender sender) {
|
||||||
boolean isString = value instanceof String string && !string.strip().isEmpty();
|
boolean isString = value instanceof String string && !string.isBlank();
|
||||||
if (!isString && sender != null) {
|
if (!isString && sender != null) {
|
||||||
displayErrorMessage(sender, TranslatableMessage.INPUT_STRING_REQUIRED);
|
BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender,
|
||||||
|
BlacksmithTranslatableMessage.INPUT_STRING_REQUIRED);
|
||||||
}
|
}
|
||||||
return isString;
|
return isString;
|
||||||
}
|
}
|
||||||
@ -98,12 +166,13 @@ public final class TypeValidationHelper {
|
|||||||
* @param sender <p>The command sender to use for printing error messages</p>
|
* @param sender <p>The command sender to use for printing error messages</p>
|
||||||
* @return <p>True if the value is a positive double</p>
|
* @return <p>True if the value is a positive double</p>
|
||||||
*/
|
*/
|
||||||
private static boolean isPositiveDouble(Object value, CommandSender sender) {
|
private static boolean isPositiveDouble(@Nullable Object value, @Nullable CommandSender sender) {
|
||||||
try {
|
try {
|
||||||
return ConfigHelper.asDouble(value) >= 0.0;
|
return value != null && ConfigHelper.asDouble(value) >= 0.0;
|
||||||
} catch (NumberFormatException | NullPointerException exception) {
|
} catch (NumberFormatException | NullPointerException exception) {
|
||||||
if (sender != null) {
|
if (sender != null) {
|
||||||
displayErrorMessage(sender, TranslatableMessage.INPUT_POSITIVE_DOUBLE_REQUIRED);
|
BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender,
|
||||||
|
BlacksmithTranslatableMessage.INPUT_POSITIVE_DOUBLE_REQUIRED);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -116,12 +185,13 @@ public final class TypeValidationHelper {
|
|||||||
* @param sender <p>The command sender to use for printing error messages</p>
|
* @param sender <p>The command sender to use for printing error messages</p>
|
||||||
* @return <p>True if the value is a positive integer</p>
|
* @return <p>True if the value is a positive integer</p>
|
||||||
*/
|
*/
|
||||||
private static boolean isPositiveInteger(Object value, CommandSender sender) {
|
private static boolean isPositiveInteger(@Nullable Object value, @Nullable CommandSender sender) {
|
||||||
try {
|
try {
|
||||||
return ConfigHelper.asInt(value) >= 0;
|
return value != null && ConfigHelper.asInt(value) >= 0;
|
||||||
} catch (NumberFormatException | NullPointerException exception) {
|
} catch (NumberFormatException | NullPointerException exception) {
|
||||||
if (sender != null) {
|
if (sender != null) {
|
||||||
displayErrorMessage(sender, TranslatableMessage.INPUT_POSITIVE_INTEGER_REQUIRED);
|
BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender,
|
||||||
|
BlacksmithTranslatableMessage.INPUT_POSITIVE_INTEGER_REQUIRED);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
38
src/main/resources/config-migrations.txt
Normal file
38
src/main/resources/config-migrations.txt
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
global.basePrice=blacksmith.global.basePrice
|
||||||
|
global.pricePerDurabilityPoint=blacksmith.global.pricePerDurabilityPoint
|
||||||
|
global.enchantmentCost=blacksmith.global.enchantmentCost
|
||||||
|
global.useNaturalCost=blacksmith.global.useNaturalCost
|
||||||
|
global.showExactTime=blacksmith.global.showExactTime
|
||||||
|
global.chippedAnvilRepairCost=blacksmith.global.chippedAnvilReforgingCost
|
||||||
|
global.damagedAnvilRepairCost=blacksmith.global.damagedAnvilReforgingCost
|
||||||
|
global.chippedAnvilReforgingCost=blacksmith.global.chippedAnvilReforgingCost
|
||||||
|
global.damagedAnvilReforgingCost=blacksmith.global.damagedAnvilReforgingCost
|
||||||
|
global.disableMaterialLimitation=
|
||||||
|
defaults.dropItem=blacksmith.defaults.dropItem
|
||||||
|
defaults.reforgeAbleItems=blacksmith.defaults.reforgeAbleItems
|
||||||
|
defaults.disableCoolDown=
|
||||||
|
defaults.disableDelay=
|
||||||
|
defaults.failReforgeChance=blacksmith.defaults.failReforgeChance
|
||||||
|
defaults.extraEnchantmentChance=blacksmith.defaults.extraEnchantmentChance
|
||||||
|
defaults.maxEnchantments=blacksmith.defaults.maxEnchantments
|
||||||
|
defaults.delaysInSeconds.maximum=blacksmith.defaults.maxReforgeWaitTimeSeconds
|
||||||
|
defaults.delaysInSeconds.minimum=blacksmith.defaults.minReforgeWaitTimeSeconds
|
||||||
|
defaults.delaysInSeconds.reforgeCoolDown=blacksmith.defaults.reforgeCoolDownSeconds
|
||||||
|
defaults.delaysInSeconds.blacksmithTitle=
|
||||||
|
defaults.messages.busyPlayerMessage=blacksmith.defaults.messages.busyPlayerMessage
|
||||||
|
defaults.messages.busyReforgeMessage=blacksmith.defaults.messages.busyReforgeMessage
|
||||||
|
defaults.messages.coolDownUnexpiredMessage=blacksmith.defaults.messages.coolDownUnexpiredMessage
|
||||||
|
defaults.messages.costMessage=blacksmith.defaults.messages.costMessage
|
||||||
|
defaults.messages.failReforgeMessage=blacksmith.defaults.messages.failReforgeMessage
|
||||||
|
defaults.messages.insufficientFundsMessage=blacksmith.defaults.messages.insufficientFundsMessage
|
||||||
|
defaults.messages.invalidItemMessage=blacksmith.defaults.messages.invalidItemMessage
|
||||||
|
defaults.messages.itemChangedMessage=blacksmith.defaults.messages.itemChangedMessage
|
||||||
|
defaults.messages.startReforgeMessage=blacksmith.defaults.messages.startReforgeMessage
|
||||||
|
defaults.messages.successMessage=blacksmith.defaults.messages.successMessage
|
||||||
|
defaults.messages.notDamagedMessage=blacksmith.defaults.messages.notDamagedMessage
|
||||||
|
defaults.blacksmithTitle=blacksmith.defaults.blacksmithTitle
|
||||||
|
defaults.enchantmentBlocklist=blacksmith.defaults.enchantmentBlockList
|
||||||
|
defaults.repairAnvils=blacksmith.defaults.reforgeAnvils
|
||||||
|
defaults.repairAnvils=
|
||||||
|
defaults.reforgeAnvils=blacksmith.defaults.reforgeAnvils
|
||||||
|
defaults.failReforgeRemovesEnchantments=blacksmith.defaults.failReforgeRemovesEnchantments
|
@ -3,8 +3,10 @@
|
|||||||
# The language used for messages. Only "en" is supported
|
# The language used for messages. Only "en" is supported
|
||||||
language: en
|
language: en
|
||||||
|
|
||||||
# The settings which apply to all Blacksmith NPCs. These can also be changed using the /blacksmithconfig command
|
# Settings for the blacksmith trait
|
||||||
global:
|
blacksmith:
|
||||||
|
# The settings which apply to all Blacksmith NPCs. These can also be changed using the /blacksmithconfig command
|
||||||
|
global:
|
||||||
# The minimum price of each cost
|
# The minimum price of each cost
|
||||||
basePrice:
|
basePrice:
|
||||||
# You can add, for example "diamond-sword: 15.3" to change the base cost for a specific item
|
# You can add, for example "diamond-sword: 15.3" to change the base cost for a specific item
|
||||||
@ -28,9 +30,15 @@ global:
|
|||||||
# reforging delay messages, instead of just vaguely hinting at the remaining time.
|
# reforging delay messages, instead of just vaguely hinting at the remaining time.
|
||||||
showExactTime: false
|
showExactTime: false
|
||||||
|
|
||||||
# The settings which are set to any new NPC. To change any of these settings for an existing NPC, you must change the
|
# The cost of fully repairing a chipped anvil
|
||||||
# Citizens NPC file, or use the /blacksmith command
|
chippedAnvilReforgingCost: 10.0
|
||||||
defaults:
|
|
||||||
|
# The cost of fully repairing a damaged anvil
|
||||||
|
damagedAnvilReforgingCost: 20.0
|
||||||
|
|
||||||
|
# The settings which are set to any new NPC. To change any of these settings for an existing NPC, you must change the
|
||||||
|
# Citizens NPC file, or use the /blacksmith command
|
||||||
|
defaults:
|
||||||
# Whether the item will drop a reforged item on the ground, instead of putting it into the user's inventory
|
# Whether the item will drop a reforged item on the ground, instead of putting it into the user's inventory
|
||||||
dropItem: true
|
dropItem: true
|
||||||
|
|
||||||
@ -40,29 +48,33 @@ defaults:
|
|||||||
reforgeAbleItems: [ ]
|
reforgeAbleItems: [ ]
|
||||||
|
|
||||||
# The enchantments a blacksmith is denied from applying to an item. Disable anything you find too op or annoying.
|
# The enchantments a blacksmith is denied from applying to an item. Disable anything you find too op or annoying.
|
||||||
enchantmentBlocklist: [ "binding_curse", "mending", "vanishing_curse" ]
|
enchantmentBlockList: [ "binding_curse", "mending", "vanishing_curse" ]
|
||||||
|
|
||||||
# The chance to fail reforging an item, which only repairs the item a tiny bit or not at all (0-100)
|
# The chance to fail reforging an item, which only repairs the item a tiny bit or not at all (0-100)
|
||||||
failReforgeChance: 10 # Default = 10%
|
failReforgeChance: 10 # Default = 10%
|
||||||
|
|
||||||
|
# Whether failed reforging should remove or downgrade the item's enchantments
|
||||||
|
failReforgeRemovesEnchantments: false # Default = false
|
||||||
|
|
||||||
# The chance that an enchantment will be added to the reforged item (0-100)
|
# The chance that an enchantment will be added to the reforged item (0-100)
|
||||||
extraEnchantmentChance: 5 # Default = 5%
|
extraEnchantmentChance: 5 # Default = 5%
|
||||||
|
|
||||||
# The maximum number of enchantments the blacksmith will try to add
|
# The maximum number of enchantments the blacksmith will try to add
|
||||||
maxEnchantments: 3
|
maxEnchantments: 3
|
||||||
|
|
||||||
# All settable delays
|
# Whether the blacksmith will reforge anvils as a special case
|
||||||
delaysInSeconds:
|
reforgeAnvils: false
|
||||||
# The maximum time for a reforging to finish
|
|
||||||
maximum: 30
|
|
||||||
|
|
||||||
# The minimum time for a reforging to finish
|
# The minimum time for a reforging to finish
|
||||||
minimum: 5
|
minReforgeWaitTimeSeconds: 5
|
||||||
|
|
||||||
|
# The maximum time for a reforging to finish
|
||||||
|
maxReforgeWaitTimeSeconds: 30
|
||||||
|
|
||||||
# The cool-down period between each reforge
|
# The cool-down period between each reforge
|
||||||
reforgeCoolDown: 60
|
reforgeCoolDownSeconds: 60
|
||||||
|
|
||||||
# The title describing the blacksmith's usage/speciality
|
# The title describing the blacksmith's usage/speciality (e.x: armor-smith, tool-smith, weapon-smith)
|
||||||
blacksmithTitle: "blacksmith"
|
blacksmithTitle: "blacksmith"
|
||||||
|
|
||||||
# All messages used by the NPC
|
# All messages used by the NPC
|
||||||
@ -99,3 +111,138 @@ defaults:
|
|||||||
|
|
||||||
# The message to display if a player is trying to reforge an item with full durability
|
# The message to display if a player is trying to reforge an item with full durability
|
||||||
notDamagedMessage: "&cThat item is not in need of repair"
|
notDamagedMessage: "&cThat item is not in need of repair"
|
||||||
|
|
||||||
|
# The message to display when a blacksmith is clicked with an empty hand
|
||||||
|
noItemMessage: "Please present the item you want to reforge"
|
||||||
|
|
||||||
|
# Settings for the scrapper trait
|
||||||
|
scrapper:
|
||||||
|
# The settings which apply to all Scrapper NPCs. These can also be changed using the /scrapperConfig command
|
||||||
|
global:
|
||||||
|
# Exact time displays the exact number of seconds and minutes remaining as part of the salvaging cool-down and
|
||||||
|
# salvaging delay messages, instead of just vaguely hinting at the remaining time.
|
||||||
|
showExactTime: false
|
||||||
|
|
||||||
|
# Whether enchanted salvaged items should return some amount of exp upon salvage
|
||||||
|
giveExperience: true
|
||||||
|
|
||||||
|
# Items treated as trash during salvage calculation. This follows the format:
|
||||||
|
# "MATERIAL[;MATERIAL2][;MATERIAL3]:TRASH_MATERIAL[;TRASH_MATERIAL2]", so the material or materials listed will
|
||||||
|
# treat the material specified after the ":" as trash when calculating salvage unless all non-trash items can be
|
||||||
|
# given as well(* matches any character).
|
||||||
|
trashSalvage:
|
||||||
|
- "*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD;SHIELD;*_BOW:STICK"
|
||||||
|
|
||||||
|
# The cost of using a scrapper to salvage an item
|
||||||
|
salvagePrice: 0
|
||||||
|
|
||||||
|
# The cost of using the scrapper to remove armor trim
|
||||||
|
armorTrimSalvagePrice: 5
|
||||||
|
|
||||||
|
# The cost of using the scrapper to remove netherite from an item
|
||||||
|
netheriteSalvagePrice: 15
|
||||||
|
|
||||||
|
# The settings which are set to any new scrapper NPC. To change any of these settings for an existing NPC, you must
|
||||||
|
# change the Citizens NPC file, or use the /scrapper command
|
||||||
|
defaults:
|
||||||
|
|
||||||
|
# Whether the item will drop materials resulting from salvaging on the ground, instead of putting them into the user's inventory
|
||||||
|
dropItem: true
|
||||||
|
|
||||||
|
# The chance to fail a salvage, thus destroying the item (0-100)
|
||||||
|
failSalvageChance: 0
|
||||||
|
|
||||||
|
# The items a blacksmith is able to salvage. Setting this only allows NPCs to repair the listed items. This should be
|
||||||
|
# set for each individual NPC, and should not be set here, unless you want to restrict NPCs which have not been set
|
||||||
|
# up yet.
|
||||||
|
salvageAbleItems: [ ]
|
||||||
|
|
||||||
|
# The minimum time for a salvaging to finish
|
||||||
|
minSalvageWaitTimeSeconds: 5
|
||||||
|
|
||||||
|
# The maximum time for a salvaging to finish
|
||||||
|
maxSalvageWaitTimeSeconds: 30
|
||||||
|
|
||||||
|
# The cool-down period between each salvage
|
||||||
|
salvageCoolDownSeconds: 60
|
||||||
|
|
||||||
|
# The title describing the scrapper's usage/speciality (e.x armor-scrapper, tool-scrapper, weapon-scrapper)
|
||||||
|
scrapperTitle: "scrapper"
|
||||||
|
|
||||||
|
# Whether to enable salvaging of non-repairable items, such as planks
|
||||||
|
extendedSalvageEnabled: false
|
||||||
|
|
||||||
|
# Whether to enable salvaging of enchanted items. This is disabled by default because it's possible to accidentally
|
||||||
|
# salvage items with very good enchantments.
|
||||||
|
salvageEnchanted: false
|
||||||
|
|
||||||
|
# Whether to enable salvaging of armor trims
|
||||||
|
salvageArmorTrims: true
|
||||||
|
|
||||||
|
# Whether to enable salvaging of netherite items
|
||||||
|
salvageNetherite: true
|
||||||
|
|
||||||
|
# Default values for messages used by NPCs
|
||||||
|
messages:
|
||||||
|
# The message to display when another player is using the scrapper
|
||||||
|
busyPlayerMessage: "&cI'm busy at the moment. Come back later!"
|
||||||
|
|
||||||
|
# The message to display when the blacksmith is working on the salvaging
|
||||||
|
busySalvageMessage: "&cI'm working on it. Be patient! I'll finish {time}!"
|
||||||
|
|
||||||
|
# The message to display when the scrapper is still on a cool-down from the previous salvaging
|
||||||
|
coolDownUnexpiredMessage: "&cYou've already had your chance! Give me a break! I'll be ready {time}!"
|
||||||
|
|
||||||
|
# The message to display when holding an item the blacksmith is unable to reforge
|
||||||
|
invalidItemMessage: "&cI'm sorry, but I'm a/an {title}, I don't know how to salvage that!"
|
||||||
|
|
||||||
|
# The message to display if salvaging the player's item would result in no salvage
|
||||||
|
tooDamagedForSalvageMessage: "&cThat item is too damaged to be salvaged into anything useful"
|
||||||
|
|
||||||
|
# The message to display when an item is successfully salvaged
|
||||||
|
successSalvagedMessage: "There you go!"
|
||||||
|
|
||||||
|
# The message to display when the scrapper fails to salvage an item
|
||||||
|
failSalvageMessage: "&cWhoops! The item broke! Maybe next time?"
|
||||||
|
|
||||||
|
# The message to display when the scrapper fails to salvage an item without durability
|
||||||
|
failExtendedSalvageMessage: "&cWhoops! I was unable to extract much, if any, salvage! Maybe next time?"
|
||||||
|
|
||||||
|
# The message to display when presenting a different item than the one just evaluated
|
||||||
|
itemChangedMessage: "&cThat's not the item you wanted to salvage before!"
|
||||||
|
|
||||||
|
# The message to display once the scrapper starts salvaging
|
||||||
|
startSalvageMessage: "&eOk, let's see what I can do..."
|
||||||
|
|
||||||
|
# The message to display if the player is unable to pay the scrapper's fee
|
||||||
|
insufficientFundsMessage: "&cYou don't have enough money to salvage an item!"
|
||||||
|
|
||||||
|
# The message to display when explaining the shown item's salvage cost
|
||||||
|
costMessage: "&eIt will cost &a{cost}&e to salvage that &a{item}&e! {yield} &eClick again to salvage!"
|
||||||
|
|
||||||
|
# The message to display when explaining the shown item's armor trim's salvage cost
|
||||||
|
costMessageArmorTrim: "&eIt will cost &a{cost}&e to salvage that &a{item}&e's armor trim!"
|
||||||
|
|
||||||
|
# The message to display when explaining the shown item's netherite salvage cost
|
||||||
|
costMessageNetherite: "&eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond!"
|
||||||
|
|
||||||
|
# The yield message to display if trying to salvage a non-damaged item
|
||||||
|
fullSalvageMessage: "&aI should be able to extract all components from that pristine item.&r"
|
||||||
|
|
||||||
|
# The yield message to display if trying to salvage a damaged item
|
||||||
|
partialSalvageMessage: "&cI cannot extract all components from that damaged item.&r"
|
||||||
|
|
||||||
|
# The message to display when asked to salvage an enchanted item, and that option is disabled
|
||||||
|
cannotSalvageEnchantedMessage: "&cI'm sorry, but I'm unable to salvage enchanted items!"
|
||||||
|
|
||||||
|
# The message to display when asked to salvage an armor trim, and that option is disabled
|
||||||
|
cannotSalvageArmorTrimMessage: "&cI'm sorry, but I'm unable to salvage armor trims!"
|
||||||
|
|
||||||
|
# The message to display if the correct materials to return for the armor trim are unknown
|
||||||
|
armorTrimSalvageNotFoundMessage: "&cI'm sorry, but I don't know how to salvage that armor trim!"
|
||||||
|
|
||||||
|
# The message to display when asked to salvage netherite items, and that option is disabled
|
||||||
|
cannotSalvageNetheriteMessage: "&cI'm sorry, but I'm unable to salvage netherite items!"
|
||||||
|
|
||||||
|
# The message to display when a scrapper is clicked with an empty hand
|
||||||
|
noItemMessage: "Please present the item you want to salvage"
|
@ -1,39 +1,50 @@
|
|||||||
name: Blacksmith
|
name: Blacksmith
|
||||||
author: EpicKnarvik97, aPunch, jrbudda, HurricanKai
|
|
||||||
authors: [ EpicKnarvik97, aPunch, jrbudda, HurricanKai ]
|
authors: [ EpicKnarvik97, aPunch, jrbudda, HurricanKai ]
|
||||||
version: 1.0.2
|
version: '${project.version}'
|
||||||
main: net.knarcraft.blacksmith.BlacksmithPlugin
|
main: net.knarcraft.blacksmith.BlacksmithPlugin
|
||||||
depend: [ Citizens, Vault ]
|
depend: [ Citizens, Vault ]
|
||||||
|
softdepend: [ ProtocolLib ]
|
||||||
|
prefix: "Blacksmith"
|
||||||
|
description: "A plugin that adds Blacksmith and Scrapper traits compatible with Citizens, allowing players to repair and salvage items"
|
||||||
|
website: "https://www.spigotmc.org/resources/blacksmith.105938/"
|
||||||
|
|
||||||
api-version: 1.19
|
api-version: 1.20
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
blacksmith:
|
blacksmith:
|
||||||
permission: blacksmith.edit
|
permission: blacksmith.edit
|
||||||
usage: /<command> <option> [new value]
|
usage: /<command> <option> [new value]
|
||||||
description: Used for configuring the selected blacksmith NPC
|
description: Used for configuring the selected blacksmith NPC.
|
||||||
blacksmithconfig:
|
blacksmithConfig:
|
||||||
permission: blacksmith.admin
|
permission: blacksmith.admin
|
||||||
usage: /<command> <option/reload> [new value]
|
usage: /<command> <option/reload> [new value]
|
||||||
description: Used for configuring default blacksmith settings, or global settings
|
description: Used for configuring default blacksmith settings, or global blacksmith settings.
|
||||||
|
scrapper:
|
||||||
|
permission: blacksmith.edit
|
||||||
|
usage: /<command> <option> [new value]
|
||||||
|
description: Used for configuring the selected scrapper NPC.
|
||||||
|
scrapperConfig:
|
||||||
|
permission: blacksmith.admin
|
||||||
|
usage: /<command> <option/reload> [new value]
|
||||||
|
description: Used for configuring default scrapper settings, or global scrapper settings.
|
||||||
preset:
|
preset:
|
||||||
permission: blacksmith.preset
|
permission: blacksmith.preset
|
||||||
usage: /<command> <preset>[:filter]
|
usage: /<command> <preset>[:filter]
|
||||||
description: Used to display which materials are part of a given preset. If a filter, such as diamond is used, the result of applying the filter is shown.
|
description: Used to display which materials are part of a given preset. If a filter, such as diamond is used, the result of applying the filter is shown.
|
||||||
permissions:
|
permissions:
|
||||||
blacksmith.admin:
|
blacksmith.admin:
|
||||||
description: Allows overall blacksmith configuration
|
description: Allows overall blacksmith and scrapper configuration.
|
||||||
default: op
|
default: op
|
||||||
children:
|
children:
|
||||||
blacksmith.edit: true
|
blacksmith.edit: true
|
||||||
blacksmith.use: true
|
blacksmith.use: true
|
||||||
blacksmith.preset: true
|
blacksmith.preset: true
|
||||||
blacksmith.edit:
|
blacksmith.edit:
|
||||||
description: Allows changing settings for the selected blacksmith NPC
|
description: Allows changing settings for the selected blacksmith or scrapper NPC.
|
||||||
default: op
|
default: op
|
||||||
blacksmith.use:
|
blacksmith.use:
|
||||||
description: Allows the player to repair items using blacksmiths
|
description: Allows the player to repair items using blacksmiths and salvage items using scrappers.
|
||||||
default: true
|
default: true
|
||||||
blacksmith.preset:
|
blacksmith.preset:
|
||||||
description: Allows the player to use the /preset command
|
description: Allows the player to use the /preset command.
|
||||||
default: op
|
default: op
|
@ -1,32 +1,92 @@
|
|||||||
|
# The english translation of internal strings. To add your own language, copy everything below, and change "en" to your
|
||||||
|
# own language's code, and change each string. Afterward, copy this file to Blacksmith's plugin folder, and change the
|
||||||
|
# language in config.yml to your language's language code.
|
||||||
en:
|
en:
|
||||||
|
# The format used to display when a setting's value has been changed
|
||||||
VALUE_CHANGED: "&7{setting} set to &6{newValue}"
|
VALUE_CHANGED: "&7{setting} set to &6{newValue}"
|
||||||
|
# The format used to display when a setting's value has been changed for a specific material or enchantment
|
||||||
VALUE_FOR_ITEM_CHANGED: "&7{setting} for {itemType} {item} set to &6{newValue}"
|
VALUE_FOR_ITEM_CHANGED: "&7{setting} for {itemType} {item} set to &6{newValue}"
|
||||||
|
# The format used to display the current value of a setting
|
||||||
CURRENT_VALUE: "&7Current value of {setting}:&r {currentValue}"
|
CURRENT_VALUE: "&7Current value of {setting}:&r {currentValue}"
|
||||||
|
# The format used to display the default value of a setting
|
||||||
|
DEFAULT_VALUE: "&7Default value of {setting}:&r {defaultValue}"
|
||||||
|
# The format used to display the current value of a setting for a specific material or enchantment
|
||||||
CURRENT_VALUE_FOR_ITEM: "&7Current value of {setting} for {itemType} {item}:&r {currentValue}"
|
CURRENT_VALUE_FOR_ITEM: "&7Current value of {setting} for {itemType} {item}:&r {currentValue}"
|
||||||
|
# Translation of the enchantment item type (used for VALUE_FOR_ITEM_CHANGED, CURRENT_VALUE_FOR_ITEM)
|
||||||
ITEM_TYPE_ENCHANTMENT: "enchantment"
|
ITEM_TYPE_ENCHANTMENT: "enchantment"
|
||||||
|
# Translation of the material item type (used for VALUE_FOR_ITEM_CHANGED, CURRENT_VALUE_FOR_ITEM)
|
||||||
ITEM_TYPE_MATERIAL: "material"
|
ITEM_TYPE_MATERIAL: "material"
|
||||||
|
# The format used when displaying the raw formatting of messages
|
||||||
RAW_VALUE: "Raw value: {rawValue}"
|
RAW_VALUE: "Raw value: {rawValue}"
|
||||||
NO_NPC_SELECTED: "You must select an NPC before running this command"
|
# The translation of the message displayed when the player uses /blacksmith or /scrapper without selecting an NPC first
|
||||||
DEFAULT_REFORGE_ABLE_ITEMS_UNCHANGEABLE: "Changing reforge-able items globally will make every new blacksmith unable to reforge anything not in the list, unless it's changed for the individual NPC. If you really want to change this, change it manually."
|
NO_NPC_SELECTED: "You must select an NPC with the correct trait before running this command (/npc select)"
|
||||||
|
# The translation of the message displayed when a comma-separated list of strings is expected by a setting, but not given
|
||||||
INPUT_STRING_LIST_REQUIRED: "A string list is required!"
|
INPUT_STRING_LIST_REQUIRED: "A string list is required!"
|
||||||
|
# The translation of the message displayed when a percentage is expected, but not given
|
||||||
INPUT_PERCENTAGE_REQUIRED: "You specified a value which isn't between 0 and 100!"
|
INPUT_PERCENTAGE_REQUIRED: "You specified a value which isn't between 0 and 100!"
|
||||||
|
# The translation of the message displayed when a non-empty text string is expected, but not given
|
||||||
INPUT_STRING_REQUIRED: "A non-empty string is required!"
|
INPUT_STRING_REQUIRED: "A non-empty string is required!"
|
||||||
|
# The translation of the message displayed when a positive double (comma number) is expected, but not given
|
||||||
INPUT_POSITIVE_DOUBLE_REQUIRED: "You specified a value which isn't a positive double!"
|
INPUT_POSITIVE_DOUBLE_REQUIRED: "You specified a value which isn't a positive double!"
|
||||||
|
# The translation of the message displayed when a positive integer is expected, but not given
|
||||||
INPUT_POSITIVE_INTEGER_REQUIRED: "You specified a value which isn't a positive integer!"
|
INPUT_POSITIVE_INTEGER_REQUIRED: "You specified a value which isn't a positive integer!"
|
||||||
|
# The translation of the message displayed when a player is missing the necessary permission for an action
|
||||||
PERMISSION_DENIED: "You lack the necessary permission"
|
PERMISSION_DENIED: "You lack the necessary permission"
|
||||||
|
# The translation of the message displayed when the configuration is reloaded
|
||||||
PLUGIN_RELOADED: "Blacksmith config reloaded!"
|
PLUGIN_RELOADED: "Blacksmith config reloaded!"
|
||||||
|
# The translation of the message displayed when an invalid filter is used for a smith preset
|
||||||
INVALID_FILTER_FOR_PRESET: "The specified filter is not valid for that preset"
|
INVALID_FILTER_FOR_PRESET: "The specified filter is not valid for that preset"
|
||||||
|
# The translation of the message displayed when an invalid filter or preset is specified
|
||||||
INVALID_PRESET_OR_FILTER: "You specified an invalid preset or an invalid filter"
|
INVALID_PRESET_OR_FILTER: "You specified an invalid preset or an invalid filter"
|
||||||
|
# The translation of the message displayed before listing all materials in a preset for the /preset command
|
||||||
PRESET_MATERIALS: "Materials in preset: {materials}"
|
PRESET_MATERIALS: "Materials in preset: {materials}"
|
||||||
|
# The format used when displaying any duration remaining
|
||||||
DURATION_FORMAT: "in {time} {unit}"
|
DURATION_FORMAT: "in {time} {unit}"
|
||||||
|
# The format used when NPCs talk to players ({npc} = The NPC's name, {message} is the actual message contents)
|
||||||
|
NPC_TALK_FORMAT: "&a[{npc}] -> You:&r {message}"
|
||||||
|
# Translation of the duration of less than a second
|
||||||
UNIT_NOW: "imminently"
|
UNIT_NOW: "imminently"
|
||||||
|
# Translation of seconds in singular form
|
||||||
UNIT_SECOND: "second"
|
UNIT_SECOND: "second"
|
||||||
|
# Translation of seconds in plural form
|
||||||
UNIT_SECONDS: "seconds"
|
UNIT_SECONDS: "seconds"
|
||||||
|
# Translation of minutes in singular form
|
||||||
UNIT_MINUTE: "minute"
|
UNIT_MINUTE: "minute"
|
||||||
|
# Translation of minutes in plural form
|
||||||
UNIT_MINUTES: "minutes"
|
UNIT_MINUTES: "minutes"
|
||||||
|
# Translation of hour in singular form
|
||||||
|
UNIT_HOUR: "hour"
|
||||||
|
# Translation of hour in plural form
|
||||||
|
UNIT_HOURS: "hours"
|
||||||
|
# Translation of days in singular form
|
||||||
|
UNIT_DAY: "day"
|
||||||
|
# Translation of days in plural form
|
||||||
|
UNIT_DAYS: "days"
|
||||||
|
# Translation of weeks in singular form
|
||||||
|
UNIT_WEEK: "week"
|
||||||
|
# Translation of weeks in plural form
|
||||||
|
UNIT_WEEKS: "weeks"
|
||||||
|
# Translation of months in singular form
|
||||||
|
UNIT_MONTH: "month"
|
||||||
|
# Translation of months in plural form
|
||||||
|
UNIT_MONTHS: "months"
|
||||||
|
# Translation of years in singular form
|
||||||
|
UNIT_YEAR: "year"
|
||||||
|
# Translation of years in plural form
|
||||||
|
UNIT_YEARS: "years"
|
||||||
|
# Translation of decades in singular form
|
||||||
|
UNIT_DECADE: "decade"
|
||||||
|
# Translation of decades in plural form
|
||||||
|
UNIT_DECADES: "decades"
|
||||||
|
# The text shown if the player has less than 10 seconds left of waiting
|
||||||
INTERVAL_LESS_THAN_10_SECONDS: "in just a moment"
|
INTERVAL_LESS_THAN_10_SECONDS: "in just a moment"
|
||||||
|
# The text shown if the player has to wait between 10 and 30 seconds
|
||||||
INTERVAL_LESS_THAN_30_SECONDS: "in a little while"
|
INTERVAL_LESS_THAN_30_SECONDS: "in a little while"
|
||||||
|
# The text shown if the player has to wait for between 30 seconds and 1 minute
|
||||||
INTERVAL_LESS_THAN_1_MINUTE: "in a while"
|
INTERVAL_LESS_THAN_1_MINUTE: "in a while"
|
||||||
|
# The text shown if the player has to wait for less than 5 minutes, but more than 1 minute
|
||||||
INTERVAL_LESS_THAN_5_MINUTES: "after some time"
|
INTERVAL_LESS_THAN_5_MINUTES: "after some time"
|
||||||
|
# The text shown if the player has to wait for more than 5 minutes
|
||||||
INTERVAL_MORE_THAN_5_MINUTES: "in quite a while"
|
INTERVAL_MORE_THAN_5_MINUTES: "in quite a while"
|
||||||
|
# The marker shown when displaying values overridden for the selected NPC (not shown if the NPC inherits the default value)
|
||||||
SETTING_OVERRIDDEN_MARKER: " [NPC]"
|
SETTING_OVERRIDDEN_MARKER: " [NPC]"
|
@ -0,0 +1,130 @@
|
|||||||
|
package net.knarcraft.blacksmith.util;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A test class to test the config helper
|
||||||
|
*/
|
||||||
|
public class ConfigHelperTest {
|
||||||
|
|
||||||
|
private static List<String> expectedStringList;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public static void setUp() {
|
||||||
|
expectedStringList = new ArrayList<>();
|
||||||
|
for (int i = 1; i < 8; i++) {
|
||||||
|
expectedStringList.add(String.valueOf(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asStringListStringTest() {
|
||||||
|
assertEquals(expectedStringList, ConfigHelper.asStringList("1,2,3,4,5,6,7"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asStringListStringListTest() {
|
||||||
|
List<String> testValues = new ArrayList<>();
|
||||||
|
for (int i = 1; i < 8; i++) {
|
||||||
|
testValues.add(String.valueOf(i));
|
||||||
|
}
|
||||||
|
assertEquals(expectedStringList, ConfigHelper.asStringList(testValues));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asStringListIntListTest() {
|
||||||
|
List<Integer> testValues = new ArrayList<>();
|
||||||
|
for (int i = 1; i < 8; i++) {
|
||||||
|
testValues.add(i);
|
||||||
|
}
|
||||||
|
assertEquals(expectedStringList, ConfigHelper.asStringList(testValues));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asDoubleDoubleTest() {
|
||||||
|
assertEquals(5.244352345, ConfigHelper.asDouble(5.244352345));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asDoubleIntTest() {
|
||||||
|
assertEquals(554636d, ConfigHelper.asDouble(554636));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asDoubleDoubleStringTest() {
|
||||||
|
assertEquals(54.54642388, ConfigHelper.asDouble("54.54642388"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asDoubleIntStringTest() {
|
||||||
|
assertEquals(967876554, ConfigHelper.asDouble("967876554"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asDoubleInvalidDoubleStringTest() {
|
||||||
|
assertThrows(NumberFormatException.class, () -> ConfigHelper.asDouble("Potato"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asDoubleInvalidObjectTest() {
|
||||||
|
assertThrows(ClassCastException.class, () -> ConfigHelper.asDouble(new ArrayList<>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asBooleanTrueTest() {
|
||||||
|
assertTrue(ConfigHelper.asBoolean(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asBooleanFalseTest() {
|
||||||
|
assertFalse(ConfigHelper.asBoolean(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asBooleanTrueStringTest() {
|
||||||
|
assertTrue(ConfigHelper.asBoolean("trUe"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asBooleanFalseStringTest() {
|
||||||
|
assertFalse(ConfigHelper.asBoolean("faLse"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asBooleanInvalidStringTest() {
|
||||||
|
assertFalse(ConfigHelper.asBoolean("potato"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asBooleanInvalidObjectTest() {
|
||||||
|
assertThrows(ClassCastException.class, () -> {
|
||||||
|
boolean result = ConfigHelper.asBoolean(new ArrayList<>());
|
||||||
|
assertFalse(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asIntIntTest() {
|
||||||
|
assertEquals(5466547, ConfigHelper.asInt(5466547));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asIntStringIntTest() {
|
||||||
|
assertEquals(976586547, ConfigHelper.asInt("976586547"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asIntInvalidTest() {
|
||||||
|
assertThrows(ClassCastException.class, () -> ConfigHelper.asInt(54675467d));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
package net.knarcraft.blacksmith.util;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A test class for testing input parsing
|
||||||
|
*/
|
||||||
|
public class InputParsingHelperTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isEmptyTrueTest() {
|
||||||
|
assertTrue(InputParsingHelper.isEmpty(null));
|
||||||
|
assertTrue(InputParsingHelper.isEmpty("-1"));
|
||||||
|
assertTrue(InputParsingHelper.isEmpty("\"\""));
|
||||||
|
assertTrue(InputParsingHelper.isEmpty("null"));
|
||||||
|
assertTrue(InputParsingHelper.isEmpty(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isEmptyFalseTest() {
|
||||||
|
assertFalse(InputParsingHelper.isEmpty("potato"));
|
||||||
|
assertFalse(InputParsingHelper.isEmpty("67465775"));
|
||||||
|
assertFalse(InputParsingHelper.isEmpty("657.4655467"));
|
||||||
|
assertFalse(InputParsingHelper.isEmpty(" a "));
|
||||||
|
assertFalse(InputParsingHelper.isEmpty("\"fish\""));
|
||||||
|
assertFalse(InputParsingHelper.isEmpty("-657858"));
|
||||||
|
assertFalse(InputParsingHelper.isEmpty("-6578.58"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void matchMaterialValidTest() {
|
||||||
|
assertEquals(Material.DIAMOND_PICKAXE, InputParsingHelper.matchMaterial("DIAMOND_PICKAXE"));
|
||||||
|
assertEquals(Material.DIAMOND_AXE, InputParsingHelper.matchMaterial("DIAMOND_axe"));
|
||||||
|
assertEquals(Material.IRON_SWORD, InputParsingHelper.matchMaterial("iron-SWORD"));
|
||||||
|
assertEquals(Material.WOODEN_HOE, InputParsingHelper.matchMaterial("wOoDeN-HoE"));
|
||||||
|
assertEquals(Material.ACACIA_CHEST_BOAT, InputParsingHelper.matchMaterial("ACACIA-chest_bOaT"));
|
||||||
|
assertEquals(Material.NETHERITE_PICKAXE, InputParsingHelper.matchMaterial("netherite pickaxe"));
|
||||||
|
assertEquals(Material.STONE_SHOVEL, InputParsingHelper.matchMaterial("minecraft:stone_shovel"));
|
||||||
|
assertEquals(Material.GOLDEN_BOOTS, InputParsingHelper.matchMaterial("minecraft:golden BOOTS"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void matchMaterialInvalidTest() {
|
||||||
|
assertNull(InputParsingHelper.matchMaterial("this_item_does_not_exist"));
|
||||||
|
assertNull(InputParsingHelper.matchMaterial("stone:pickaxe"));
|
||||||
|
assertNull(InputParsingHelper.matchMaterial("aron sword"));
|
||||||
|
assertNull(InputParsingHelper.matchMaterial("minecraft : golden BOOTS"));
|
||||||
|
assertNull(InputParsingHelper.matchMaterial("minecraft: golden BOOTS"));
|
||||||
|
assertNull(InputParsingHelper.matchMaterial("MINECRAFT:golden-BOOTS"));
|
||||||
|
assertNull(InputParsingHelper.matchMaterial("minecraft: golden-BOOTS"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void regExIfyTest() {
|
||||||
|
assertEquals("NO REGEX HERE", InputParsingHelper.regExIfy("no regEx here"));
|
||||||
|
assertEquals("NO_REGEX_HERE", InputParsingHelper.regExIfy("no-regEx-here"));
|
||||||
|
assertEquals("NETHERITE.*", InputParsingHelper.regExIfy("netherite*"));
|
||||||
|
assertEquals("GOLDEN_.*", InputParsingHelper.regExIfy("golden-*"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package net.knarcraft.blacksmith.util;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for the ItemHelper class
|
||||||
|
*/
|
||||||
|
public class ItemHelperTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isAnvilRequiresDamagedTest() {
|
||||||
|
assertTrue(ItemHelper.isAnvil(Material.DAMAGED_ANVIL, true));
|
||||||
|
assertTrue(ItemHelper.isAnvil(Material.CHIPPED_ANVIL, true));
|
||||||
|
|
||||||
|
assertFalse(ItemHelper.isAnvil(Material.ANVIL, true));
|
||||||
|
assertFalse(ItemHelper.isAnvil(Material.POTATO, true));
|
||||||
|
assertFalse(ItemHelper.isAnvil(Material.IRON_HOE, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isAnvilTest() {
|
||||||
|
assertTrue(ItemHelper.isAnvil(Material.ANVIL, false));
|
||||||
|
assertTrue(ItemHelper.isAnvil(Material.DAMAGED_ANVIL, false));
|
||||||
|
assertTrue(ItemHelper.isAnvil(Material.CHIPPED_ANVIL, false));
|
||||||
|
|
||||||
|
assertFalse(ItemHelper.isAnvil(Material.POTATO, false));
|
||||||
|
assertFalse(ItemHelper.isAnvil(Material.IRON_HOE, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,147 @@
|
|||||||
|
package net.knarcraft.blacksmith.util;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.config.SettingValueType;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for the type validator helper
|
||||||
|
*/
|
||||||
|
public class TypeValidatorHelperTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isValidPositiveDoubleValidTest() {
|
||||||
|
SettingValueType type = SettingValueType.POSITIVE_DOUBLE;
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, 6578d, null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, 5346.4534, null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, "237.4378", null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, 74567, null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, "843552", null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isValidPositiveDoubleInvalidTest() {
|
||||||
|
SettingValueType type = SettingValueType.POSITIVE_DOUBLE;
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, "potato", null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, 354f, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, SettingValueType.STRING, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, -1, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, -0.45654, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isValidStringValidTest() {
|
||||||
|
assertTrue(TypeValidationHelper.isValid(SettingValueType.STRING, "potato", null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isValidStringInvalidTest() {
|
||||||
|
SettingValueType type = SettingValueType.STRING;
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, 5467, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, SettingValueType.POSITIVE_DOUBLE, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, "", null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, " ", null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isValidPositiveIntegerValidTest() {
|
||||||
|
SettingValueType type = SettingValueType.POSITIVE_INTEGER;
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, 6574567, null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, "785768", null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isValidPositiveIntegerInvalidTest() {
|
||||||
|
SettingValueType type = SettingValueType.POSITIVE_INTEGER;
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, 0.2345, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, -1, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, "potato", null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isValidPercentageValidTest() {
|
||||||
|
SettingValueType type = SettingValueType.PERCENTAGE;
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, 33, null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, 100, null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, 0, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isValidPercentageInvalidTest() {
|
||||||
|
SettingValueType type = SettingValueType.PERCENTAGE;
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, -1, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, -73, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, 101, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, 14.4, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, "potato", null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isValidBooleanValidTest() {
|
||||||
|
SettingValueType type = SettingValueType.BOOLEAN;
|
||||||
|
//Note: As anything invalid will just be parsed to false, anything goes
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, null, null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, "potato", null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, "True", null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, "False", null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, "On", null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, "Off", null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isValidStringListValidTest() {
|
||||||
|
SettingValueType type = SettingValueType.STRING_LIST;
|
||||||
|
List<String> testList = new ArrayList<>();
|
||||||
|
testList.add("fish");
|
||||||
|
testList.add("potato");
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, "1, 2, 3, 4, 5, 6, 7, 8", null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, new ArrayList<>(), null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, testList, null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, "potato", null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, "", null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, new String[]{"a", "b", "c"}, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isValidStringListInvalidTest() {
|
||||||
|
SettingValueType type = SettingValueType.STRING_LIST;
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, null, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, 456, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, -2345.4321, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isValidMaterialValidTest() {
|
||||||
|
SettingValueType type = SettingValueType.MATERIAL;
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, Material.POTATO, null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, "POTATO", null));
|
||||||
|
assertTrue(TypeValidationHelper.isValid(type, "minecraft:potato", null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isValidMaterialInvalidTest() {
|
||||||
|
SettingValueType type = SettingValueType.MATERIAL;
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, null, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, 1, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, "random", null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, -546.678, null));
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, true, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isValidEnchantmentInvalidTest() {
|
||||||
|
SettingValueType type = SettingValueType.ENCHANTMENT;
|
||||||
|
assertFalse(TypeValidationHelper.isValid(type, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user