This commit is contained in:
BuildTools 2024-05-16 15:45:18 +05:00
parent 5cfdf14198
commit 359782ff57
43 changed files with 815 additions and 206 deletions

4
.gitignore vendored
View File

@ -16,4 +16,6 @@
/V1_20_R3/target/
/V1_20_R3/pom.xml.versionsBackup
/API/target/
/API/pom.xml.versionsBackup
/API/pom.xml.versionsBackup
/MC_1_20_6/target/
/MC_1_20_6/pom.xml.versionsBackup

View File

@ -5,15 +5,16 @@
<parent>
<artifactId>ExcellentEnchants</artifactId>
<groupId>su.nightexpress.excellentenchants</groupId>
<version>4.0.4</version>
<version>4.0.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>API</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@ -0,0 +1,51 @@
package su.nightexpress.excellentenchants.api.enchantment;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
public class Cost {
private final int base;
private final int perLevel;
public Cost(int base, int perLevel) {
this.base = base;
this.perLevel = perLevel;
}
@NotNull
public static Cost read(@NotNull FileConfig config, @NotNull String path, @NotNull Cost defaultValue, String ... comments) {
return ConfigValue.create(path,
(cfg2, path2, def2) -> Cost.read(cfg2, path2),
(cfg2, path2, mod) -> mod.write(cfg2, path2),
() -> defaultValue,
comments
).read(config);
}
@NotNull
public static Cost read(@NotNull FileConfig config, @NotNull String path) {
int base = ConfigValue.create(path + ".Base", 0).read(config);
int perLevel = ConfigValue.create(path + ".Per_Level", 0).read(config);
return new Cost(base, perLevel);
}
public void write(@NotNull FileConfig config, @NotNull String path) {
config.set(path + ".Base", this.base());
config.set(path + ".Per_Level", this.perLevel());
}
public int calculate(int level) {
return this.base + this.perLevel * (level - 1);
}
public int base() {
return this.base;
}
public int perLevel() {
return this.perLevel;
}
}

View File

@ -20,6 +20,10 @@ import java.util.Set;
public interface EnchantmentData {
default void clear() {
}
@NotNull PlaceholderMap getPlaceholders(int level);
@NotNull FileConfig getConfig();
@ -81,14 +85,8 @@ public interface EnchantmentData {
@NotNull Set<String> getConflicts();
int getMinLevel();
int getMaxLevel();
//int getMaxMergeLevel();
//int getAnvilMergeCost(int level);
int getMinCost(int level);
int getMaxCost(int level);
@ -153,23 +151,19 @@ public interface EnchantmentData {
void setTreasure(boolean treasure);
void setStartLevel(int levelMin);
void setMaxLevel(int levelMax);
//void setMaxMergeLevel(int maxMergeLevel);
@NotNull Cost getMinCost();
@NotNull Modifier getMinCost();
void setMinCost(@NotNull Cost minCost);
void setMinCost(@NotNull Modifier minCost);
@NotNull Cost getMaxCost();
@NotNull Modifier getMaxCost();
void setMaxCost(@NotNull Cost maxCost);
void setMaxCost(@NotNull Modifier maxCost);
int getAnvilCost();
//@NotNull Modifier getAnvilMergeCost();
//void setAnvilMergeCost(@NotNull Modifier anvilMergeCost);
void setAnvilCost(int anvilCost);
default void setConflicts(@NotNull String... conflicts) {
this.setConflicts(Lists.newSet(conflicts));

View File

@ -5,15 +5,15 @@
<parent>
<artifactId>ExcellentEnchants</artifactId>
<groupId>su.nightexpress.excellentenchants</groupId>
<version>4.0.4</version>
<version>4.0.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Core</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
@ -67,32 +67,37 @@
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>API</artifactId>
<version>4.0.4</version>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>NMS</artifactId>
<version>4.0.4</version>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>MC_1_20_6</artifactId>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>V1_20_R3</artifactId>
<version>4.0.4</version>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>V1_20_R2</artifactId>
<version>4.0.4</version>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>V1_20_R1</artifactId>
<version>4.0.4</version>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>V1_19_R3</artifactId>
<version>4.0.4</version>
<version>4.0.5</version>
</dependency>
</dependencies>

View File

@ -110,6 +110,7 @@ public class EnchantsPlugin extends NightPlugin {
case V1_20_R1 -> new V1_20_R1();
case V1_20_R2 -> new V1_20_R2();
case V1_20_R3 -> new V1_20_R3();
case MC_1_20_6 -> new Internal1_20_6();
default -> null;
};
return this.enchantNMS != null;

View File

@ -7,9 +7,9 @@ import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.EnchantsPlugin;
import su.nightexpress.excellentenchants.config.Perms;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.config.Lang;
import su.nightexpress.excellentenchants.config.Perms;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
import su.nightexpress.nightcore.command.CommandResult;
import su.nightexpress.nightcore.command.impl.AbstractCommand;

View File

@ -75,7 +75,7 @@ public class RarityBookCommand extends AbstractCommand<EnchantsPlugin> {
int level = result.getInt(3, -1);
if (level < 1) {
level = Rnd.get(enchantmentData.getMinLevel(), enchantmentData.getMaxLevel());
level = Rnd.get(1, enchantmentData.getMaxLevel());
}
ItemStack item = new ItemStack(Material.ENCHANTED_BOOK);

View File

@ -60,12 +60,13 @@ public class EnchantManager extends AbstractManager<EnchantsPlugin> {
}
}
@Override
protected void onShutdown() {
if (this.enchantmentsListMenu != null) this.enchantmentsListMenu.clear();
if (EnchantRegistry.isRegistered(FlameWalkerEnchant.ID)) {
/*if (EnchantRegistry.isRegistered(FlameWalkerEnchant.ID)) {
FlameWalkerEnchant.clear();
}
}*/
}
@NotNull

View File

@ -215,7 +215,7 @@ public class EnchantPopulator {
// Level generation failed.
int level = this.getLevelGenerator().apply(enchantmentData, distribution);
if (level < enchantmentData.getMinLevel()) {
if (level < 1) {
this.purge(rarity, enchantmentData);
continue;
}

View File

@ -14,13 +14,14 @@ import org.jetbrains.annotations.Nullable;
import su.nightexpress.excellentenchants.EnchantsPlugin;
import su.nightexpress.excellentenchants.api.DistributionWay;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.distribution.DistributionOptions;
import su.nightexpress.excellentenchants.api.enchantment.Cost;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.PeriodicData;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionData;
import su.nightexpress.excellentenchants.api.enchantment.distribution.DistributionOptions;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.enchantment.util.EnchantPlaceholders;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
@ -56,13 +57,11 @@ public abstract class AbstractEnchantmentData extends AbstractFileData<EnchantsP
private boolean treasure;
private boolean visualEffects;
private int minLevel;
private int maxLevel;
//private int maxMergeLevel;
private Modifier minCost;
private Modifier maxCost;
//private Modifier anvilMergeCost;
private Cost minCost;
private Cost maxCost;
private int anvilCost;
private boolean chargesEnabled;
private boolean chargesCustomFuel;
@ -80,7 +79,6 @@ public abstract class AbstractEnchantmentData extends AbstractFileData<EnchantsP
super(plugin, file);
this.setDescription(new ArrayList<>());
this.setRarity(Rarity.COMMON);
this.setStartLevel(1);
this.setMaxLevel(3);
this.conflicts = new HashSet<>();
@ -110,9 +108,12 @@ public abstract class AbstractEnchantmentData extends AbstractFileData<EnchantsP
protected boolean onLoad(@NotNull FileConfig cfg) {
this.setRarity(ConfigValue.create("Settings.Rarity", Rarity.class, this.rarity,
"The rarity is an attribute of an enchantment.",
"It affects the chance of getting an enchantment from enchanting or loots as well as the combination cost in anvil."
"It affects the chance of getting an enchantment from enchanting or loots as well as the combination cost in anvil.",
"[*] Only for versions BELOW 1.20.6!"
).read(cfg));
// TODO Custom rarity class for 1.21
this.setDisplayName(ConfigValue.create("Settings.Name",
StringUtil.capitalizeUnderscored(this.getId()),
"Enchantment name."
@ -124,11 +125,6 @@ public abstract class AbstractEnchantmentData extends AbstractFileData<EnchantsP
"You can use 'Enchantment' placeholders: " + URL_PLACEHOLDERS
).read(cfg));
this.setStartLevel(ConfigValue.create("Settings.Level.Min",
this.getMinLevel(),
"Min. enchantment level."
).read(cfg));
this.setMaxLevel(ConfigValue.create("Settings.Level.Max",
this.getMaxLevel(),
"Max. enchantment level."
@ -159,22 +155,24 @@ public abstract class AbstractEnchantmentData extends AbstractFileData<EnchantsP
).read(cfg));
//int costAdjust = Math.max(7, 42 - this.getMaxLevel() * 7);
double costBase = Config.isVanillaDistribution() ? 45D : 30D;
double costMaxBase = Config.isVanillaDistribution() ? Rnd.get(6, 8) : 0;
double costAdjust = costBase / this.getMaxLevel();
int costBase = Config.isVanillaDistribution() ? 45 : 30;
int costStart = Rnd.get(5) + 1;
int costMod = Rnd.get(10) + 1;
int costPerLevel = (int) ((double) costBase / (double) this.getMaxLevel());
this.setMinCost(Modifier.read(cfg, "Distribution." + DistributionWay.ENCHANTING.getPathName() + ".Min_Cost",
Modifier.add(1 - costAdjust, costAdjust - 1, 1),
this.setMinCost(Cost.read(cfg, "Distribution." + DistributionWay.ENCHANTING.getPathName() + ".Cost.Min",
new Cost(costStart, costPerLevel),
VANILLA_DISTRIBUTION_HEADER,
"Sets min. **modified** level cost for this enchantment to be selected in enchanting table.",
"Explanation: https://minecraft.wiki/w/Enchanting_mechanics#How_enchantments_are_chosen",
"Vanilla costs: https://minecraft.wiki/w/Enchanting/Levels",
CUSTOM_DISTRIBUTION_HEADER,
"Sets min. **plain** level cost for this enchantment to be selected in enchanting table.")
"Sets min. **plain** level cost for this enchantment to be selected in enchanting table."
)
);
this.setMaxCost(Modifier.read(cfg, "Distribution." + DistributionWay.ENCHANTING.getPathName() + ".Max_Cost",
Modifier.add(costMaxBase, costAdjust, 1),
this.setMaxCost(Cost.read(cfg, "Distribution." + DistributionWay.ENCHANTING.getPathName() + ".Cost.Max",
new Cost(costStart * costMod, costPerLevel),
VANILLA_DISTRIBUTION_HEADER,
"Sets max. **modified** level cost for this enchantment to be selected in enchanting table.",
"Explanation: https://minecraft.wiki/w/Enchanting_mechanics#How_enchantments_are_chosen",
@ -183,6 +181,13 @@ public abstract class AbstractEnchantmentData extends AbstractFileData<EnchantsP
"Sets max. **plain** level cost for this enchantment to be selected in enchanting table.")
);
// TODO Check what actually does
this.setAnvilCost(ConfigValue.create("Anvil.Cost",
Rnd.get(8) + 1,
"Sets enchantment anvil cost.",
"[*] Works for 1.20.6+ only!"
).read(cfg));
this.distributionOptions.load(cfg);
@ -242,7 +247,7 @@ public abstract class AbstractEnchantmentData extends AbstractFileData<EnchantsP
.add(ENCHANTMENT_DESCRIPTION_FORMATTED, () -> String.join("\n", this.getDescriptionFormatted()))
.add(ENCHANTMENT_DESCRIPTION_REPLACED, level -> String.join("\n", this.getDescriptionReplaced(level)))
.add(ENCHANTMENT_LEVEL, NumberUtil::toRoman)
.add(ENCHANTMENT_LEVEL_MIN, () -> String.valueOf(this.getMinLevel()))
.add(ENCHANTMENT_LEVEL_MIN, () -> String.valueOf(1))
.add(ENCHANTMENT_LEVEL_MAX, () -> String.valueOf(this.getMaxLevel()))
.add(ENCHANTMENT_RARITY, () -> plugin.getLangManager().getEnum(this.getRarity()))
.add(ENCHANTMENT_FIT_ITEM_TYPES, () -> {
@ -327,7 +332,7 @@ public abstract class AbstractEnchantmentData extends AbstractFileData<EnchantsP
case ARMOR_FEET -> new EquipmentSlot[]{EquipmentSlot.FEET};
case ARMOR, WEARABLE -> new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
case BREAKABLE -> new EquipmentSlot[]{EquipmentSlot.HAND, EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
case VANISHABLE -> EquipmentSlot.values();
case VANISHABLE -> EnchantUtils.EQUIPMENT_SLOTS;
default -> throw new IllegalStateException("Unexpected value: " + this.getCategory());
};
}
@ -345,10 +350,12 @@ public abstract class AbstractEnchantmentData extends AbstractFileData<EnchantsP
@Override
public boolean checkEnchantLimit(@NotNull ItemStack item) {
int limit = Config.CORE_ITEM_ENCHANT_LIMIT.get();
int has = EnchantUtils.countCustomEnchantments(item);
// Allow to re-enchant item with the same enchantment.
if (EnchantUtils.contains(item, this.getEnchantment())) {
return true;
}
return has < limit;
return !EnchantUtils.hasMaximumEnchants(item);
}
@Override
@ -373,7 +380,7 @@ public abstract class AbstractEnchantmentData extends AbstractFileData<EnchantsP
}
public int generateLevel() {
return Rnd.get(this.getMinLevel(), this.getMaxLevel());
return Rnd.get(1, this.getMaxLevel());
}
@Override
@ -423,12 +430,12 @@ public abstract class AbstractEnchantmentData extends AbstractFileData<EnchantsP
@Override
public int getMinCost(int level) {
return this.getMinCost().getIntValue(level);
return this.getMinCost().calculate(level);
}
@Override
public int getMaxCost(int level) {
return this.getMaxCost().getIntValue(level);
return this.getMaxCost().calculate(level);
}
/*@Override
@ -590,16 +597,6 @@ public abstract class AbstractEnchantmentData extends AbstractFileData<EnchantsP
this.treasure = treasure;
}
@Override
public void setStartLevel(int levelMin) {
this.minLevel = Math.max(1, levelMin);
}
@Override
public int getMinLevel() {
return this.minLevel;
}
@Override
public void setMaxLevel(int levelMax) {
this.maxLevel = Math.max(1, levelMax);
@ -612,26 +609,36 @@ public abstract class AbstractEnchantmentData extends AbstractFileData<EnchantsP
@Override
@NotNull
public Modifier getMinCost() {
public Cost getMinCost() {
return this.minCost;
}
@Override
public void setMinCost(@NotNull Modifier minCost) {
public void setMinCost(@NotNull Cost minCost) {
this.minCost = minCost;
}
@Override
@NotNull
public Modifier getMaxCost() {
public Cost getMaxCost() {
return this.maxCost;
}
@Override
public void setMaxCost(@NotNull Modifier maxCost) {
public void setMaxCost(@NotNull Cost maxCost) {
this.maxCost = maxCost;
}
@Override
public int getAnvilCost() {
return anvilCost;
}
@Override
public void setAnvilCost(int anvilCost) {
this.anvilCost = anvilCost;
}
/*@Override
@NotNull
public Modifier getAnvilMergeCost() {

View File

@ -123,7 +123,7 @@ public class CustomDistribution implements DistributionOptions {
int levelCapMin = this.getMinLevel(distributionWay);
int levelCapMax = this.getMaxLevel(distributionWay);
if (levelCapMin <= 0 || levelCapMin < this.enchantmentData.getMinLevel()) levelCapMin = this.enchantmentData.getMinLevel();
if (levelCapMin < 1) levelCapMin = 1;
if (levelCapMax <= 0 || levelCapMax > this.enchantmentData.getMaxLevel()) levelCapMax = this.enchantmentData.getMaxLevel();
return Rnd.get(levelCapMin, levelCapMax);
@ -132,7 +132,7 @@ public class CustomDistribution implements DistributionOptions {
public int getLevelByEnchantCost(int xpLevel) {
int get = 0;
for (int level = this.enchantmentData.getMaxLevel(); level > this.enchantmentData.getMinLevel() - 1; level--) {
for (int level = this.enchantmentData.getMaxLevel(); level > 0; level--) {
if (xpLevel >= this.enchantmentData.getMinCost(level) && xpLevel <= this.enchantmentData.getMaxCost(level)) {
get = level;
break;

View File

@ -62,7 +62,8 @@ public class FlameWalkerEnchant extends AbstractEnchantmentData implements Gener
"Sets up to how long (in seconds) blocks will stay before turn back to lava.");
}
public static void clear() {
@Override
public void clear() {
BLOCKS_TO_DESTROY.keySet().forEach(location -> location.getBlock().setType(Material.LAVA));
BLOCKS_TO_DESTROY.clear();
}

View File

@ -79,6 +79,11 @@ public class TreasureHunterEnchant extends AbstractEnchantmentData implements Ch
}
}
@Override
public void clear() {
this.lootTables.clear();
}
@NotNull
@Override
public ChanceSettings getChanceSettings() {

View File

@ -41,7 +41,6 @@ public class SurvivalistEnchant extends AbstractEnchantmentData implements Fishi
protected void loadAdditional(@NotNull FileConfig config) {
this.chanceSettings = ChanceSettingsImpl.create(config);
this.cookingRecipes.clear();
this.plugin.getServer().recipeIterator().forEachRemaining(recipe -> {
if (recipe instanceof CookingRecipe<?> cookingRecipe && cookingRecipe.getInput().getType().isItem()) {
this.cookingRecipes.add(cookingRecipe);
@ -49,6 +48,11 @@ public class SurvivalistEnchant extends AbstractEnchantmentData implements Fishi
});
}
@Override
public void clear() {
this.cookingRecipes.clear();
}
@NotNull
@Override
public ChanceSettings getChanceSettings() {

View File

@ -36,6 +36,7 @@ import su.nightexpress.nightcore.util.Plugins;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;
public class SilkChestEnchant extends AbstractEnchantmentData implements BlockDropEnchant, SimpeListener {
@ -123,9 +124,12 @@ public class SilkChestEnchant extends AbstractEnchantmentData implements BlockDr
if (!(state instanceof Chest chest)) return false;
// Добавляем в сундук обратно предметы из дроп листа, кроме самого сундука.
event.getItems().removeIf(drop -> drop.getItemStack().getType() == state.getType() && drop.getItemStack().getAmount() == 1);
// Remove original chest from drops to prevent duplication.
AtomicBoolean originRemoved = new AtomicBoolean(false);
event.getItems().removeIf(drop -> drop.getItemStack().getType() == state.getType() && drop.getItemStack().getAmount() == 1 && !originRemoved.getAndSet(true));
// Add chest content back to the chest.
chest.getBlockInventory().addItem(event.getItems().stream().map(Item::getItemStack).toList().toArray(new ItemStack[0]));
// Drop nothing of chest content.
event.getItems().clear();
if (chest.getBlockInventory().isEmpty()) {

View File

@ -27,6 +27,7 @@ import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.BukkitThing;
import su.nightexpress.nightcore.util.Lists;
import su.nightexpress.nightcore.util.LocationUtil;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
import su.nightexpress.nightcore.util.wrapper.UniSound;
@ -44,7 +45,7 @@ public class SmelterEnchant extends AbstractEnchantmentData implements ChanceDat
private boolean disableOnCrouch;
private ChanceSettingsImpl chanceSettings;
private final Set<Material> exemptedBlocks;
private final Set<Material> exemptedItems;
private final Set<FurnaceRecipe> recipes;
public SmelterEnchant(@NotNull EnchantsPlugin plugin, @NotNull File file) {
@ -57,18 +58,12 @@ public class SmelterEnchant extends AbstractEnchantmentData implements ChanceDat
Enchantment.SILK_TOUCH.getKey().getKey()
);
this.exemptedBlocks = new HashSet<>();
this.exemptedItems = new HashSet<>();
this.recipes = new HashSet<>();
}
@Override
protected void loadAdditional(@NotNull FileConfig config) {
this.plugin.getServer().recipeIterator().forEachRemaining(recipe -> {
if (recipe instanceof FurnaceRecipe furnaceRecipe && furnaceRecipe.getInput().getType().isBlock()) {
this.recipes.add(furnaceRecipe);
}
});
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(10, 8, 1, 100));
this.disableOnCrouch = ConfigValue.create("Settings.Disable_On_Crouch",
@ -82,12 +77,26 @@ public class SmelterEnchant extends AbstractEnchantmentData implements ChanceDat
"https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Sound.html"
).read(config);
this.exemptedBlocks.addAll(ConfigValue.forSet("Settings.Exempted_Blocks",
this.exemptedItems.addAll(ConfigValue.forSet("Settings.Exempted_Blocks",
BukkitThing::getMaterial,
(cfg, path, set) -> cfg.set(path, set.stream().map(material -> material.getKey().getKey()).toList()),
Set.of(Material.STONE),
"List of blocks that are immune to smelter effect."
(cfg, path, set) -> cfg.set(path, set.stream().map(BukkitThing::toString).toList()),
Lists.newSet(Material.COBBLESTONE),
"List of blocks / items that are immune to the Smelter effect."
).read(config));
this.plugin.getServer().recipeIterator().forEachRemaining(recipe -> {
if (!(recipe instanceof FurnaceRecipe furnaceRecipe)) return;
if (!this.exemptedItems.contains(furnaceRecipe.getInput().getType())) {
this.recipes.add(furnaceRecipe);
}
});
}
@Override
public void clear() {
this.recipes.clear();
this.exemptedItems.clear();
}
@NotNull
@ -113,8 +122,7 @@ public class SmelterEnchant extends AbstractEnchantmentData implements ChanceDat
if (this.disableOnCrouch && entity instanceof Player player && player.isSneaking()) return false;
BlockState state = event.getBlockState();
if (state instanceof Container || this.exemptedBlocks.contains(state.getType())) return false;
if (state instanceof Container) return false;
if (!this.checkTriggerChance(level)) return false;
List<ItemStack> smelts = new ArrayList<>();
@ -122,14 +130,20 @@ public class SmelterEnchant extends AbstractEnchantmentData implements ChanceDat
FurnaceRecipe recipe = this.recipes.stream().filter(rec -> rec.getInputChoice().test(drop.getItemStack())).findFirst().orElse(null);
if (recipe == null) return false;
smelts.add(recipe.getResult());
// Copy amount of the origin drop item. Fixes Fortune compatibility and overall original drop amount.
// Hopefully furnaces will not require multiple input items in the future, otherwise we'll suck here :D
int amount = drop.getItemStack().getAmount();
ItemStack result = new ItemStack(recipe.getResult());
result.setAmount(amount);
smelts.add(result);
return true;
});
if (smelts.isEmpty()) return false;
smelts.forEach(itemStack -> this.plugin.populateResource(event, itemStack));
Block block = event.getBlockState().getBlock();
Block block = state.getBlock();
if (this.hasVisualEffects()) {
Location location = LocationUtil.getCenter(block.getLocation(), true);
UniParticle.of(Particle.FLAME).play(location, 0.25, 0.05, 20);

View File

@ -17,6 +17,7 @@ import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentDat
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.Lists;
import java.io.File;
import java.util.HashSet;
@ -76,7 +77,7 @@ public class TunnelEnchant extends AbstractEnchantmentData implements BlockBreak
if (block.getDrops(item).isEmpty()) return false;
final List<Block> lastTwoTargetBlocks = player.getLastTwoTargetBlocks(null, 10);
final List<Block> lastTwoTargetBlocks = player.getLastTwoTargetBlocks(Lists.newSet(Material.AIR, Material.WATER, Material.LAVA), 10);
if (lastTwoTargetBlocks.size() != 2 || !lastTwoTargetBlocks.get(1).getType().isOccluding()) {
return false;
}

View File

@ -6,6 +6,7 @@ import org.bukkit.enchantments.Enchantment;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
@ -44,7 +45,7 @@ public class SoulboundEnchant extends AbstractEnchantmentData implements Generic
return EnchantmentTarget.BREAKABLE;
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onDeath(@NotNull PlayerDeathEvent deathEvent) {
Player player = deathEvent.getEntity();
if (!this.isAvailableToUse(player)) return;

View File

@ -106,6 +106,11 @@ public class ScavengerEnchant extends AbstractEnchantmentData implements ChanceD
}
}
@Override
public void clear() {
this.lootTables.clear();
}
@NotNull
@Override
public ChanceSettings getChanceSettings() {

View File

@ -13,6 +13,7 @@ import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.EnchantsPlugin;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.config.Keys;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
import su.nightexpress.nightcore.manager.AbstractListener;
@ -95,6 +96,10 @@ public class EnchantAnvilListener extends AbstractListener<EnchantsPlugin> {
private boolean handleCombine(@NotNull PrepareAnvilEvent event, @NotNull ItemStack first, @NotNull ItemStack second, @NotNull ItemStack result) {
ItemStack merged = new ItemStack(result.getType().isAir() ? first : result);
if (EnchantUtils.countCustomEnchantments(merged) > Config.CORE_ITEM_ENCHANT_LIMIT.get()) {
event.setResult(null);
return false;
}
Map<EnchantmentData, Integer> chargesMap = new HashMap<>();
EnchantUtils.getCustomEnchantments(result).forEach((data, level) -> {

View File

@ -116,9 +116,20 @@ public class EnchantGenericListener extends AbstractListener<EnchantsPlugin> {
ItemStack result = origin.getResult();
if (!EnchantUtils.isEnchantable(result)) return;
int uses = origin.getUses();
int maxUses = origin.getMaxUses();
boolean expReward = origin.hasExperienceReward();
int villagerExperience = origin.getVillagerExperience();
float priceMultiplier = origin.getPriceMultiplier();
int demand = origin.getDemand();
int specialPrice = origin.getSpecialPrice();
EnchantUtils.updateDisplay(result);
event.setRecipe(origin);
MerchantRecipe recipe = new MerchantRecipe(result, uses, maxUses, expReward, villagerExperience,
priceMultiplier, demand, specialPrice);
recipe.setIngredients(origin.getIngredients());
event.setRecipe(recipe);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)

View File

@ -116,7 +116,7 @@ public class EnchantPopulationListener extends AbstractListener<EnchantsPlugin>
boolean isMythic = Plugins.isLoaded(HookPlugin.MYTHIC_MOBS) && MythicMobsHook.isMythicMob(entity);
boolean doPopulation = Config.getDistributionWaySettings(DistributionWay.MOB_EQUIPMENT).isPresent() && !isMythic;
for (EquipmentSlot slot : EquipmentSlot.values()) {
for (EquipmentSlot slot : EnchantUtils.EQUIPMENT_SLOTS) {
ItemStack item = equipment.getItem(slot);
if (EnchantUtils.isEnchantable(item)) {
if (doPopulation) {

View File

@ -153,12 +153,9 @@ public class EnchantmentsListMenu extends ConfigMenu<EnchantsPlugin> implements
ItemStack currentItem = event.getCurrentItem();
if (currentItem == null) return;
int levelHas = PDCUtil.getInt(currentItem, this.keyLevel).orElse(0);
if (levelHas == 0) {
levelHas = enchantmentData.getMinLevel();
}
int levelHas = PDCUtil.getInt(currentItem, this.keyLevel).orElse(1);
if (++levelHas > enchantmentData.getMaxLevel()) {
levelHas = enchantmentData.getMinLevel();
levelHas = 1;
}
currentItem = this.getEnchantIcon(enchantmentData, levelHas);
PDCUtil.set(currentItem, this.keyLevel, levelHas);

View File

@ -68,7 +68,10 @@ public class EnchantRegistry extends SimpleManager<EnchantsPlugin> {
// Prevent to register enchantments during the runtime.
if (this.isLocked) {
BY_ID.values().forEach(this::load);
getRegistered().forEach(data -> {
data.clear();
this.load(data);
});
return;
}
@ -165,13 +168,14 @@ public class EnchantRegistry extends SimpleManager<EnchantsPlugin> {
this.register(RestoreEnchant.ID, file -> new RestoreEnchant(plugin, file));
this.plugin.getEnchantNMS().freezeRegistry();
this.plugin.info("Enchantments Registered: " + EnchantRegistry.getRegistered().size());
this.plugin.info("Enchantments Registered: " + BY_ID.size());
this.isLocked = true;
}
@Override
protected void onShutdown() {
if (!isLocked) {
getRegistered().forEach(EnchantmentData::clear);
ENCHANTS_MAP.clear();
}
}
@ -231,8 +235,8 @@ public class EnchantRegistry extends SimpleManager<EnchantsPlugin> {
this.plugin.info("Registered enchantment: " + enchantmentData.getId());
}
private void load(@NotNull EnchantmentData enchant) {
enchant.load();
private void load(@NotNull EnchantmentData enchantmentData) {
enchantmentData.load();
}
@NotNull
@ -278,6 +282,6 @@ public class EnchantRegistry extends SimpleManager<EnchantsPlugin> {
@NotNull
public static Collection<EnchantmentData> getRegistered() {
return BY_ID.values();
return new HashSet<>(BY_ID.values());
}
}

View File

@ -302,7 +302,7 @@ public class DataGathers {
@NotNull
@Override
public EquipmentSlot[] getEnchantSlots(@NotNull EntityDeathEvent event) {
return EquipmentSlot.values();
return EnchantUtils.EQUIPMENT_SLOTS;
}
@Override
@ -327,7 +327,7 @@ public class DataGathers {
@NotNull
@Override
public EquipmentSlot[] getEnchantSlots(@NotNull EntityResurrectEvent event) {
return EquipmentSlot.values();
return EnchantUtils.EQUIPMENT_SLOTS;
}
@Override

View File

@ -30,6 +30,7 @@ import java.util.stream.Stream;
public class EnchantUtils {
public static final EquipmentSlot[] EQUIPMENT_SLOTS = {EquipmentSlot.HAND, EquipmentSlot.OFF_HAND, EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
private static final Map<UUID, EnchantedProjectile> ENCHANTED_PROJECTILE_MAP = new ConcurrentHashMap<>();
private static boolean busyBreak = false;
@ -241,6 +242,10 @@ public class EnchantUtils {
return getLevel(item, enchantment) > 0;
}
public static boolean hasMaximumEnchants(@NotNull ItemStack item) {
return countCustomEnchantments(item) >= Config.CORE_ITEM_ENCHANT_LIMIT.get();
}
public static int getLevel(@NotNull ItemStack item, @NotNull Enchantment enchant) {
return getEnchantments(item).getOrDefault(enchant, 0);
}
@ -289,7 +294,7 @@ public class EnchantUtils {
@NotNull
public static Map<EquipmentSlot, ItemStack> getEnchantedEquipment(@NotNull LivingEntity entity) {
return getEnchantedEquipment(entity, EquipmentSlot.values());
return getEnchantedEquipment(entity, EQUIPMENT_SLOTS);
}
@NotNull
@ -317,7 +322,7 @@ public class EnchantUtils {
@NotNull
public static <T extends EnchantmentData> Map<ItemStack, Map<T, Integer>> getEquipped(@NotNull LivingEntity entity,
@NotNull Class<T> clazz) {
return getEquipped(entity, clazz, EquipmentSlot.values());
return getEquipped(entity, clazz, EQUIPMENT_SLOTS);
}
@NotNull

View File

@ -3,9 +3,7 @@ package su.nightexpress.excellentenchants.hook.impl;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.*;
import org.bukkit.GameMode;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
@ -29,6 +27,15 @@ public class ProtocolHook {
if (isRegistered) return;
ProtocolManager manager = ProtocolLibrary.getProtocolManager();
// Not worked :(
manager.addPacketListener(new PacketAdapter(plugin, PacketType.Login.Server.SUCCESS) {
@Override
public void onPacketSending(PacketEvent event) {
PacketContainer packet = event.getPacket();
packet.getBooleans().write(0, false);
}
});
manager.addPacketListener(new PacketAdapter(plugin, PacketType.Play.Server.SET_SLOT) {
@Override
public void onPacketSending(PacketEvent event) {

View File

@ -1,13 +1,72 @@
# Tranlsated by @qsefthuopq
# Last updated:2021-03-15
Command:
List:
Desc: '自定义附魔列表.'
Usage: '[player]'
DoneOthers: <light_gray>为玩家<light_yellow>%player_name%</light_yellow>打开GUI.</light_gray>
GetFuel:
Desc: '获得充能物品.'
Usage: <enchant> [amount]
Done: <light_gray>你获得了<light_yellow>x%amount% %name%</light_yellow>.</light_gray>
Enchant:
Usage: <附魔名> <等级>
Desc: 附魔你手中的物品。
Done: '&a附魔成功'
Usage: <enchant> <level> [player] [slot]
Desc: '附魔手上的物品.'
Done:
Self: <light_gray><light_yellow>%item%</light_yellow>的附魔是<light_yellow>%enchant% %level%</light_yellow>!</light_gray>
Others: <light_gray><light_yellow>%player_display_name%</light_yellow>的<light_yellow>%item%</light_yellow>的附魔是<light_yellow>%enchant% %level%</light_yellow>!</light_gray>
Error:
NoItem: <red>没有要附魔的物品!</red>
Book:
Usage: <玩家> <附魔名> <等级>
Desc: 给予自定义附魔书。
Done: 已给予&6%player%&6%enchant%&7附魔书。
Usage: <player> <enchant> <level>
Desc: '给予自定义附魔书.'
Done: <light_gray>将<light_yellow>%enchant%</light_yellow>附魔书给予<light_yellow>%player_display_name%</light_yellow>.</light_gray>
RarityBook:
Usage: <player> <tier> <level>
Desc: '给予指定品质的附魔书'
Done: <light_gray>将<light_yellow>%name%</light_yellow>附魔书给予<light_yellow>%player_display_name%</light_yellow>.</light_gray>
Error:
NoEnchant: '&c没有这种附魔'
InvalidEnchantment: <red>无效的参数.</red>
InvalidRarity: <red>无效的品质类型!</red>
ItemCategory:
HELMET: '头盔'
CHESTPLATE: '胸甲'
LEGGINGS: '护腿'
BOOTS: '靴子'
ELYTRA: '鞘翅'
SWORD: '剑'
TRIDENT: '三叉戟'
AXE: '斧头'
BOW: '弓'
CROSSBOW: '弩'
HOE: '锄头'
PICKAXE: '镐子'
SHOVEL: '铲子'
FISHING_ROD: '钓鱼竿'
SHIELD: '盾牌'
TOOL: '工具'
EnchantmentTarget:
ALL: '全部'
ARMOR: '装备'
ARMOR_FEET: '靴子'
ARMOR_LEGS: '护腿'
ARMOR_TORSO: '胸甲'
ARMOR_HEAD: '头盔'
WEAPON: '武器'
TOOL: '工具'
BOW: '弓'
FISHING_ROD: '钓鱼竿'
BREAKABLE: '耐久'
WEARABLE: '穿戴'
TRIDENT: '三叉戟'
CROSSBOW: '弩'
VANISHABLE: '隐身'
DistributionWay:
ENCHANTING: '附魔'
VILLAGER: '村民'
LOOT_GENERATION: '战利品'
FISHING: '钓鱼'
MOB_EQUIPMENT: '怪物装备'
Rarity:
COMMON: '<white>普通</white>'
UNCOMMON: '<light_green>勇者</light_green>'
RARE: '<purple>史诗</purple>'
VERY_RARE: '<red>神话</red>'

79
MC_1_20_6/pom.xml Normal file
View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>ExcellentEnchants</artifactId>
<version>4.0.5</version>
</parent>
<artifactId>MC_1_20_6</artifactId>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.20.6-R0.1-SNAPSHOT</version>
<classifier>remapped-mojang</classifier>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>API</artifactId>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>NMS</artifactId>
<version>4.0.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>net.md-5</groupId>
<artifactId>specialsource-maven-plugin</artifactId>
<version>2.0.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>remap</goal>
</goals>
<id>remap-obf</id>
<configuration>
<srgIn>org.spigotmc:minecraft-server:1.20.6-R0.1-SNAPSHOT:txt:maps-mojang</srgIn>
<reverse>true</reverse>
<remappedDependencies>org.spigotmc:spigot:1.20.6-R0.1-SNAPSHOT:jar:remapped-mojang</remappedDependencies>
<remappedArtifactAttached>true</remappedArtifactAttached>
<remappedClassifierName>remapped-obf</remappedClassifierName>
</configuration>
</execution>
<execution>
<phase>package</phase>
<goals>
<goal>remap</goal>
</goals>
<id>remap-spigot</id>
<configuration>
<inputFile>${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar</inputFile>
<srgIn>org.spigotmc:minecraft-server:1.20.6-R0.1-SNAPSHOT:csrg:maps-spigot</srgIn>
<remappedDependencies>org.spigotmc:spigot:1.20.6-R0.1-SNAPSHOT:jar:remapped-obf</remappedDependencies>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,148 @@
package su.nightexpress.excellentenchants;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.ItemTags;
import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.Enchantment;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.v1_20_R4.CraftEquipmentSlot;
import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_20_R4.util.CraftNamespacedKey;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.EnchantingBridge;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.distribution.VanillaOptions;
public class CustomEnchantment extends Enchantment {
private final EnchantmentData enchantmentData;
private VanillaOptions vanillaOptions;
@NotNull
public static CustomEnchantment from(@NotNull EnchantmentData enchantmentData) {
TagKey<Item> category = nmsCategory(enchantmentData);
int weight = enchantmentData.getRarity().getWeight();
int maxLevel = enchantmentData.getMaxLevel();
Cost minCost = new Cost(enchantmentData.getMinCost().base(), enchantmentData.getMinCost().perLevel());
Cost maxCost = new Cost(enchantmentData.getMaxCost().base(), enchantmentData.getMaxCost().perLevel());
int anvilCost = enchantmentData.getAnvilCost();
EquipmentSlot[] slots = nmsSlots(enchantmentData);
EnchantmentDefinition definition = Enchantment.definition(category, weight, maxLevel, minCost, maxCost, anvilCost, slots);
return new CustomEnchantment(enchantmentData, definition);
}
public CustomEnchantment(@NotNull EnchantmentData enchantmentData, @NotNull EnchantmentDefinition definition) {
super(definition);
this.enchantmentData = enchantmentData;
if (enchantmentData.getDistributionOptions() instanceof VanillaOptions options) {
this.vanillaOptions = options;
}
}
@Override
protected boolean checkCompatibility(Enchantment other) {
ResourceLocation location = BuiltInRegistries.ENCHANTMENT.getKey(other);
if (location == null) return false;
NamespacedKey key = CraftNamespacedKey.fromMinecraft(location);
String id = key.getKey();
// Expensive probably.
//org.bukkit.enchantments.Enchantment bukkit = CraftEnchantment.minecraftToBukkit(other);
//String id = bukkit.getKey().getKey();
return !this.enchantmentData.getConflicts().contains(id);
}
@Override
public boolean canEnchant(ItemStack item) {
if (!super.canEnchant(item)) return false;
return this.canEnchant(CraftItemStack.asBukkitCopy(item));
}
public boolean canEnchant(@NotNull org.bukkit.inventory.ItemStack bukkitItem) {
if (!this.enchantmentData.checkEnchantLimit(bukkitItem)) return false;
if (!this.enchantmentData.hasItemCategory()) {
if (this.enchantmentData.checkEnchantCategory(bukkitItem)) return true;
}
return this.enchantmentData.checkItemCategory(bukkitItem);
}
@Override
public boolean isTreasureOnly() {
return this.enchantmentData.isTreasure() || this.isCurse();
}
@Override
public boolean isCurse() {
return this.enchantmentData.isCurse();
}
@Override
public boolean isTradeable() {
return this.vanillaOptions != null && this.vanillaOptions.isTradeable();
}
@Override
public boolean isDiscoverable() {
org.bukkit.inventory.ItemStack bukkitItem = EnchantingBridge.getEnchantingItem();
if (bukkitItem != null && !this.canEnchant(bukkitItem)) {
return false;
}
return this.vanillaOptions != null && this.vanillaOptions.isDiscoverable();
}
public static Rarity nmsRarity(@NotNull EnchantmentData data) {
return switch (data.getRarity()) {
case RARE -> Rarity.RARE;
case COMMON -> Rarity.COMMON;
case UNCOMMON -> Rarity.UNCOMMON;
case VERY_RARE -> Rarity.VERY_RARE;
};
}
@NotNull
public static TagKey<Item> nmsCategory(@NotNull EnchantmentData data) {
return switch (data.getCategory()) {
case WEAPON -> ItemTags.WEAPON_ENCHANTABLE;
case TOOL -> ItemTags.MINING_ENCHANTABLE;
case ARMOR -> ItemTags.ARMOR_ENCHANTABLE;
case BOW -> ItemTags.BOW_ENCHANTABLE;
case TRIDENT -> ItemTags.TRIDENT_ENCHANTABLE;
case CROSSBOW -> ItemTags.CROSSBOW_ENCHANTABLE;
case WEARABLE -> ItemTags.EQUIPPABLE_ENCHANTABLE;
case BREAKABLE -> ItemTags.DURABILITY_ENCHANTABLE;
case ARMOR_FEET -> ItemTags.FOOT_ARMOR_ENCHANTABLE;
case ARMOR_HEAD -> ItemTags.HEAD_ARMOR_ENCHANTABLE;
case ARMOR_LEGS -> ItemTags.LEG_ARMOR_ENCHANTABLE;
case ARMOR_TORSO -> ItemTags.CHEST_ARMOR_ENCHANTABLE;
case VANISHABLE -> ItemTags.VANISHING_ENCHANTABLE;
case FISHING_ROD -> ItemTags.FISHING_ENCHANTABLE;
default -> throw new IllegalStateException("Unexpected value: " + data.getCategory());
};
}
public static EquipmentSlot[] nmsSlots(@NotNull EnchantmentData data) {
org.bukkit.inventory.EquipmentSlot[] slots = data.getSlots();
EquipmentSlot[] nmsSlots = new EquipmentSlot[slots.length];
for (int index = 0; index < nmsSlots.length; index++) {
org.bukkit.inventory.EquipmentSlot bukkitSlot = slots[index];
nmsSlots[index] = CraftEquipmentSlot.getNMS(bukkitSlot);
}
return nmsSlots;
}
}

View File

@ -0,0 +1,233 @@
package su.nightexpress.excellentenchants;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.protocol.game.ClientboundAnimatePacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.Container;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.projectile.FishingHook;
import net.minecraft.world.inventory.EnchantmentMenu;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.enchantment.EnchantmentInstance;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.LiquidBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.CollisionContext;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_20_R4.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R4.block.CraftBlock;
import org.bukkit.craftbukkit.v1_20_R4.block.CraftBlockType;
import org.bukkit.craftbukkit.v1_20_R4.enchantments.CraftEnchantment;
import org.bukkit.craftbukkit.v1_20_R4.entity.CraftFishHook;
import org.bukkit.craftbukkit.v1_20_R4.entity.CraftLivingEntity;
import org.bukkit.craftbukkit.v1_20_R4.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_20_R4.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftInventory;
import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_20_R4.util.CraftNamespacedKey;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.Item;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
import su.nightexpress.excellentenchants.nms.EnchantNMS;
import su.nightexpress.nightcore.util.BukkitThing;
import su.nightexpress.nightcore.util.Reflex;
import su.nightexpress.nightcore.util.random.Rnd;
import java.lang.reflect.Method;
import java.util.*;
public class Internal1_20_6 implements EnchantNMS {
@Override
public void unfreezeRegistry() {
Reflex.setFieldValue(BuiltInRegistries.ENCHANTMENT, "l", false); // MappedRegistry#frozen
Reflex.setFieldValue(BuiltInRegistries.ENCHANTMENT, "m", new IdentityHashMap<>()); // MappedRegistry#unregisteredIntrusiveHolders
}
@Override
public void freezeRegistry() {
BuiltInRegistries.ENCHANTMENT.freeze();
}
public void registerEnchantment(@NotNull EnchantmentData data) {
CustomEnchantment enchantment = CustomEnchantment.from(data);
Registry.register(BuiltInRegistries.ENCHANTMENT, data.getId(), enchantment);
Enchantment bukkitEnchant = CraftEnchantment.minecraftToBukkit(enchantment);
data.setEnchantment(bukkitEnchant);
}
private static final Method GET_ENCHANTS_LIST = Reflex.getMethod(EnchantmentMenu.class, "a", net.minecraft.world.item.ItemStack.class, Integer.TYPE, Integer.TYPE);
@SuppressWarnings("unchecked")
@NotNull
@Override
public Map<Integer, Map<Enchantment, Integer>> getEnchantLists(@NotNull Inventory inventory, @NotNull ItemStack bukkitItem) {
Map<Integer, Map<Enchantment, Integer>> map = new HashMap<>();
// Returns SimpleContainer class assigned to 'enchantSlots' field.
Container container = ((CraftInventory) inventory).getInventory();
// Get parent (real EnchantmentMenu) object from SimpleContainer obtained above.
EnchantmentMenu enchantmentMenu = (EnchantmentMenu) Reflex.getFieldValue(container, "this$0");
net.minecraft.world.item.ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);
for (int button = 0; button < 3; button++) {
int cost = enchantmentMenu.costs[button];
List<EnchantmentInstance> list = (List<EnchantmentInstance>) Reflex.invokeMethod(GET_ENCHANTS_LIST, enchantmentMenu, itemStack, button, cost);
Map<Enchantment, Integer> enchantments = new HashMap<>();
if (list != null && !list.isEmpty()) {
EnchantmentInstance random = Rnd.get(list);
enchantmentMenu.enchantClue[button] = BuiltInRegistries.ENCHANTMENT.getId(random.enchantment);
enchantmentMenu.levelClue[button] = random.level;
for (EnchantmentInstance instance : list) {
ResourceLocation location = BuiltInRegistries.ENCHANTMENT.getKey(instance.enchantment);
if (location == null) continue;
enchantments.put(BukkitThing.getEnchantment(CraftNamespacedKey.fromMinecraft(location).getKey()), instance.level);
}
}
map.put(button, enchantments);
}
return map;
}
@Override
public void sendAttackPacket(@NotNull Player player, int id) {
CraftPlayer craftPlayer = (CraftPlayer) player;
ServerPlayer entity = craftPlayer.getHandle();
ClientboundAnimatePacket packet = new ClientboundAnimatePacket(entity, id);
craftPlayer.getHandle().connection.send(packet);
player.spigot().sendMessage();
}
/*@NotNull
public ItemStack setItemLore(@NotNull ItemStack item, @NotNull List<String> lore) {
CraftItemStack craftItem = ensureCraftItemStack(item);
net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(craftItem);
CompoundTag tag = nmsItem.getTag() == null ? new CompoundTag() : nmsItem.getTag();
if (!tag.contains(net.minecraft.world.item.ItemStack.TAG_DISPLAY)) {
tag.put(net.minecraft.world.item.ItemStack.TAG_DISPLAY, new CompoundTag());
}
CompoundTag displayTag = tag.getCompound(net.minecraft.world.item.ItemStack.TAG_DISPLAY);
ListTag loreTag = new ListTag();
for (int index = 0; index < lore.size(); index++) {
String text = lore.get(index);
String json = ComponentSerializer.toString(NightMessage.asComponent(text));
loreTag.add(index, StringTag.valueOf(json));
}
displayTag.put(net.minecraft.world.item.ItemStack.TAG_LORE, loreTag);
return CraftItemStack.asBukkitCopy(nmsItem);
}*/
@NotNull
private static CraftItemStack ensureCraftItemStack(ItemStack item) {
return item instanceof CraftItemStack craftItem ? craftItem : CraftItemStack.asCraftCopy(item);
}
@Override
public void retrieveHook(@NotNull FishHook hook, @NotNull ItemStack item, @NotNull EquipmentSlot slot) {
CraftFishHook craftFishHook = (CraftFishHook) hook;
FishingHook handle = craftFishHook.getHandle();
net.minecraft.world.entity.player.Player owner = handle.getPlayerOwner();
if (owner == null) return;
int result = handle.retrieve(CraftItemStack.asNMSCopy(item));
net.minecraft.world.entity.EquipmentSlot hand = slot == EquipmentSlot.HAND ? net.minecraft.world.entity.EquipmentSlot.MAINHAND : net.minecraft.world.entity.EquipmentSlot.OFFHAND;
net.minecraft.world.item.ItemStack itemStack = owner.getItemBySlot(hand);
if (itemStack == null) return;
itemStack.hurtAndBreak(result, handle.getPlayerOwner(), hand);
}
@NotNull
@Override
public Material getItemBlockVariant(@NotNull Material material) {
ItemStack itemStack = new ItemStack(material);
net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
if (nmsStack.getItem() instanceof BlockItem blockItem) {
return CraftBlockType.minecraftToBukkit(blockItem.getBlock());
}
return material;
}
@Override
@NotNull
public Set<Block> handleFlameWalker(@NotNull LivingEntity bukkitEntity, @NotNull Location location, int level) {
Entity entity = ((CraftLivingEntity) bukkitEntity).getHandle();
BlockPos pos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ());
ServerLevel world = ((CraftWorld) bukkitEntity.getWorld()).getHandle();
int radius = Math.min(16, 2 + level);
BlockState bStone = Blocks.MAGMA_BLOCK.defaultBlockState();
BlockPos.MutableBlockPos posAbove = new BlockPos.MutableBlockPos();
Set<Block> blocks = new HashSet<>();
for (BlockPos posNear : BlockPos.betweenClosed(pos.offset(-radius, -1, -radius), pos.offset(radius, -1, radius))) {
if (!posNear.closerThan(entity.blockPosition(), radius)) continue;
posAbove.set(posNear.getX(), posNear.getY() + 1, posNear.getZ());
BlockState bLavaAbove = world.getBlockState(posAbove);
BlockState bLava = world.getBlockState(posNear);
if (!bLavaAbove.isAir()) continue;
if (!bLava.getBlock().equals(Blocks.LAVA)) continue;
if (bLava.getValue(LiquidBlock.LEVEL) != 0) continue;
if (!bStone.canSurvive(world, posNear)) continue;
if (!world.isUnobstructed(bStone, posNear, CollisionContext.empty())) continue;
if (!CraftEventFactory.handleBlockFormEvent(world, posNear, bStone, entity)) continue;
//world.scheduleTick(posNear, Blocks.STONE, Rnd.get(60, 120));
Location bukkitLoc = new Location(world.getWorld(), posNear.getX(), posNear.getY(), posNear.getZ());
blocks.add(bukkitLoc.getBlock());
}
return blocks;
}
@NotNull
public Item popResource(@NotNull Block block, @NotNull ItemStack item) {
Level world = ((CraftWorld)block.getWorld()).getHandle();
BlockPos pos = ((CraftBlock)block).getPosition();
net.minecraft.world.item.ItemStack itemstack = CraftItemStack.asNMSCopy(item);
float yMod = EntityType.ITEM.getHeight() / 2.0F;
double x = (pos.getX() + 0.5F) + Mth.nextDouble(world.random, -0.25D, 0.25D);
double y = (pos.getY() + 0.5F) + Mth.nextDouble(world.random, -0.25D, 0.25D) - yMod;
double z = (pos.getZ() + 0.5F) + Mth.nextDouble(world.random, -0.25D, 0.25D);
ItemEntity itemEntity = new ItemEntity(world, x, y, z, itemstack);
itemEntity.setDefaultPickUpDelay();
return (Item) itemEntity.getBukkitEntity();
}
}

View File

@ -5,15 +5,15 @@
<parent>
<artifactId>ExcellentEnchants</artifactId>
<groupId>su.nightexpress.excellentenchants</groupId>
<version>4.0.4</version>
<version>4.0.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>NMS</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
@ -33,7 +33,7 @@
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>API</artifactId>
<version>4.0.4</version>
<version>4.0.5</version>
</dependency>
</dependencies>

View File

@ -5,15 +5,15 @@
<parent>
<artifactId>ExcellentEnchants</artifactId>
<groupId>su.nightexpress.excellentenchants</groupId>
<version>4.0.4</version>
<version>4.0.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>V1_19_R3</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
@ -27,7 +27,7 @@
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>NMS</artifactId>
<version>4.0.4</version>
<version>4.0.5</version>
</dependency>
</dependencies>
@ -36,7 +36,7 @@
<plugin>
<groupId>net.md-5</groupId>
<artifactId>specialsource-maven-plugin</artifactId>
<version>1.2.4</version>
<version>2.0.3</version>
<executions>
<execution>
<phase>package</phase>

View File

@ -30,11 +30,6 @@ public class CustomEnchantment extends Enchantment {
}
}
@Override
public int getMinLevel() {
return this.enchantmentData.getMinLevel();
}
@Override
public int getMaxLevel() {
return this.enchantmentData.getMaxLevel();

View File

@ -5,15 +5,15 @@
<parent>
<artifactId>ExcellentEnchants</artifactId>
<groupId>su.nightexpress.excellentenchants</groupId>
<version>4.0.4</version>
<version>4.0.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>V1_20_R1</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
@ -27,7 +27,7 @@
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>NMS</artifactId>
<version>4.0.4</version>
<version>4.0.5</version>
</dependency>
</dependencies>
@ -36,7 +36,7 @@
<plugin>
<groupId>net.md-5</groupId>
<artifactId>specialsource-maven-plugin</artifactId>
<version>1.2.4</version>
<version>2.0.3</version>
<executions>
<execution>
<phase>package</phase>

View File

@ -30,11 +30,6 @@ public class CustomEnchantment extends Enchantment {
}
}
@Override
public int getMinLevel() {
return this.enchantmentData.getMinLevel();
}
@Override
public int getMaxLevel() {
return this.enchantmentData.getMaxLevel();

View File

@ -5,15 +5,15 @@
<parent>
<artifactId>ExcellentEnchants</artifactId>
<groupId>su.nightexpress.excellentenchants</groupId>
<version>4.0.4</version>
<version>4.0.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>V1_20_R2</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
@ -27,7 +27,7 @@
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>NMS</artifactId>
<version>4.0.4</version>
<version>4.0.5</version>
</dependency>
</dependencies>
@ -36,7 +36,7 @@
<plugin>
<groupId>net.md-5</groupId>
<artifactId>specialsource-maven-plugin</artifactId>
<version>1.2.4</version>
<version>2.0.3</version>
<executions>
<execution>
<phase>package</phase>

View File

@ -30,11 +30,6 @@ public class CustomEnchantment extends Enchantment {
}
}
@Override
public int getMinLevel() {
return this.enchantmentData.getMinLevel();
}
@Override
public int getMaxLevel() {
return this.enchantmentData.getMaxLevel();

View File

@ -5,15 +5,15 @@
<parent>
<artifactId>ExcellentEnchants</artifactId>
<groupId>su.nightexpress.excellentenchants</groupId>
<version>4.0.4</version>
<version>4.0.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>V1_20_R3</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
@ -27,12 +27,12 @@
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>API</artifactId>
<version>4.0.4</version>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>NMS</artifactId>
<version>4.0.4</version>
<version>4.0.5</version>
</dependency>
</dependencies>
@ -41,7 +41,7 @@
<plugin>
<groupId>net.md-5</groupId>
<artifactId>specialsource-maven-plugin</artifactId>
<version>1.2.4</version>
<version>2.0.3</version>
<executions>
<execution>
<phase>package</phase>

View File

@ -30,11 +30,6 @@ public class CustomEnchantment extends Enchantment {
}
}
@Override
public int getMinLevel() {
return this.enchantmentData.getMinLevel();
}
@Override
public int getMaxLevel() {
return this.enchantmentData.getMaxLevel();

View File

@ -9,12 +9,14 @@ import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.Container;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.projectile.FishingHook;
import net.minecraft.world.inventory.EnchantmentMenu;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.enchantment.EnchantmentInstance;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
@ -121,13 +123,10 @@ public class V1_20_R3 implements EnchantNMS {
ServerPlayer entity = craftPlayer.getHandle();
ClientboundAnimatePacket packet = new ClientboundAnimatePacket(entity, id);
craftPlayer.getHandle().connection.send(packet);
player.spigot().sendMessage();
}
/*public ItemStack setItemLore(@NotNull ItemStack item, @NotNull List<String> lore) {
lore.add("<translate>enchantment.level.5</translate>");
/*@NotNull
public ItemStack setItemLore(@NotNull ItemStack item, @NotNull List<String> lore) {
CraftItemStack craftItem = ensureCraftItemStack(item);
net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(craftItem);
@ -140,24 +139,16 @@ public class V1_20_R3 implements EnchantNMS {
ListTag loreTag = new ListTag();
for (int index = 0; index < lore.size(); index++) {
String text = lore.get(index);
System.out.println("text = " + text);
String json = ComponentSerializer.toString(NightMessage.create(text).parseIfAbsent());
System.out.println("json = " + json);
Component component = CraftChatMessage.fromJSON(json);
System.out.println("component = " + component);
String fromComponent = CraftChatMessage.toJSON(component);
System.out.println("fromComponent = " + fromComponent);
loreTag.add(index, StringTag.valueOf(fromComponent));
String json = ComponentSerializer.toString(NightMessage.asComponent(text));
loreTag.add(index, StringTag.valueOf(json));
}
displayTag.put(net.minecraft.world.item.ItemStack.TAG_LORE, loreTag);
return CraftItemStack.asBukkitCopy(nmsItem);
}*/
private CraftItemStack ensureCraftItemStack(ItemStack item) {
@NotNull
private static CraftItemStack ensureCraftItemStack(ItemStack item) {
return item instanceof CraftItemStack craftItem ? craftItem : CraftItemStack.asCraftCopy(item);
}
@ -169,16 +160,8 @@ public class V1_20_R3 implements EnchantNMS {
net.minecraft.world.entity.player.Player owner = handle.getPlayerOwner();
if (owner == null) return;
int result = handle.retrieve(CraftItemStack.asNMSCopy(item));
net.minecraft.world.entity.EquipmentSlot hand = slot == EquipmentSlot.HAND ? net.minecraft.world.entity.EquipmentSlot.MAINHAND : net.minecraft.world.entity.EquipmentSlot.OFFHAND;
net.minecraft.world.item.ItemStack itemStack = owner.getItemBySlot(hand);
if (itemStack == null) return;
itemStack.hurtAndBreak(result, handle.getPlayerOwner(), player -> {
player.broadcastBreakEvent(hand);
});
InteractionHand hand = slot == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
Items.FISHING_ROD.use(owner.level(), owner, hand);
}
/*@Override

11
pom.xml
View File

@ -7,20 +7,21 @@
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>ExcellentEnchants</artifactId>
<packaging>pom</packaging>
<version>4.0.4</version>
<version>4.0.5</version>
<modules>
<module>API</module>
<module>Core</module>
<module>NMS</module>
<module>V1_19_R3</module>
<module>V1_20_R1</module>
<module>V1_20_R2</module>
<module>V1_20_R3</module>
<module>API</module>
<module>MC_1_20_6</module>
</modules>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
@ -28,7 +29,7 @@
<dependency>
<groupId>su.nightexpress.nightcore</groupId>
<artifactId>nightcore</artifactId>
<version>2.5.1</version>
<version>2.6.1</version>
</dependency>
</dependencies>