This commit is contained in:
nulli0n 2024-12-14 23:49:34 +05:00
parent b3a2e62c42
commit 01c497aaa4
45 changed files with 1215 additions and 598 deletions

4
.gitignore vendored
View File

@ -10,4 +10,6 @@
/MC_1_21/target/
/MC_1_21/pom.xml.versionsBackup
/MC_1_21_3/target/
/MC_1_21_3/pom.xml.versionsBackup
/MC_1_21_3/pom.xml.versionsBackup
/MC_1_21_4/target/
/MC_1_21_4/pom.xml.versionsBackup

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>ExcellentEnchants</artifactId>
<groupId>su.nightexpress.excellentenchants</groupId>
<version>4.3.1</version>
<version>4.3.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -8,18 +8,17 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.meta.MetaHolder;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.placeholder.PlaceholderMap;
import su.nightexpress.nightcore.util.random.Rnd;
import java.util.List;
import java.util.function.UnaryOperator;
public interface CustomEnchantment extends MetaHolder {
default void clear() {
// default void clear() {
//
// }
}
@NotNull PlaceholderMap getPlaceholders(int level);
@NotNull UnaryOperator<String> replacePlaceholders(int level);
@NotNull FileConfig getConfig();
@ -84,7 +83,4 @@ public interface CustomEnchantment extends MetaHolder {
void fuelCharges(@NotNull ItemStack item, int level);
void consumeCharges(@NotNull ItemStack item, int level);
@Deprecated
void consumeChargesNoUpdate(@NotNull ItemStack item, int level);
}

View File

@ -0,0 +1,46 @@
package su.nightexpress.excellentenchants.api.enchantment;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.nightcore.util.TimeUtil;
import su.nightexpress.nightcore.util.random.Rnd;
public class DecayBlock {
private final Location location;
private final long createDate;
private final long decayDate;
private final int sourceId;
public DecayBlock(@NotNull Location location, double seconds) {
this.location = location;
this.createDate = System.currentTimeMillis();
this.decayDate = TimeUtil.createFutureTimestamp(seconds);
this.sourceId = Rnd.nextInt(10000);
}
public float getProgress() {
//long start = booster.getCreationDate();
float end = this.decayDate - this.createDate;
float now = System.currentTimeMillis() - this.createDate;
return /*1F - */now / end;
}
public boolean isExpired() {
return TimeUtil.isPassed(this.decayDate);
}
@NotNull
public Location getLocation() {
return this.location;
}
public int getSourceId() {
return this.sourceId;
}
public long getDecayDate() {
return this.decayDate;
}
}

View File

@ -18,13 +18,11 @@ public class ItemsCategory {
private final Supplier<Set<Material>> supplier;
private final EquipmentSlot[] slots;
// private final EnchantmentTarget target;
private final String localized;
public ItemsCategory(@NotNull Supplier<Set<Material>> supplier, EquipmentSlot[] slots/*, @Nullable EnchantmentTarget target*/, @Nullable String localized) {
public ItemsCategory(@NotNull Supplier<Set<Material>> supplier, EquipmentSlot[] slots, @Nullable String localized) {
this.supplier = supplier;
this.slots = slots;
// this.target = target;
this.localized = localized;
}
@ -62,13 +60,6 @@ public class ItemsCategory {
return slots;
}
// /**
// * Only for compatibility reasons with versions < 1.21
// */
// public EnchantmentTarget getTarget() {
// return target;
// }
public String getLocalized() {
return localized;
}
@ -77,7 +68,6 @@ public class ItemsCategory {
private Supplier<Set<Material>> supplier;
private EquipmentSlot[] slots;
// private EnchantmentTarget target;
private String localized;
public Builder() {
@ -87,7 +77,7 @@ public class ItemsCategory {
@NotNull
public ItemsCategory build() {
return new ItemsCategory(this.supplier, this.slots, /*this.target,*/ this.localized);
return new ItemsCategory(this.supplier, this.slots, this.localized);
}
@NotNull
@ -102,13 +92,6 @@ public class ItemsCategory {
return this;
}
// @NotNull
// @Deprecated
// public Builder target(EnchantmentTarget target) {
// this.target = target;
// return this;
// }
@NotNull
public Builder localized(@NotNull LangString localized) {
return this.localized(localized.getString());

View File

@ -15,5 +15,4 @@ public enum TradeType {
SWAMP_SPECIAL,
TAIGA_COMMON,
TAIGA_SPECIAL
;
}

View File

@ -1,22 +1,16 @@
package su.nightexpress.excellentenchants.api.enchantment.bridge;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.nightcore.util.Pair;
import su.nightexpress.nightcore.util.random.Rnd;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public interface FlameWalker {
Map<Location, Pair<Long, Integer>> MAGMA_BLOCKS = new ConcurrentHashMap<>();
void removeBlocks();
static void addBlock(@NotNull Block block, double seconds) {
MAGMA_BLOCKS.put(block.getLocation(), Pair.of(System.currentTimeMillis() + (long) seconds * 1000L, Rnd.get(1000)));
}
void tickBlocks();
void addBlock(@NotNull Block block, int level);
@NotNull Modifier getRadius();

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>ExcellentEnchants</artifactId>
<groupId>su.nightexpress.excellentenchants</groupId>
<version>4.3.1</version>
<version>4.3.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -89,25 +89,31 @@
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>API</artifactId>
<version>4.3.1</version>
<version>4.3.2</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>NMS</artifactId>
<version>4.3.1</version>
<version>4.3.2</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>MC_1_21_4</artifactId>
<version>4.3.2</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>MC_1_21_3</artifactId>
<version>4.3.1</version>
<version>4.3.2</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>MC_1_21</artifactId>
<version>4.3.1</version>
<version>4.3.2</version>
</dependency>
</dependencies>

View File

@ -17,6 +17,7 @@ import su.nightexpress.excellentenchants.hook.impl.PlaceholderHook;
import su.nightexpress.excellentenchants.hook.impl.ProtocolLibHook;
import su.nightexpress.excellentenchants.nms.EnchantNMS;
import su.nightexpress.excellentenchants.nms.Internal_1_21_3;
import su.nightexpress.excellentenchants.nms.Internal_1_21_4;
import su.nightexpress.excellentenchants.rarity.RarityManager;
import su.nightexpress.excellentenchants.registry.EnchantRegistry;
import su.nightexpress.nightcore.NightPlugin;
@ -79,12 +80,14 @@ public class EnchantsPlugin extends NightPlugin implements ImprovedCommands {
if (this.rarityManager != null) this.rarityManager.shutdown();
this.registry.shutdown();
Keys.clear();
}
private boolean loadInternals() {
this.enchantNMS = switch (Version.getCurrent()) {
case MC_1_21 -> new Internal_1_21(this);
case MC_1_21_3 -> new Internal_1_21_3(this);
case MC_1_21_4 -> new Internal_1_21_4(this);
default -> null;
};

View File

@ -5,10 +5,10 @@ import su.nightexpress.excellentenchants.api.enchantment.meta.ChanceMeta;
import su.nightexpress.excellentenchants.api.enchantment.meta.PeriodMeta;
import su.nightexpress.excellentenchants.api.enchantment.meta.PotionMeta;
import su.nightexpress.excellentenchants.enchantment.impl.GameEnchantment;
import su.nightexpress.excellentenchants.util.EnchantPlaceholders;
import su.nightexpress.nightcore.language.LangAssets;
import su.nightexpress.nightcore.util.ItemUtil;
import su.nightexpress.nightcore.util.NumberUtil;
import su.nightexpress.nightcore.util.placeholder.PlaceholderList;
public class Placeholders extends su.nightexpress.nightcore.util.Placeholders {
@ -53,24 +53,24 @@ public class Placeholders extends su.nightexpress.nightcore.util.Placeholders {
public static final String ENCHANTMENT_CHARGES_RECHARGE_AMOUNT = "%enchantment_charges_recharge_amount%";
public static final String ENCHANTMENT_CHARGES_FUEL_ITEM = "%enchantment_charges_fuel_item%";
public static EnchantPlaceholders forEnchant(@NotNull GameEnchantment enchantment) {
EnchantPlaceholders placeholders = new EnchantPlaceholders();
placeholders
.add(ENCHANTMENT_ID, enchantment::getId)
.add(ENCHANTMENT_NAME, enchantment::getDisplayName)
.add(ENCHANTMENT_DESCRIPTION, () -> String.join("\n", enchantment.getDescription()))
@NotNull
public static PlaceholderList<Integer> forEnchant(@NotNull GameEnchantment enchantment) {
PlaceholderList<Integer> placeholders = PlaceholderList.create(list -> list
.add(ENCHANTMENT_ID, level -> enchantment.getId())
.add(ENCHANTMENT_NAME, level -> enchantment.getDisplayName())
.add(ENCHANTMENT_DESCRIPTION, level -> String.join("\n", enchantment.getDescription()))
//.add(ENCHANTMENT_DESCRIPTION_FORMATTED, () -> String.join("\n", enchantment.getDescriptionFormatted()))
.add(ENCHANTMENT_DESCRIPTION_REPLACED, level -> String.join("\n", enchantment.getDescription(level)))
.add(ENCHANTMENT_LEVEL, NumberUtil::toRoman)
.add(ENCHANTMENT_LEVEL_MIN, () -> String.valueOf(1))
.add(ENCHANTMENT_LEVEL_MAX, () -> String.valueOf(enchantment.getDefinition().getMaxLevel()))
.add(ENCHANTMENT_RARITY, () -> enchantment.getDefinition().getRarity().getName())
.add(ENCHANTMENT_FIT_ITEM_TYPES, () -> enchantment.getDefinition().getSupportedItems().getLocalized())
.add(ENCHANTMENT_LEVEL_MIN, level -> String.valueOf(1))
.add(ENCHANTMENT_LEVEL_MAX, level -> String.valueOf(enchantment.getDefinition().getMaxLevel()))
.add(ENCHANTMENT_RARITY, level -> enchantment.getDefinition().getRarity().getName())
.add(ENCHANTMENT_FIT_ITEM_TYPES, level -> enchantment.getDefinition().getSupportedItems().getLocalized())
.add(ENCHANTMENT_CHARGES_MAX_AMOUNT, level -> NumberUtil.format(enchantment.getCharges().getMaxAmount(level)))
.add(ENCHANTMENT_CHARGES_CONSUME_AMOUNT, level -> NumberUtil.format(enchantment.getCharges().getConsumeAmount(level)))
.add(ENCHANTMENT_CHARGES_RECHARGE_AMOUNT, level -> NumberUtil.format(enchantment.getCharges().getRechargeAmount(level)))
.add(ENCHANTMENT_CHARGES_FUEL_ITEM, () -> ItemUtil.getItemName(enchantment.getCharges().getFuel()));
.add(ENCHANTMENT_CHARGES_FUEL_ITEM, level -> ItemUtil.getItemName(enchantment.getCharges().getFuel()))
);
if (enchantment instanceof ChanceMeta chanceMeta) {
placeholders.add(ENCHANTMENT_CHANCE, level -> NumberUtil.format(chanceMeta.getTriggerChance(level)));

View File

@ -31,7 +31,7 @@ public class BaseCommands {
public static void load(@NotNull EnchantsPlugin plugin) {
ChainedNode rootNode = plugin.getRootNode();
ReloadCommand.inject(plugin, rootNode, Perms.COMMAND_RELOAD);
rootNode.addChildren(ReloadCommand.builder(plugin, Perms.COMMAND_RELOAD));
rootNode.addChildren(DirectNode.builder(plugin, "book")
.description(Lang.COMMAND_BOOK_DESC)
@ -111,10 +111,10 @@ public class BaseCommands {
EnchantUtils.add(item, enchantment, level, true);
Players.addItem(player, item);
Lang.COMMAND_BOOK_DONE.getMessage()
Lang.COMMAND_BOOK_DONE.getMessage().send(context.getSender(), replacer -> replacer
.replace(Placeholders.GENERIC_ENCHANT, EnchantUtils.getLocalized(enchantment))
.replace(Placeholders.forPlayer(player))
.send(context.getSender());
);
return true;
}
@ -138,12 +138,12 @@ public class BaseCommands {
EnchantUtils.add(item, enchantment, level, true);
}
(context.getSender() == player ? Lang.COMMAND_ENCHANT_DONE_SELF : Lang.COMMAND_ENCHANT_DONE_OTHERS).getMessage()
(context.getSender() == player ? Lang.COMMAND_ENCHANT_DONE_SELF : Lang.COMMAND_ENCHANT_DONE_OTHERS).getMessage().send(context.getSender(), replacer -> replacer
.replace(Placeholders.forPlayer(player))
.replace(Placeholders.GENERIC_ITEM, ItemUtil.getItemName(item))
.replace(Placeholders.GENERIC_ENCHANT, EnchantUtils.getLocalized(enchantment))
.replace(Placeholders.GENERIC_LEVEL, NumberUtil.toRoman(level))
.send(context.getSender());
);
return true;
}
@ -163,11 +163,11 @@ public class BaseCommands {
Enchantment enchantment = arguments.getEnchantmentArgument(CommandArguments.ENCHANT);
EnchantUtils.remove(item, enchantment);
(context.getSender() == player ? Lang.COMMAND_DISENCHANT_DONE_SELF : Lang.COMMAND_DISENCHANT_DONE_OTHERS).getMessage()
(context.getSender() == player ? Lang.COMMAND_DISENCHANT_DONE_SELF : Lang.COMMAND_DISENCHANT_DONE_OTHERS).getMessage().send(context.getSender(), replacer -> replacer
.replace(Placeholders.forPlayer(player))
.replace(Placeholders.GENERIC_ITEM, ItemUtil.getItemName(item))
.replace(Placeholders.GENERIC_ENCHANT, EnchantUtils.getLocalized(enchantment))
.send(context.getSender());
);
return true;
}
@ -178,9 +178,9 @@ public class BaseCommands {
int amount = arguments.getIntArgument(CommandArguments.AMOUNT, 1);
if (!enchantment.hasCharges()) {
Lang.COMMAND_GET_FUEL_ERROR_NO_CHARGES.getMessage()
Lang.COMMAND_GET_FUEL_ERROR_NO_CHARGES.getMessage().send(context.getSender(), replacer -> replacer
.replace(Placeholders.GENERIC_NAME, enchantment.getDisplayName())
.send(context.getSender());
);
return false;
}
@ -189,10 +189,10 @@ public class BaseCommands {
Players.addItem(player, fuel);
Lang.COMMAND_GET_FUEL_DONE.getMessage()
Lang.COMMAND_GET_FUEL_DONE.getMessage().send(context.getSender(), replacer -> replacer
.replace(Placeholders.GENERIC_AMOUNT, NumberUtil.format(amount))
.replace(Placeholders.GENERIC_NAME, ItemUtil.getItemName(fuel))
.send(context.getSender());
);
return true;
}
@ -204,7 +204,7 @@ public class BaseCommands {
plugin.getEnchantManager().openEnchantsMenu(player);
if (player != context.getSender()) {
Lang.COMMAND_LIST_DONE_OTHERS.getMessage().replace(Placeholders.forPlayer(player)).send(context.getSender());
Lang.COMMAND_LIST_DONE_OTHERS.getMessage().send(context.getSender(), replacer -> replacer.replace(Placeholders.forPlayer(player)));
}
return true;
}
@ -229,10 +229,10 @@ public class BaseCommands {
EnchantUtils.add(item, enchantment, level, true);
Players.addItem(player, item);
Lang.COMMAND_RARITY_BOOK_DONE.getMessage()
Lang.COMMAND_RARITY_BOOK_DONE.getMessage().send(context.getSender(), replacer -> replacer
.replace(Placeholders.GENERIC_NAME, rarity.getName())
.replace(Placeholders.forPlayer(player))
.send(context.getSender());
);
return true;
}

View File

@ -1,14 +1,18 @@
package su.nightexpress.excellentenchants.config;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.World;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import su.nightexpress.excellentenchants.util.ChargesFormat;
import su.nightexpress.excellentenchants.util.EnchantBlacklist;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.Lists;
import su.nightexpress.nightcore.util.NumberUtil;
import su.nightexpress.nightcore.util.bukkit.NightItem;
import java.util.*;
import java.util.stream.Collectors;
import java.util.Map;
import java.util.Set;
import static su.nightexpress.excellentenchants.Placeholders.*;
import static su.nightexpress.nightcore.util.text.tag.Tags.*;
@ -116,14 +120,12 @@ public class Config {
"[**] Disabled enchantments will be removed from all items forever!"
);
public static final ConfigValue<Map<String, Set<String>>> ENCHANTMENTS_DISABLED_IN_WORLDS = ConfigValue.forMap("Enchantments.Disabled.ByWorld",
String::toLowerCase,
(cfg, path, worldName) -> cfg.getStringSet(path + "." + worldName).stream().map(String::toLowerCase).collect(Collectors.toSet()),
(cfg, path, map) -> map.forEach((world, enchants) -> cfg.set(path + "." + world, enchants)),
() -> Map.of(
"your_world_name", Lists.newSet("enchantment_name", "ice_aspect"),
"another_world", Lists.newSet("another_enchantment", "ice_aspect")
),
public static final ConfigValue<Map<String, EnchantBlacklist>> ENCHANTMENTS_DISABLED_IN_WORLDS = ConfigValue.forMapById("Enchantments.Disabled.ByWorld",
EnchantBlacklist::read,
map -> {
map.put("your_world_name", new EnchantBlacklist(Lists.newSet("enchantment_name", "ice_aspect")));
map.put("another_world", new EnchantBlacklist(Lists.newSet("another_enchantment", "ice_aspect")));
},
"Put here CUSTOM enchantment names that you want to disable in specific worlds.",
"To disable all enchantments for a world, use '" + WILDCARD + "' instead of enchantment names.",
"Enchantment names are equal to their config file names in the '" + DIR_ENCHANTS + "' directory.",
@ -170,17 +172,13 @@ public class Config {
WIKI_CHRAGES
);
public static final ConfigValue<TreeMap<Integer, String>> ENCHANTMENTS_CHARGES_FORMAT = ConfigValue.forTreeMap("Enchantments.Charges.Format",
raw -> NumberUtil.getInteger(raw, 0),
(cfg, path, value) -> cfg.getString(path + "." + value, GENERIC_AMOUNT),
(cfg, path, map) -> map.forEach((perc, str) -> cfg.set(path + "." + perc, str)),
() -> {
TreeMap<Integer, String> map = new TreeMap<>();
map.put(0, LIGHT_RED.enclose("(" + GENERIC_AMOUNT + "⚡)"));
map.put(25, LIGHT_ORANGE.enclose("(" + GENERIC_AMOUNT + "⚡)"));
map.put(50, LIGHT_YELLOW.enclose("(" + GENERIC_AMOUNT + "⚡)"));
map.put(75, LIGHT_GREEN.enclose("(" + GENERIC_AMOUNT + "⚡)"));
return map;
public static final ConfigValue<Map<String, ChargesFormat>> ENCHANTMENTS_CHARGES_FORMAT = ConfigValue.forMapById("Enchantments.Charges.Formation",
ChargesFormat::read,
map -> {
map.put("zero", new ChargesFormat(0, LIGHT_RED.enclose("(" + GENERIC_AMOUNT + "⚡)")));
map.put("low", new ChargesFormat(25, LIGHT_ORANGE.enclose("(" + GENERIC_AMOUNT + "⚡)")));
map.put("medium", new ChargesFormat(50, LIGHT_YELLOW.enclose("(" + GENERIC_AMOUNT + "⚡)")));
map.put("high", new ChargesFormat(75, LIGHT_GREEN.enclose("(" + GENERIC_AMOUNT + "⚡)")));
},
"Enchantment charges format depends on amount of charges left (in percent).",
"If you don't want to display charges, leave only keys with negative values.",
@ -194,8 +192,8 @@ public class Config {
"[Default is false]"
);
public static final ConfigValue<ItemStack> ENCHANTMENTS_CHARGES_FUEL_ITEM = ConfigValue.create("Enchantments.Charges.Fuel_Item",
new ItemStack(Material.LAPIS_LAZULI),
public static final ConfigValue<NightItem> ENCHANTMENTS_CHARGES_FUEL_ITEM = ConfigValue.create("Enchantments.Charges.Fuel_Item",
new NightItem(Material.LAPIS_LAZULI),
"Default item used to recharge item's enchantments on anvils.",
"If you want different item for certain enchantments, you can do it in that enchantment configs.",
"Item Options: " + WIKI_ITEMS_URL
@ -209,4 +207,9 @@ public class Config {
public static boolean isChargesEnabled() {
return ENCHANTMENTS_CHARGES_ENABLED.get();
}
@Nullable
public static EnchantBlacklist getDisabledEnchantments(@NotNull World world) {
return ENCHANTMENTS_DISABLED_IN_WORLDS.get().get(world.getName().toLowerCase());
}
}

View File

@ -7,11 +7,18 @@ import su.nightexpress.excellentenchants.EnchantsPlugin;
public class Keys {
public static NamespacedKey itemRecharged;
public static NamespacedKey keyLevel;
public static NamespacedKey entitySpawnReason;
public static void loadKeys(@NotNull EnchantsPlugin plugin) {
itemRecharged = new NamespacedKey(plugin, "item.recharged");
keyLevel = new NamespacedKey(plugin, "list_display_level");
entitySpawnReason = new NamespacedKey(plugin, "entity.spawn_reason");
}
public static void clear() {
itemRecharged = null;
keyLevel = null;
entitySpawnReason = null;
}
}

View File

@ -6,10 +6,11 @@ import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.EnchantsPlugin;
import su.nightexpress.excellentenchants.api.ConfigBridge;
import su.nightexpress.excellentenchants.api.EnchantmentID;
import su.nightexpress.excellentenchants.api.enchantment.CustomEnchantment;
import su.nightexpress.excellentenchants.api.enchantment.bridge.FlameWalker;
import su.nightexpress.excellentenchants.api.enchantment.meta.PeriodMeta;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.enchantment.impl.armor.FlameWalkerEnchant;
import su.nightexpress.excellentenchants.enchantment.listener.AnvilListener;
import su.nightexpress.excellentenchants.enchantment.listener.GenericListener;
import su.nightexpress.excellentenchants.enchantment.menu.EnchantsMenu;
@ -25,7 +26,6 @@ public class EnchantManager extends AbstractManager<EnchantsPlugin> {
private final Set<PassiveEnchant> passiveEnchants;
private EnchantsMenu enchantsMenu;
public EnchantManager(@NotNull EnchantsPlugin plugin) {
@ -40,17 +40,25 @@ public class EnchantManager extends AbstractManager<EnchantsPlugin> {
this.addListener(new GenericListener(this.plugin, this));
this.addListener(new AnvilListener(this.plugin));
this.addTask(this.plugin.createAsyncTask(this::displayProjectileTrails).setTicksInterval(Config.CORE_PROJECTILE_PARTICLE_INTERVAL.get()));
this.addAsyncTask(this::displayProjectileTrails, Config.CORE_PROJECTILE_PARTICLE_INTERVAL.get());
if (!this.passiveEnchants.isEmpty()) {
this.addTask(this.plugin.createTask(this::updatePassiveEnchantEffects).setTicksInterval(ConfigBridge.getEnchantsTickInterval()));
this.addTask(this::updatePassiveEnchantEffects, ConfigBridge.getEnchantsTickInterval());
}
if (EnchantRegistry.isRegistered(EnchantmentID.FLAME_WALKER)) {
this.addTask(this.plugin.createTask(FlameWalkerEnchant::tickBlocks).setSecondsInterval(1));
CustomEnchantment enchantment = EnchantRegistry.getById(EnchantmentID.FLAME_WALKER);
if (enchantment instanceof FlameWalker flameWalker) {
this.addTask(flameWalker::tickBlocks, 1);
}
}
@Override
protected void onShutdown() {
CustomEnchantment enchantment = EnchantRegistry.getById(EnchantmentID.FLAME_WALKER);
if (enchantment instanceof FlameWalker flameWalker) {
flameWalker.removeBlocks();
}
if (this.enchantsMenu != null) this.enchantsMenu.clear();
}

View File

@ -8,6 +8,7 @@ import su.nightexpress.excellentenchants.api.enchantment.Charges;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.bukkit.NightItem;
import static su.nightexpress.nightcore.util.Placeholders.WIKI_ITEMS_URL;
@ -18,7 +19,7 @@ public class EnchantCharges implements Charges {
private Modifier maxAmount;
private Modifier consumeAmount;
private Modifier rechargeAmount;
private ItemStack fuel;
private NightItem fuel;
public EnchantCharges() {
@ -54,7 +55,7 @@ public class EnchantCharges implements Charges {
);
this.fuel = ConfigValue.create("Charges.Fuel_Item",
new ItemStack(Material.LAPIS_LAZULI),
new NightItem(Material.LAPIS_LAZULI),
"An item, that will be used to restore enchantment charges on anvils.",
WIKI_ITEMS_URL
).read(config);
@ -93,11 +94,10 @@ public class EnchantCharges implements Charges {
@NotNull
public ItemStack getFuel() {
ItemStack fuelHas = this.fuel;
if (!this.isCustomFuel() || fuelHas == null || fuelHas.getType().isAir()) {
return new ItemStack(Config.ENCHANTMENTS_CHARGES_FUEL_ITEM.get());
if (!this.isCustomFuel() || this.fuel == null || this.fuel.getMaterial().isAir()) {
return Config.ENCHANTMENTS_CHARGES_FUEL_ITEM.get().getItemStack();
}
return new ItemStack(fuelHas);
return this.fuel.getItemStack();
}
@Override

View File

@ -12,31 +12,30 @@ import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.CustomEnchantment;
import su.nightexpress.excellentenchants.api.enchantment.meta.EnchantMeta;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.util.EnchantPlaceholders;
import su.nightexpress.excellentenchants.util.EnchantBlacklist;
import su.nightexpress.excellentenchants.util.EnchantUtils;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.manager.AbstractFileData;
import su.nightexpress.nightcore.manager.SimpeListener;
import su.nightexpress.nightcore.util.PDCUtil;
import su.nightexpress.nightcore.util.placeholder.PlaceholderMap;
import su.nightexpress.nightcore.util.placeholder.PlaceholderList;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.function.UnaryOperator;
public abstract class GameEnchantment extends AbstractFileData<EnchantsPlugin> implements CustomEnchantment {
protected final EnchantMeta meta;
protected final EnchantDefinition definition;
protected final EnchantDistribution distribution;
protected final EnchantCharges charges;
private final NamespacedKey chargesKey;
private final EnchantPlaceholders placeholders;
private final String logPrefix;
protected final EnchantMeta meta;
protected final EnchantDefinition definition;
protected final EnchantDistribution distribution;
protected final EnchantCharges charges;
private final NamespacedKey chargesKey;
private final PlaceholderList<Integer> placeholders;
private final String logPrefix;
private Enchantment enchantment;
private boolean hiddenFromList;
@ -125,9 +124,10 @@ public abstract class GameEnchantment extends AbstractFileData<EnchantsPlugin> i
this.plugin.error(this.logPrefix + text);
}
@Override
@NotNull
public PlaceholderMap getPlaceholders(int level) {
return this.placeholders.toMap(level);
public UnaryOperator<String> replacePlaceholders(int level) {
return this.placeholders.replacer(level);
}
public void addPlaceholder(@NotNull String key, @NotNull Function<Integer, String> replacer) {
@ -166,8 +166,8 @@ public abstract class GameEnchantment extends AbstractFileData<EnchantsPlugin> i
@Override
public boolean isAvailableToUse(@NotNull World world) {
Set<String> disabled = Config.ENCHANTMENTS_DISABLED_IN_WORLDS.get().getOrDefault(world.getName().toLowerCase(), Collections.emptySet());
return disabled.isEmpty() || (!disabled.contains(this.getId()) && !disabled.contains(Placeholders.WILDCARD));
EnchantBlacklist blacklist = Config.getDisabledEnchantments(world);
return blacklist == null || !blacklist.contains(this);
}
@Override
@ -183,7 +183,7 @@ public abstract class GameEnchantment extends AbstractFileData<EnchantsPlugin> i
@Override
@NotNull
public String getFormattedName() {
return this.isCurse() ? this.getDisplayName() : this.getPlaceholders(1).replacer().apply(this.definition.getRarity().getNameFormat());
return this.isCurse() ? this.getDisplayName() : this.replacePlaceholders(1).apply(this.definition.getRarity().getNameFormat());
}
@Override
@ -208,7 +208,7 @@ public abstract class GameEnchantment extends AbstractFileData<EnchantsPlugin> i
description.replaceAll(line -> {
line = lineFormat.replace(Placeholders.GENERIC_DESCRIPTION, line);
line = EnchantUtils.replaceComponents(this, line, level, charges);
line = this.getPlaceholders(level).replacer().apply(line);
line = this.replacePlaceholders(level).apply(line);
return line;
});
return description;
@ -297,7 +297,7 @@ public abstract class GameEnchantment extends AbstractFileData<EnchantsPlugin> i
}
@Override
public void consumeChargesNoUpdate(@NotNull ItemStack item, int level) {
public void consumeCharges(@NotNull ItemStack item, int level) {
if (!this.hasCharges()) return;
int charges = this.getCharges(item);
@ -305,11 +305,4 @@ public abstract class GameEnchantment extends AbstractFileData<EnchantsPlugin> i
this.setCharges(item, level, charges < consumeAmount ? 0 : Math.max(0, charges - consumeAmount));
}
@Override
public void consumeCharges(@NotNull ItemStack item, int level) {
if (!this.hasCharges()) return;
this.consumeChargesNoUpdate(item, level);
}
}

View File

@ -19,9 +19,10 @@ import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.EnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.DecayBlock;
import su.nightexpress.excellentenchants.api.enchantment.TradeType;
import su.nightexpress.excellentenchants.api.enchantment.type.GenericEnchant;
import su.nightexpress.excellentenchants.api.enchantment.bridge.FlameWalker;
import su.nightexpress.excellentenchants.api.enchantment.type.GenericEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.EnchantDefinition;
import su.nightexpress.excellentenchants.enchantment.impl.EnchantDistribution;
import su.nightexpress.excellentenchants.enchantment.impl.GameEnchantment;
@ -32,17 +33,21 @@ import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.manager.SimpeListener;
import su.nightexpress.nightcore.util.BukkitThing;
import su.nightexpress.nightcore.util.Lists;
import su.nightexpress.nightcore.util.random.Rnd;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
import java.io.File;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
public class FlameWalkerEnchant extends GameEnchantment implements GenericEnchant, FlameWalker, SimpeListener {
private static final BlockFace[] FACES = {BlockFace.SOUTH, BlockFace.NORTH, BlockFace.EAST, BlockFace.WEST};
private final Map<Location, DecayBlock> magmaBlocks = new ConcurrentHashMap<>();
private Modifier radius;
private Modifier blockDecayTime;
@ -86,45 +91,47 @@ public class FlameWalkerEnchant extends GameEnchantment implements GenericEnchan
return this.blockDecayTime.getValue(level);
}
// @Override
// public void clear() {
// this.removeBlocks();
// }
@Override
public void clear() {
MAGMA_BLOCKS.keySet().forEach(location -> location.getBlock().setType(Material.LAVA));
MAGMA_BLOCKS.clear();
public void removeBlocks() {
magmaBlocks.keySet().forEach(location -> location.getBlock().setType(Material.LAVA));
magmaBlocks.clear();
}
public static boolean isBlock(@NotNull Block block) {
return MAGMA_BLOCKS.containsKey(block.getLocation());
public boolean isBlock(@NotNull Block block) {
return magmaBlocks.containsKey(block.getLocation());
}
public static void tickBlocks() {
long now = System.currentTimeMillis();
MAGMA_BLOCKS.keySet().removeIf(location -> location.getBlock().isLiquid() || location.getBlock().getType() != Material.MAGMA_BLOCK);
MAGMA_BLOCKS.forEach((location, pair) -> {
@Override
public void tickBlocks() {
magmaBlocks.keySet().removeIf(location -> location.getBlock().isLiquid() || location.getBlock().getType() != Material.MAGMA_BLOCK);
magmaBlocks.forEach((location, decayBlock) -> {
Block block = location.getBlock();
long time = pair.getFirst();
if (now >= time) {
if (decayBlock.isExpired()) {
block.getWorld().getPlayers().forEach(player -> {
player.sendBlockDamage(location, 0F, pair.getSecond());
player.sendBlockDamage(location, 0F, decayBlock.getSourceId());
});
block.setType(Material.LAVA);
UniParticle.blockCrack(Material.MAGMA_BLOCK).play(location, 0.5, 0.7, 0.5, 0.03, 30);
return;
}
long diff = TimeUnit.MILLISECONDS.toSeconds(time - now);
float progress = (float) (1D - Math.min(1D, diff / 5D));
if (progress > 1F) progress = 1F;
if (progress < 0F) progress = 0F;
float finalProgress = progress;
float progress = decayBlock.getProgress();
block.getWorld().getPlayers().forEach(player -> {
player.sendBlockDamage(location, finalProgress, pair.getSecond());
player.sendBlockDamage(location, progress, decayBlock.getSourceId());
});
});
}
@Override
public void addBlock(@NotNull Block block, int level) {
this.magmaBlocks.put(block.getLocation(), new DecayBlock(block.getLocation(), Rnd.getDouble(this.getBlockDecayTime(level)) + 1));
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onPlayerMove(PlayerMoveEvent event) {
Player player = event.getPlayer();

View File

@ -80,6 +80,7 @@ public class TreasureHunterEnchant extends GameEnchantment implements ChanceMeta
"Available loot table names: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/loot/LootTables.html"
).read(config);
this.lootTables.clear();
if (isWhitelist) {
this.lootTables.addAll(tables);
}
@ -89,10 +90,10 @@ public class TreasureHunterEnchant extends GameEnchantment implements ChanceMeta
}
}
@Override
public void clear() {
this.lootTables.clear();
}
// @Override
// public void clear() {
// this.lootTables.clear();
// }
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onLootExplore(LootGenerateEvent event) {

View File

@ -48,6 +48,7 @@ public class SurvivalistEnchant extends GameEnchantment implements FishingEnchan
protected void loadAdditional(@NotNull FileConfig config) {
this.meta.setProbability(Probability.create(config));
this.cookingRecipes.clear();
this.plugin.getServer().recipeIterator().forEachRemaining(recipe -> {
if (recipe instanceof CookingRecipe<?> cookingRecipe && cookingRecipe.getInput().getType().isItem() && !cookingRecipe.getResult().getType().isAir()) {
this.cookingRecipes.add(cookingRecipe);
@ -55,10 +56,10 @@ public class SurvivalistEnchant extends GameEnchantment implements FishingEnchan
});
}
@Override
public void clear() {
this.cookingRecipes.clear();
}
// @Override
// public void clear() {
// this.cookingRecipes.clear();
// }
@NotNull
@Override

View File

@ -84,6 +84,9 @@ public class SmelterEnchant extends GameEnchantment implements ChanceMeta, Block
this.sound = ConfigValue.create("Settings.Sound", NightSound.of(Sound.BLOCK_LAVA_EXTINGUISH), "Sound to play on smelting.").read(config);
this.recipes.clear();
this.exemptedItems.clear();
this.exemptedItems.addAll(ConfigValue.forSet("Settings.Exempted_Blocks",
BukkitThing::getMaterial,
(cfg, path, set) -> cfg.set(path, set.stream().map(BukkitThing::toString).toList()),
@ -100,11 +103,11 @@ public class SmelterEnchant extends GameEnchantment implements ChanceMeta, Block
});
}
@Override
public void clear() {
this.recipes.clear();
this.exemptedItems.clear();
}
// @Override
// public void clear() {
// this.recipes.clear();
// this.exemptedItems.clear();
// }
@Override
public boolean onDrop(@NotNull BlockDropItemEvent event, @NotNull LivingEntity entity, @NotNull ItemStack item, int level) {

View File

@ -80,7 +80,7 @@ public class RestoreEnchant extends GameEnchantment implements GenericEnchant, C
if (!this.checkTriggerChance(level)) return;
event.setCancelled(true);
this.consumeChargesNoUpdate(item, level);
this.consumeCharges(item, level);
double restorePercent = 100D - this.getDurabilityRestore(level);
int restored = (int) (maxDurability * (restorePercent / 100D));

View File

@ -79,7 +79,7 @@ public class SoulboundEnchant extends GameEnchantment implements GenericEnchant,
world.dropItemNaturally(location, save);
}
else {
this.consumeChargesNoUpdate(save, EnchantUtils.getLevel(save, this.getBukkitEnchantment()));
this.consumeCharges(save, EnchantUtils.getLevel(save, this.getBukkitEnchantment()));
player.getInventory().addItem(save);
}
});

View File

@ -107,6 +107,7 @@ public class ScavengerEnchant extends GameEnchantment implements ChanceMeta, Dea
"Available loot table names: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/loot/LootTables.html"
).read(config);
this.lootTables.clear();
if (isWhitelist) {
this.lootTables.addAll(tables);
}
@ -116,10 +117,10 @@ public class ScavengerEnchant extends GameEnchantment implements ChanceMeta, Dea
}
}
@Override
public void clear() {
this.lootTables.clear();
}
// @Override
// public void clear() {
// this.lootTables.clear();
// }
@Override
public boolean onKill(@NotNull EntityDeathEvent event, @NotNull LivingEntity entity, @NotNull Player killer, @NotNull ItemStack weapon, int level) {

View File

@ -41,27 +41,11 @@ public class AnvilListener extends AbstractListener<EnchantsPlugin> {
if (second == null) second = new ItemStack(Material.AIR);
if (result == null) result = new ItemStack(Material.AIR);
//if (first.getType().isAir() || first.getAmount() > 1 || !EnchantUtils.isEnchantable(first)) return;
//if (this.handleRename(event, first, second, result)) return;
if (this.handleRecharge(event, first, second)) return;
this.handleCombine(event, first, second, result);
}
/*private boolean handleRename(@NotNull PrepareAnvilEvent event, @NotNull ItemStack first, @NotNull ItemStack second, @NotNull ItemStack result) {
if (!(second.getType().isAir() || second.getType() != first.getType() && !EnchantUtils.isEnchantedBook(second))) return false;
if (result.getType() != first.getType()) return false;
ItemStack renamed = new ItemStack(result);
EnchantUtils.getCustomEnchantments(first).forEach((hasEnch, hasLevel) -> EnchantUtils.add(renamed, hasEnch.getEnchantment(), hasLevel, true));
EnchantUtils.updateDisplay(renamed);
event.setResult(renamed);
return true;
}*/
@SuppressWarnings("UnstableApiUsage")
private boolean handleRecharge(@NotNull PrepareAnvilEvent event, @NotNull ItemStack first, @NotNull ItemStack second) {
if (!Config.isChargesEnabled()) return false;
@ -82,7 +66,6 @@ public class AnvilListener extends AbstractListener<EnchantsPlugin> {
}
PDCUtil.set(recharged, Keys.itemRecharged, count);
//EnchantUtils.updateDisplay(recharged);
event.setResult(recharged);
this.plugin.runTask(task -> event.getView().setRepairCost(chargable.size()));
@ -92,66 +75,26 @@ public class AnvilListener 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);
/*AtomicInteger repairCost = new AtomicInteger(event.getInventory().getRepairCost());
EnchantUtils.getCustomEnchantments(first).forEach((data, level) -> {
if (EnchantUtils.add(merged, data.getEnchantment(), level, false)) {
repairCost.addAndGet(data.getAnvilCost());
}
});*/
if (EnchantUtils.countCustomEnchantments(merged) > Config.CORE_ITEM_ENCHANT_LIMIT.get()) {
event.setResult(null);
return false;
}
Map<CustomEnchantment, Integer> chargesMap = new HashMap<>();
EnchantUtils.getCustomEnchantments(result).forEach((data, level) -> {
int chargesFirst = data.getCharges(first);
int chargesSecond = data.getCharges(second);
EnchantUtils.getCustomEnchantments(result).forEach((enchantment, level) -> {
int chargesFirst = enchantment.getCharges(first);
int chargesSecond = enchantment.getCharges(second);
chargesMap.put(data, chargesFirst + chargesSecond);
data.setCharges(merged, level, chargesFirst + chargesSecond);
chargesMap.put(enchantment, chargesFirst + chargesSecond);
enchantment.setCharges(merged, level, chargesFirst + chargesSecond);
});
//this.plugin.runTask(task -> event.getInventory().setRepairCost(repairCost.get()));
if (!chargesMap.isEmpty()/* || repairCost.get() != event.getInventory().getRepairCost()*/) {
if (!chargesMap.isEmpty()) {
event.setResult(merged);
return true;
}
return false;
/*
if (second.getType().isAir() || second.getAmount() > 1 || !EnchantUtils.isEnchantable(second)) return false;
if (EnchantUtils.isEnchantedBook(first) && second.getType() != first.getType()) return false;
Map<EnchantmentData, Integer> firstEnchants = EnchantUtils.getCustomEnchantments(first);
//Map<EnchantmentData, Integer> secondEnchants = EnchantUtils.getCustomEnchantments(second);
Map<EnchantmentData, Integer> charges = new HashMap<>(firstEnchants.keySet().stream().collect(Collectors.toMap(k -> k, v -> v.getCharges(first))));
AtomicInteger repairCost = new AtomicInteger(event.getInventory().getRepairCost());
if (EnchantUtils.isEnchantedBook(second) || second.getType() == first.getType()) {
EnchantUtils.getCustomEnchantments(second).forEach((data, level) -> {
int maxMergeLevel = data.getMaxMergeLevel() < 0 ? data.getMaxLevel() : data.getMaxMergeLevel();
firstEnchants.merge(data, level, (oldLvl, newLvl) -> oldLvl.equals(newLvl) ? Math.min(maxMergeLevel, oldLvl + 1) : Math.max(oldLvl, newLvl));
charges.merge(data, data.getCharges(second), Integer::sum);
});
}
firstEnchants.forEach((enchantmentData, level) -> {
if (EnchantUtils.add(merged, enchantmentData.getEnchantment(), level, false)) {
repairCost.addAndGet(enchantmentData.getAnvilMergeCost(level));
enchantmentData.setCharges(merged, level, charges.getOrDefault(enchantmentData, 0));
}
});
if (first.equals(merged)) return false;
EnchantUtils.updateDisplay(merged);
event.setResult(merged);
this.plugin.runTask(task -> event.getInventory().setRepairCost(repairCost.get()));
return true;*/
}
@SuppressWarnings("UnstableApiUsage")

View File

@ -26,7 +26,7 @@ public class GenericListener extends AbstractListener<EnchantsPlugin> {
//private final EnchantManager enchantManager;
public GenericListener(@NotNull EnchantsPlugin plugin, @NotNull EnchantManager enchantManager) {
public GenericListener(@NotNull EnchantsPlugin plugin, @NotNull EnchantManager manager) {
super(plugin);
//this.enchantManager = enchantManager;
}

View File

@ -1,47 +1,53 @@
package su.nightexpress.excellentenchants.enchantment.menu;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.MenuType;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.EnchantsPlugin;
import su.nightexpress.excellentenchants.api.enchantment.CustomEnchantment;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.config.Keys;
import su.nightexpress.excellentenchants.registry.EnchantRegistry;
import su.nightexpress.excellentenchants.util.EnchantUtils;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.core.CoreLang;
import su.nightexpress.nightcore.menu.MenuOptions;
import su.nightexpress.nightcore.menu.MenuSize;
import su.nightexpress.nightcore.menu.MenuViewer;
import su.nightexpress.nightcore.menu.api.AutoFill;
import su.nightexpress.nightcore.menu.api.AutoFilled;
import su.nightexpress.nightcore.menu.impl.ConfigMenu;
import su.nightexpress.nightcore.menu.item.ItemHandler;
import su.nightexpress.nightcore.menu.item.MenuItem;
import su.nightexpress.nightcore.util.*;
import su.nightexpress.nightcore.ui.menu.MenuViewer;
import su.nightexpress.nightcore.ui.menu.data.ConfigBased;
import su.nightexpress.nightcore.ui.menu.data.Filled;
import su.nightexpress.nightcore.ui.menu.data.MenuFiller;
import su.nightexpress.nightcore.ui.menu.data.MenuLoader;
import su.nightexpress.nightcore.ui.menu.item.MenuItem;
import su.nightexpress.nightcore.ui.menu.type.NormalMenu;
import su.nightexpress.nightcore.util.ItemUtil;
import su.nightexpress.nightcore.util.Lists;
import su.nightexpress.nightcore.util.NumberUtil;
import su.nightexpress.nightcore.util.PDCUtil;
import su.nightexpress.nightcore.util.bukkit.NightItem;
import su.nightexpress.nightcore.util.placeholder.Replacer;
import su.nightexpress.nightcore.util.text.NightMessage;
import java.util.*;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.IntStream;
import static su.nightexpress.excellentenchants.Placeholders.*;
import static su.nightexpress.nightcore.util.text.tag.Tags.*;
public class EnchantsMenu extends ConfigMenu<EnchantsPlugin> implements AutoFilled<CustomEnchantment> {
@SuppressWarnings("UnstableApiUsage")
public class EnchantsMenu extends NormalMenu<EnchantsPlugin> implements ConfigBased, Filled<CustomEnchantment> {
private static final String FILE_NAME = "enchants.yml";
private static final String CONFLICTS = "%conflicts%";
private static final String CHARGES = "%charges%";
private final NamespacedKey keyLevel;
private final Map<String, Map<Integer, ItemStack>> iconCache;
private ItemStack enchantIcon;
private NightItem enchantIcon;
private String enchantName;
private List<String> enchantLoreMain;
private List<String> enchantLoreConflicts;
@ -49,78 +55,13 @@ public class EnchantsMenu extends ConfigMenu<EnchantsPlugin> implements AutoFill
private int[] enchantSlots;
public EnchantsMenu(@NotNull EnchantsPlugin plugin) {
super(plugin, FileConfig.loadOrExtract(plugin, Config.DIR_MENU, FILE_NAME));
this.keyLevel = new NamespacedKey(plugin, "list_display_level");
this.iconCache = new HashMap<>();
super(plugin, MenuType.GENERIC_9X4, BLACK.enclose("Custom Enchantments"));
this.load();
}
public void clear() {
super.clear();
this.iconCache.clear();
this.load(FileConfig.loadOrExtract(plugin, Config.DIR_MENU, FILE_NAME));
}
@Override
protected void loadAdditional() {
this.enchantIcon = ConfigValue.create("Enchantment.Icon", new ItemStack(Material.ENCHANTED_BOOK)).read(this.cfg);
this.enchantName = ConfigValue.create("Enchantment.Name",
LIGHT_YELLOW.enclose(BOLD.enclose(ENCHANTMENT_NAME + " " + ENCHANTMENT_LEVEL))
).read(this.cfg);
this.enchantLoreMain = ConfigValue.create("Enchantment.Lore.Main",
Lists.newList(
ENCHANTMENT_RARITY,
"",
ENCHANTMENT_DESCRIPTION_REPLACED,
DARK_GRAY.enclose("(click to switch levels)"),
"",
LIGHT_YELLOW.enclose(BOLD.enclose("Info:")),
LIGHT_YELLOW.enclose("" + LIGHT_GRAY.enclose("Applies to: ") + ENCHANTMENT_FIT_ITEM_TYPES),
LIGHT_YELLOW.enclose("" + LIGHT_GRAY.enclose("Levels: ") + ENCHANTMENT_LEVEL_MIN + LIGHT_GRAY.enclose(" - ") + ENCHANTMENT_LEVEL_MAX),
CHARGES,
CONFLICTS
)).read(this.cfg);
this.enchantLoreConflicts = ConfigValue.create("Enchantment.Lore.Conflicts",
Lists.newList(
"",
LIGHT_RED.enclose(BOLD.enclose("Conflicts:")),
LIGHT_RED.enclose("") + LIGHT_GRAY.enclose(GENERIC_NAME)
)).read(this.cfg);
this.enchantLoreCharges = ConfigValue.create("Enchantment.Lore.Charges",
Lists.newList(
LIGHT_YELLOW.enclose("" + LIGHT_GRAY.enclose("Charges: ") + GENERIC_AMOUNT + "" + LIGHT_GRAY.enclose(" (" + WHITE.enclose(GENERIC_ITEM) + ")")))
).read(this.cfg);
this.enchantSlots = ConfigValue.create("Enchantment.Slots", IntStream.range(0, 27).toArray()).read(this.cfg);
}
@NotNull
protected MenuOptions createDefaultOptions() {
return new MenuOptions(BLACK.enclose("Custom Enchantments"), MenuSize.CHEST_36);
}
@NotNull
protected List<MenuItem> createDefaultItems() {
List<MenuItem> list = new ArrayList<>();
ItemStack nextPageStack = ItemUtil.getSkinHead(SKIN_ARROW_RIGHT);
ItemUtil.editMeta(nextPageStack, meta -> meta.setDisplayName(CoreLang.EDITOR_ITEM_NEXT_PAGE.getLocalizedName()));
ItemStack prevPageStack = ItemUtil.getSkinHead(SKIN_ARROW_LEFT);
ItemUtil.editMeta(prevPageStack, meta -> meta.setDisplayName(CoreLang.EDITOR_ITEM_PREVIOUS_PAGE.getLocalizedName()));
list.add(new MenuItem(nextPageStack).setSlots(35).setHandler(ItemHandler.forNextPage(this)).setPriority(5));
list.add(new MenuItem(prevPageStack).setSlots(27).setHandler(ItemHandler.forPreviousPage(this)).setPriority(5));
return list;
}
@Override
public void onPrepare(@NotNull MenuViewer viewer, @NotNull MenuOptions options) {
protected void onPrepare(@NotNull MenuViewer viewer, @NotNull InventoryView view) {
this.autoFill(viewer);
}
@ -130,37 +71,39 @@ public class EnchantsMenu extends ConfigMenu<EnchantsPlugin> implements AutoFill
}
@Override
public void onAutoFill(@NotNull MenuViewer viewer, @NotNull AutoFill<CustomEnchantment> autoFill) {
@NotNull
public MenuFiller<CustomEnchantment> createFiller(@NotNull MenuViewer viewer) {
var autoFill = MenuFiller.builder(this);
autoFill.setSlots(this.enchantSlots);
autoFill.setItems(EnchantRegistry.getRegistered().stream()
.filter(Predicate.not(CustomEnchantment::isHiddenFromList))
.sorted(Comparator.comparing(data -> NightMessage.stripAll(data.getDisplayName())))
.toList()
);
autoFill.setItemCreator(enchantmentData -> this.getEnchantIcon(enchantmentData, 1));
autoFill.setClickAction(enchantmentData -> (viewer1, event) -> {
autoFill.setItemCreator(enchantmentData -> this.buildEnchantIcon(enchantmentData, 1));
autoFill.setItemClick(enchantmentData -> (viewer1, event) -> {
if (!event.isLeftClick()) return;
ItemStack currentItem = event.getCurrentItem();
if (currentItem == null) return;
int levelHas = PDCUtil.getInt(currentItem, this.keyLevel).orElse(1);
int levelHas = PDCUtil.getInt(currentItem, Keys.keyLevel).orElse(1);
if (++levelHas > enchantmentData.getDefinition().getMaxLevel()) {
levelHas = 1;
}
currentItem = this.getEnchantIcon(enchantmentData, levelHas);
PDCUtil.set(currentItem, this.keyLevel, levelHas);
event.setCurrentItem(currentItem);
});
}
private ItemStack getEnchantIcon(@NotNull CustomEnchantment enchant, int level) {
return this.iconCache.computeIfAbsent(enchant.getId(), k -> new HashMap<>()).computeIfAbsent(level, k -> this.buildEnchantIcon(enchant, level));
ItemStack item = this.buildEnchantIcon(enchantmentData, levelHas).getItemStack();
PDCUtil.set(item, Keys.keyLevel, levelHas);
event.setCurrentItem(item);
});
return autoFill.build();
}
@NotNull
private ItemStack buildEnchantIcon(@NotNull CustomEnchantment enchant, int level) {
ItemStack icon = new ItemStack(this.enchantIcon);
private NightItem buildEnchantIcon(@NotNull CustomEnchantment enchant, int level) {
NightItem icon = this.enchantIcon.copy();
List<String> conflicts = new ArrayList<>();
if (enchant.getDefinition().hasConflicts()) {
@ -178,21 +121,64 @@ public class EnchantsMenu extends ConfigMenu<EnchantsPlugin> implements AutoFill
List<String> charges = new ArrayList<>();
if (enchant.hasCharges()) {
for (String line : this.enchantLoreCharges) {
charges.add(line
charges.add(Replacer.create()
.replace(GENERIC_AMOUNT, NumberUtil.format(enchant.getCharges().getMaxAmount(level)))
.replace(GENERIC_ITEM, ItemUtil.getItemName(enchant.getCharges().getFuel()))
.apply(line)
);
}
}
ItemReplacer.create(icon).hideFlags().trimmed()
icon.setHideComponents(true)
.setDisplayName(this.enchantName)
.setLore(this.enchantLoreMain)
.replace(CHARGES, charges)
.replace(CONFLICTS, conflicts)
.replace(enchant.getPlaceholders(level))
.writeMeta();
.replacement(replacer -> replacer
.replace(CHARGES, charges)
.replace(CONFLICTS, conflicts)
.replace(enchant.replacePlaceholders(level))
);
return icon;
}
@Override
public void loadConfiguration(@NotNull FileConfig config, @NotNull MenuLoader loader) {
this.enchantIcon = ConfigValue.create("Enchantment.Icon", new NightItem(Material.ENCHANTED_BOOK)).read(config);
this.enchantName = ConfigValue.create("Enchantment.Name",
LIGHT_YELLOW.enclose(BOLD.enclose(ENCHANTMENT_NAME + " " + ENCHANTMENT_LEVEL))
).read(config);
this.enchantLoreMain = ConfigValue.create("Enchantment.Lore.Main",
Lists.newList(
ENCHANTMENT_RARITY,
"",
ENCHANTMENT_DESCRIPTION_REPLACED,
DARK_GRAY.enclose("(click to switch levels)"),
"",
LIGHT_YELLOW.enclose(BOLD.enclose("Info:")),
LIGHT_YELLOW.enclose("" + LIGHT_GRAY.enclose("Applies to: ") + ENCHANTMENT_FIT_ITEM_TYPES),
LIGHT_YELLOW.enclose("" + LIGHT_GRAY.enclose("Levels: ") + ENCHANTMENT_LEVEL_MIN + LIGHT_GRAY.enclose(" - ") + ENCHANTMENT_LEVEL_MAX),
CHARGES,
CONFLICTS
)).read(config);
this.enchantLoreConflicts = ConfigValue.create("Enchantment.Lore.Conflicts",
Lists.newList(
"",
LIGHT_RED.enclose(BOLD.enclose("Conflicts:")),
LIGHT_RED.enclose("") + LIGHT_GRAY.enclose(GENERIC_NAME)
)).read(config);
this.enchantLoreCharges = ConfigValue.create("Enchantment.Lore.Charges",
Lists.newList(
LIGHT_YELLOW.enclose("" + LIGHT_GRAY.enclose("Charges: ") + GENERIC_AMOUNT + "" + LIGHT_GRAY.enclose(" (" + WHITE.enclose(GENERIC_ITEM) + ")")))
).read(config);
this.enchantSlots = ConfigValue.create("Enchantment.Slots", IntStream.range(0, 27).toArray()).read(config);
loader.addDefaultItem(MenuItem.buildNextPage(this, 35));
loader.addDefaultItem(MenuItem.buildPreviousPage(this, 27));
}
}

View File

@ -40,43 +40,39 @@ public class PacketEventsHook {
if (player == null) return;
if (!EnchantUtils.canUpdateDisplay(player)) return;
if (type == PacketType.Play.Server.SET_SLOT) {
WrapperPlayServerSetSlot setSlot = new WrapperPlayServerSetSlot(event);
switch (type) {
case PacketType.Play.Server.SET_SLOT -> {
WrapperPlayServerSetSlot setSlot = new WrapperPlayServerSetSlot(event);
ItemStack item = EnchantUtils.addDescription(toBukkit(setSlot.getItem()));
setSlot.setItem(fromBukkit(item));
}
else if (type == PacketType.Play.Server.WINDOW_ITEMS) {
WrapperPlayServerWindowItems windowItems = new WrapperPlayServerWindowItems(event);
ItemStack item = EnchantUtils.addDescription(toBukkit(setSlot.getItem()));
setSlot.setItem(fromBukkit(item));
}
case PacketType.Play.Server.WINDOW_ITEMS -> {
WrapperPlayServerWindowItems windowItems = new WrapperPlayServerWindowItems(event);
windowItems.getItems().replaceAll(packetItem -> {
return fromBukkit(EnchantUtils.addDescription(toBukkit(packetItem)));
});
}
else if (type == PacketType.Play.Server.MERCHANT_OFFERS) {
WrapperPlayServerMerchantOffers merchantOffers = new WrapperPlayServerMerchantOffers(event);
windowItems.getItems().replaceAll(packetItem -> {
return fromBukkit(EnchantUtils.addDescription(toBukkit(packetItem)));
});
}
case PacketType.Play.Server.MERCHANT_OFFERS -> {
WrapperPlayServerMerchantOffers merchantOffers = new WrapperPlayServerMerchantOffers(event);
List<MerchantOffer> offers = merchantOffers.getMerchantOffers();
offers.forEach(offer -> {
ItemStack result = toBukkit(offer.getOutputItem());
offer.setOutputItem(fromBukkit(EnchantUtils.addDescription(result)));
});
List<MerchantOffer> offers = merchantOffers.getMerchantOffers();
offers.forEach(offer -> {
ItemStack result = toBukkit(offer.getOutputItem());
offer.setOutputItem(fromBukkit(EnchantUtils.addDescription(result)));
});
}
default -> {
return;
}
}
else return;
event.markForReEncode(true);
}
@NotNull
private static ItemStack toBukkit(@NotNull com.github.retrooper.packetevents.protocol.item.ItemStack pooperStack/*, @NotNull ClientVersion version*/) {
// pooperStack.getEnchantments(version).forEach(enchantment -> {
// String name = enchantment.getType().getName().getKey();
// CustomEnchantment custom = EnchantRegistry.getById(name);
// if (custom == null) return;
//
// EnchantUtils.add(item, custom.getBukkitEnchantment(), enchantment.getLevel(), true);
// });
private static ItemStack toBukkit(@NotNull com.github.retrooper.packetevents.protocol.item.ItemStack pooperStack) {
return SpigotConversionUtil.toBukkitItemStack(pooperStack);
}

View File

@ -88,7 +88,7 @@ public class PlaceholderHook {
CustomEnchantment enchant = EnchantRegistry.getByKey(NamespacedKey.minecraft(chargesSplit[0].toLowerCase()));
if (enchant == null) return null;
int level = NumberUtil.getInteger(chargesSplit[1], 1);
int level = NumberUtil.getIntegerAbs(chargesSplit[1], 1);
return String.valueOf(enchant.getCharges().getMaxAmount(level));
}

View File

@ -72,10 +72,7 @@ public class EnchantRegistry extends SimpleManager<EnchantsPlugin> {
// Prevent to register enchantments during the runtime.
if (this.freezed) {
getRegistered().forEach(enchantment -> {
enchantment.clear();
this.load(enchantment);
});
getRegistered().forEach(this::load);
return;
}
@ -184,10 +181,10 @@ public class EnchantRegistry extends SimpleManager<EnchantsPlugin> {
@Override
protected void onShutdown() {
if (!freezed) {
getRegistered().forEach(CustomEnchantment::clear);
ENCHANTS_MAP.clear();
}
// if (!freezed) {
// getRegistered().forEach(CustomEnchantment::clear);
// ENCHANTS_MAP.clear();
// }
}
private <T extends CustomEnchantment> void registerType(@NotNull Class<T> enchantClass) {

View File

@ -1,7 +1,6 @@
package su.nightexpress.excellentenchants.registry.wrapper;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@ -38,7 +37,7 @@ public class WrappedEvent<E extends Event, T extends CustomEnchantment> implemen
LivingEntity entity = this.dataGather.getEntity(event);
if (entity == null) return;
Player player = entity instanceof Player user ? user : null;
//Player player = entity instanceof Player user ? user : null;
this.dataGather.getEnchants(event, this.enchantClass, entity).forEach((item, enchants) -> {
enchants.forEach((enchant, level) -> {
@ -46,7 +45,7 @@ public class WrappedEvent<E extends Event, T extends CustomEnchantment> implemen
if (!enchant.isAvailableToUse(entity)) return;
if (enchant.isOutOfCharges(item)) return;
if (this.dataGather.useEnchant(event, entity, item, enchant, level)) {
enchant.consumeChargesNoUpdate(item, level);
enchant.consumeCharges(item, level);
}
});
});

View File

@ -0,0 +1,53 @@
package su.nightexpress.excellentenchants.util;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.config.Writeable;
public class ChargesFormat implements Writeable {
private final int threshold;
private final String format;
public ChargesFormat(int threshold, @NotNull String format) {
this.threshold = threshold;
this.format = format;
}
@NotNull
public String getFormatted(int charges) {
return this.format.replace(Placeholders.GENERIC_AMOUNT, String.valueOf(charges));
}
public boolean isAboveThreshold(int percent) {
return percent >= this.threshold;
}
public boolean isUnderThreshold(int percent) {
return percent < this.threshold;
}
@NotNull
public static ChargesFormat read(@NotNull FileConfig config, @NotNull String path) {
int threshold = config.getInt(path + ".Threshold");
String format = config.getString(path + ".Format", Placeholders.GENERIC_AMOUNT);
return new ChargesFormat(threshold, format);
}
@Override
public void write(@NotNull FileConfig config, @NotNull String path) {
config.set(path + ".Threshold", this.threshold);
config.set(path + ".Format", this.format);
}
public int getThreshold() {
return this.threshold;
}
@NotNull
public String getFormat() {
return this.format;
}
}

View File

@ -0,0 +1,38 @@
package su.nightexpress.excellentenchants.util;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.CustomEnchantment;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.config.Writeable;
import java.util.Set;
import java.util.stream.Collectors;
public class EnchantBlacklist implements Writeable {
private final Set<String> enchantNames;
public EnchantBlacklist(@NotNull Set<String> enchantNames) {
this.enchantNames = enchantNames.stream().map(String::toLowerCase).collect(Collectors.toSet());
}
public boolean contains(@NotNull CustomEnchantment enchantment) {
return this.contains(enchantment.getId());
}
public boolean contains(@NotNull String name) {
return this.enchantNames.contains(Placeholders.WILDCARD) || this.enchantNames.contains(name.toLowerCase());
}
@NotNull
public static EnchantBlacklist read(@NotNull FileConfig config, @NotNull String path) {
Set<String> names = config.getStringSet(path);
return new EnchantBlacklist(names);
}
@Override
public void write(@NotNull FileConfig config, @NotNull String path) {
config.set(path, this.enchantNames);
}
}

View File

@ -1,78 +0,0 @@
package su.nightexpress.excellentenchants.util;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.nightcore.util.Pair;
import su.nightexpress.nightcore.util.placeholder.PlaceholderMap;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
public class EnchantPlaceholders {
private final List<Pair<String, Function<Integer, String>>> keys;
public EnchantPlaceholders() {
this(new ArrayList<>());
}
public EnchantPlaceholders(@NotNull EnchantPlaceholders other) {
this(other.getKeys());
}
public EnchantPlaceholders(@NotNull List<Pair<String, Function<Integer, String>>> keys) {
this.keys = new ArrayList<>(keys);
}
@NotNull
public static EnchantPlaceholders fusion(@NotNull EnchantPlaceholders... others) {
EnchantPlaceholders map = new EnchantPlaceholders();
for (EnchantPlaceholders other : others) {
map.add(other);
}
return map;
}
@NotNull
public List<Pair<String, Function<Integer, String>>> getKeys() {
return keys;
}
@NotNull
public EnchantPlaceholders add(@NotNull EnchantPlaceholders other) {
this.getKeys().addAll(other.getKeys());
return this;
}
@NotNull
public EnchantPlaceholders add(@NotNull String key, @NotNull String replacer) {
this.add(key, level -> replacer);
return this;
}
@NotNull
public EnchantPlaceholders add(@NotNull String key, @NotNull Supplier<String> replacer) {
this.add(key, level -> replacer.get());
return this;
}
@NotNull
public EnchantPlaceholders add(@NotNull String key, @NotNull Function<Integer, String> replacer) {
this.getKeys().add(Pair.of(key, replacer));
return this;
}
public void clear() {
this.getKeys().clear();
}
@NotNull
public PlaceholderMap toMap(int level) {
List<Pair<String, Supplier<String>>> list = new ArrayList<>();
this.getKeys().forEach(pair -> {
list.add(Pair.of(pair.getFirst(), () -> pair.getSecond().apply(level)));
});
return new PlaceholderMap(list);
}
}

View File

@ -31,8 +31,6 @@ import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static su.nightexpress.excellentenchants.Placeholders.*;
import static su.nightexpress.excellentenchants.Placeholders.GENERIC_CHARGES;
import static su.nightexpress.nightcore.util.Placeholders.GENERIC_VALUE;
public class EnchantUtils {
@ -110,9 +108,13 @@ public class EnchantUtils {
if (showCharges) {
int chargesMax = enchantment.getCharges().getMaxAmount(level);
int percent = (int) Math.ceil((double) charges / (double) chargesMax * 100D);
Map.Entry<Integer, String> entry = Config.ENCHANTMENTS_CHARGES_FORMAT.get().floorEntry(percent);
if (entry != null) {
chargesFormat = entry.getValue().replace(GENERIC_AMOUNT, String.valueOf(charges));
ChargesFormat format = Config.ENCHANTMENTS_CHARGES_FORMAT.get().values().stream()
.filter(f -> f.isAboveThreshold(percent))
.max(Comparator.comparingInt(ChargesFormat::getThreshold)).orElse(null);
if (format != null) {
chargesFormat = format.getFormatted(charges);
}
}
@ -298,30 +300,9 @@ public class EnchantUtils {
Map<EquipmentSlot, ItemStack> equipment = EntityUtil.getEquippedItems(entity, slots);
equipment.values().removeIf(item -> item == null || isEnchantedBook(item) || !item.hasItemMeta());
// equipment.entrySet().removeIf(entry -> {
// ItemStack item = entry.getValue();
// EquipmentSlot slot = entry.getKey();
// if (item == null || item.getType().isAir() || item.getType() == Material.ENCHANTED_BOOK) return true;
// if ((slot == EquipmentSlot.HAND || slot == EquipmentSlot.OFF_HAND) && ItemUtil.isArmor(item)) return true;
// return !item.hasItemMeta();
// });
return equipment;
}
/*@NotNull
private static Map<ItemStack, Map<EnchantmentData, Integer>> getEquipped(@NotNull LivingEntity entity) {
Map<ItemStack, Map<EnchantmentData, Integer>> map = new HashMap<>();
getEnchantedEquipment(entity).values().forEach(item -> {
map.computeIfAbsent(item, k -> new LinkedHashMap<>()).putAll(getCustomEnchantments(item));
});
return map;
}
@NotNull
public static <T extends EnchantmentData> Map<ItemStack, Map<T, Integer>> getEquipped(@NotNull LivingEntity entity, @NotNull Class<T> clazz) {
return getEquipped(entity, clazz, EQUIPMENT_SLOTS);
}*/
@Nullable
public static ItemStack getEquipped(@NotNull LivingEntity entity, @NotNull EquipmentSlot slot) {
EntityEquipment equipment = entity.getEquipment();

View File

@ -16,80 +16,66 @@ public class ItemCategories {
public static final ItemsCategory HELMET = ItemsCategory.buildDirect(getItemsBySlot(EquipmentSlot.HEAD)).slots(EquipmentSlot.HEAD)
.localized(Lang.ITEM_CATEGORY_HELMET)
/*.target(EnchantmentTarget.ARMOR_HEAD)*/.build();
.build();
public static final ItemsCategory CHESTPLATE = ItemsCategory.buildDirect(getItemsBySlot(EquipmentSlot.CHEST)).slots(EquipmentSlot.CHEST)
.localized(Lang.ITEM_CATEGORY_CHESTPLATE)
/*.target(EnchantmentTarget.ARMOR_TORSO)*/.build();
.build();
public static final ItemsCategory LEGGINGS = ItemsCategory.buildDirect(getItemsBySlot(EquipmentSlot.LEGS)).slots(EquipmentSlot.LEGS)
.localized(Lang.ITEM_CATEGORY_LEGGINGS)
//.target(EnchantmentTarget.ARMOR_LEGS)
.build();
public static final ItemsCategory BOOTS = ItemsCategory.buildDirect(getItemsBySlot(EquipmentSlot.FEET)).slots(EquipmentSlot.FEET)
.localized(Lang.ITEM_CATEGORY_BOOTS)
//.target(EnchantmentTarget.ARMOR_FEET)
.build();
public static final ItemsCategory ELYTRA = ItemsCategory.buildDirect(Material.ELYTRA).slots(EquipmentSlot.CHEST)
.localized(Lang.ITEM_CATEGORY_ELYTRA)
//.target(EnchantmentTarget.ARMOR_TORSO)
.build();
public static final ItemsCategory SWORD = ItemsCategory.buildDirect(Tag.ITEMS_SWORDS).slots(EquipmentSlot.HAND)
.localized(Lang.ITEM_CATEGORY_SWORD)
//.target(EnchantmentTarget.WEAPON)
.build();
public static final ItemsCategory AXE = ItemsCategory.buildDirect(Tag.ITEMS_AXES).slots(EquipmentSlot.HAND)
.localized(Lang.ITEM_CATEGORY_AXE)
//.target(EnchantmentTarget.TOOL)
.build();
public static final ItemsCategory HOE = ItemsCategory.buildDirect(Tag.ITEMS_HOES).slots(EquipmentSlot.HAND)
.localized(Lang.ITEM_CATEGORY_HOE)
//.target(EnchantmentTarget.TOOL)
.build();
public static final ItemsCategory PICKAXE = ItemsCategory.buildDirect(Tag.ITEMS_PICKAXES).slots(EquipmentSlot.HAND)
.localized(Lang.ITEM_CATEGORY_PICKAXE)
//.target(EnchantmentTarget.TOOL)
.build();
public static final ItemsCategory SHOVEL = ItemsCategory.buildDirect(Tag.ITEMS_SHOVELS).slots(EquipmentSlot.HAND)
.localized(Lang.ITEM_CATEGORY_SHOVEL)
//.target(EnchantmentTarget.TOOL)
.build();
public static final ItemsCategory TRIDENT = ItemsCategory.buildDirect(Material.TRIDENT).slots(EquipmentSlot.HAND, EquipmentSlot.OFF_HAND)
.localized(Lang.ITEM_CATEGORY_TRIDENT)
//.target(EnchantmentTarget.TRIDENT)
.build();
public static final ItemsCategory BOW = ItemsCategory.buildDirect(Material.BOW).slots(EquipmentSlot.HAND, EquipmentSlot.OFF_HAND)
.localized(Lang.ITEM_CATEGORY_BOW)
//.target(EnchantmentTarget.BOW)
.build();
public static final ItemsCategory CROSSBOW = ItemsCategory.buildDirect(Material.CROSSBOW).slots(EquipmentSlot.HAND, EquipmentSlot.OFF_HAND)
.localized(Lang.ITEM_CATEGORY_CROSSBOW)
//.target(EnchantmentTarget.CROSSBOW)
.build();
public static final ItemsCategory FISHING_ROD = ItemsCategory.buildDirect(Material.FISHING_ROD).slots(EquipmentSlot.HAND, EquipmentSlot.OFF_HAND)
.localized(Lang.ITEM_CATEGORY_FISHING_ROD)
//.target(EnchantmentTarget.FISHING_ROD)
.build();
public static final ItemsCategory SHIELD = ItemsCategory.buildDirect(Material.SHIELD).slots(EquipmentSlot.OFF_HAND)
.localized(Lang.ITEM_CATEGORY_SHIELD)
//.target(EnchantmentTarget.BREAKABLE)
.build();
public static final ItemsCategory BREAKABLE = ItemsCategory.buildDirect(getItemsWithDurability()).slots(EquipmentSlot.values())
.localized(Lang.ITEM_CATEGORY_BREAKABLE)
//.target(EnchantmentTarget.BREAKABLE)
.build();
public static final ItemsCategory ARMOR = ItemsCategory.buildRef(() -> {
@ -99,14 +85,14 @@ public class ItemCategories {
materials.addAll(getItemsBySlot(EquipmentSlot.LEGS));
materials.addAll(getItemsBySlot(EquipmentSlot.FEET));
return materials;
}).slots(EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET)./*target(EnchantmentTarget.ARMOR).*/localized(Lang.ITEM_CATEGORY_ARMOR).build();
}).slots(EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET).localized(Lang.ITEM_CATEGORY_ARMOR).build();
public static final ItemsCategory TOOL = ItemsCategory.buildDirect(
Tag.ITEMS_AXES,
Tag.ITEMS_HOES,
Tag.ITEMS_PICKAXES,
Tag.ITEMS_SHOVELS
).slots(EquipmentSlot.HAND)/*.target(EnchantmentTarget.TOOL)*/.localized(Lang.ITEM_CATEGORY_TOOL).build();
).slots(EquipmentSlot.HAND).localized(Lang.ITEM_CATEGORY_TOOL).build();
public static final ItemsCategory WEAPON = ItemsCategory.buildRef(() -> {
@ -117,7 +103,7 @@ public class ItemCategories {
}
return materials;
}).slots(EquipmentSlot.HAND)./*target(EnchantmentTarget.WEAPON).*/localized(Lang.ITEM_CATEGORY_WEAPON).build();
}).slots(EquipmentSlot.HAND).localized(Lang.ITEM_CATEGORY_WEAPON).build();
public static final ItemsCategory BOWS = ItemsCategory.buildRef(() -> {
@ -128,7 +114,7 @@ public class ItemCategories {
}
return materials;
}).slots(EquipmentSlot.HAND, EquipmentSlot.OFF_HAND)./*target(EnchantmentTarget.BOW).*/localized(Lang.ITEM_CATEGORY_BOWS).build();
}).slots(EquipmentSlot.HAND, EquipmentSlot.OFF_HAND).localized(Lang.ITEM_CATEGORY_BOWS).build();
public static final ItemsCategory TORSO = ItemsCategory.buildRef(() -> {
@ -139,7 +125,7 @@ public class ItemCategories {
}
return materials;
}).slots(EquipmentSlot.CHEST)./*target(EnchantmentTarget.ARMOR_TORSO).*/localized(Lang.ITEM_CATEGORY_TORSO).build();
}).slots(EquipmentSlot.CHEST).localized(Lang.ITEM_CATEGORY_TORSO).build();
public static final ItemsCategory ALL_RANGE_WEAPON = ItemsCategory.buildRef(() -> {
@ -149,7 +135,7 @@ public class ItemCategories {
materials.addAll(TRIDENT.getMaterials());
materials.addAll(TOOL.getMaterials());
return materials;
}).slots(EquipmentSlot.HAND)./*target(EnchantmentTarget.BREAKABLE).*/localized(Lang.ITEM_CATEGORY_ALL_WEAPON).build();
}).slots(EquipmentSlot.HAND).localized(Lang.ITEM_CATEGORY_ALL_WEAPON).build();
public static final ItemsCategory MINING_TOOLS = ItemsCategory.buildRef(() -> {
Set<Material> materials = new HashSet<>();
@ -157,7 +143,7 @@ public class ItemCategories {
materials.addAll(PICKAXE.getMaterials());
materials.addAll(SHOVEL.getMaterials());
return materials;
}).slots(EquipmentSlot.HAND)./*target(EnchantmentTarget.TOOL).*/localized(Lang.ITEM_CATEGORY_MINING_TOOLS).build();
}).slots(EquipmentSlot.HAND).localized(Lang.ITEM_CATEGORY_MINING_TOOLS).build();
@NotNull

View File

@ -1,72 +1,72 @@
Command:
List:
Desc: 'Lista de encantamentos personalizados.'
Usage: '[jogador]'
DoneOthers: <light_gray>Abriu o GUI para o jogador <light_yellow>%player_name%</light_yellow>.</light_gray>
GetFuel:
Desc: 'Obtém um item de recarga.'
Usage: <enchant> [quantidade]
Done: <light_gray>Você recebeu <light_yellow>x%amount% %name%</light_yellow>.</light_gray>
Enchant:
Usage: <enchant> <nivel> [jogador] [slot]
Desc: 'Encanta o item na mão.'
Done:
Self: <light_gray>O encantamento de <light_yellow>%item%</light_yellow> é <light_yellow>%enchant% %level%</light_yellow>!</light_gray>
Others: <light_gray>O encantamento de <light_yellow>%item%</light_yellow> do jogador <light_yellow>%player_display_name%</light_yellow> é <light_yellow>%enchant% %level%</light_yellow>!</light_gray>
Error:
NoItem: <red>Não há item para encantar!</red>
Book:
Usage: <jogador> <enchant> <nivel>
Desc: 'Concede um livro de encantamento personalizado.'
Done: <light_gray>Concedeu o livro de encantamento <light_yellow>%enchant%</light_yellow> para <light_yellow>%player_display_name%</light_yellow>.</light_gray>
RarityBook:
Usage: <jogador> <nivel> <raridade>
Desc: 'Concede um livro de encantamento com uma raridade específica.'
Done: <light_gray>Concedeu o livro de encantamento <light_yellow>%name%</light_yellow> para <light_yellow>%player_display_name%</light_yellow>.</light_gray>
Error:
InvalidEnchantment: <red>Parâmetro inválido.</red>
InvalidRarity: <red>Tipo de raridade inválido!</red>
ItemCategory:
HELMET: 'Capacete'
CHESTPLATE: 'Peitoral'
LEGGINGS: 'Calças'
BOOTS: 'Botas'
ELYTRA: 'Elytra'
SWORD: 'Espada'
TRIDENT: 'Tridente'
AXE: 'Machado'
BOW: 'Arco'
CROSSBOW: 'Besta'
HOE: 'Enxada'
PICKAXE: 'Picareta'
SHOVEL: 'Pá'
FISHING_ROD: 'Vara de pesca'
SHIELD: 'Escudo'
TOOL: 'Ferramenta'
EnchantmentTarget:
ALL: 'Todos'
ARMOR: 'Armadura'
ARMOR_FEET: 'Botas'
ARMOR_LEGS: 'Calças'
ARMOR_TORSO: 'Peitoral'
ARMOR_HEAD: 'Capacete'
WEAPON: 'Arma'
TOOL: 'Ferramenta'
BOW: 'Arco'
FISHING_ROD: 'Vara de pesca'
BREAKABLE: 'Durabilidade'
WEARABLE: 'Vestível'
TRIDENT: 'Tridente'
CROSSBOW: 'Besta'
VANISHABLE: 'Desaparecível'
DistributionWay:
ENCHANTING: 'Encantamento'
VILLAGER: 'Aldeão'
LOOT_GENERATION: 'Geração de saque'
FISHING: 'Pesca'
MOB_EQUIPMENT: 'Equipamento de mob'
Rarity:
COMMON: '<white>Comum</white>'
UNCOMMON: '<light_green>Incomum</light_green>'
RARE: '<purple>Raro</purple>'
Command:
List:
Desc: 'Lista de encantamentos personalizados.'
Usage: '[jogador]'
DoneOthers: <light_gray>Abriu o GUI para o jogador <light_yellow>%player_name%</light_yellow>.</light_gray>
GetFuel:
Desc: 'Obtém um item de recarga.'
Usage: <enchant> [quantidade]
Done: <light_gray>Você recebeu <light_yellow>x%amount% %name%</light_yellow>.</light_gray>
Enchant:
Usage: <enchant> <nivel> [jogador] [slot]
Desc: 'Encanta o item na mão.'
Done:
Self: <light_gray>O encantamento de <light_yellow>%item%</light_yellow> é <light_yellow>%enchant% %level%</light_yellow>!</light_gray>
Others: <light_gray>O encantamento de <light_yellow>%item%</light_yellow> do jogador <light_yellow>%player_display_name%</light_yellow> é <light_yellow>%enchant% %level%</light_yellow>!</light_gray>
Error:
NoItem: <red>Não há item para encantar!</red>
Book:
Usage: <jogador> <enchant> <nivel>
Desc: 'Concede um livro de encantamento personalizado.'
Done: <light_gray>Concedeu o livro de encantamento <light_yellow>%enchant%</light_yellow> para <light_yellow>%player_display_name%</light_yellow>.</light_gray>
RarityBook:
Usage: <jogador> <nivel> <raridade>
Desc: 'Concede um livro de encantamento com uma raridade específica.'
Done: <light_gray>Concedeu o livro de encantamento <light_yellow>%name%</light_yellow> para <light_yellow>%player_display_name%</light_yellow>.</light_gray>
Error:
InvalidEnchantment: <red>Parâmetro inválido.</red>
InvalidRarity: <red>Tipo de raridade inválido!</red>
ItemCategory:
HELMET: 'Capacete'
CHESTPLATE: 'Peitoral'
LEGGINGS: 'Calças'
BOOTS: 'Botas'
ELYTRA: 'Elytra'
SWORD: 'Espada'
TRIDENT: 'Tridente'
AXE: 'Machado'
BOW: 'Arco'
CROSSBOW: 'Besta'
HOE: 'Enxada'
PICKAXE: 'Picareta'
SHOVEL: 'Pá'
FISHING_ROD: 'Vara de pesca'
SHIELD: 'Escudo'
TOOL: 'Ferramenta'
EnchantmentTarget:
ALL: 'Todos'
ARMOR: 'Armadura'
ARMOR_FEET: 'Botas'
ARMOR_LEGS: 'Calças'
ARMOR_TORSO: 'Peitoral'
ARMOR_HEAD: 'Capacete'
WEAPON: 'Arma'
TOOL: 'Ferramenta'
BOW: 'Arco'
FISHING_ROD: 'Vara de pesca'
BREAKABLE: 'Durabilidade'
WEARABLE: 'Vestível'
TRIDENT: 'Tridente'
CROSSBOW: 'Besta'
VANISHABLE: 'Desaparecível'
DistributionWay:
ENCHANTING: 'Encantamento'
VILLAGER: 'Aldeão'
LOOT_GENERATION: 'Geração de saque'
FISHING: 'Pesca'
MOB_EQUIPMENT: 'Equipamento de mob'
Rarity:
COMMON: '<white>Comum</white>'
UNCOMMON: '<light_green>Incomum</light_green>'
RARE: '<purple>Raro</purple>'
VERY_RARE: '<red>Mítico</red>'

View File

@ -6,7 +6,7 @@
<parent>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>ExcellentEnchants</artifactId>
<version>4.3.1</version>
<version>4.3.2</version>
</parent>
<artifactId>MC_1_21</artifactId>
@ -28,13 +28,13 @@
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>API</artifactId>
<version>4.3.1</version>
<version>4.3.2</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>NMS</artifactId>
<version>4.3.1</version>
<version>4.3.2</version>
</dependency>
</dependencies>

View File

@ -57,7 +57,6 @@ import su.nightexpress.excellentenchants.api.enchantment.bridge.FlameWalker;
import su.nightexpress.excellentenchants.nms.EnchantNMS;
import su.nightexpress.nightcore.NightPlugin;
import su.nightexpress.nightcore.util.Reflex;
import su.nightexpress.nightcore.util.random.Rnd;
import su.nightexpress.nightcore.util.text.NightMessage;
import java.util.*;
@ -407,7 +406,8 @@ public class Internal_1_21 implements EnchantNMS {
blocks.add(CraftBlock.at(world, posNear));
}
blocks.forEach(block -> FlameWalker.addBlock(block, Rnd.getDouble(flameWalker.getBlockDecayTime(level)) + 1));
//blocks.forEach(block -> FlameWalker.addBlock(block, Rnd.getDouble(flameWalker.getBlockDecayTime(level)) + 1));
blocks.forEach(block -> flameWalker.addBlock(block, level));
return !blocks.isEmpty();
}

View File

@ -6,7 +6,7 @@
<parent>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>ExcellentEnchants</artifactId>
<version>4.3.1</version>
<version>4.3.2</version>
</parent>
<artifactId>MC_1_21_3</artifactId>
@ -28,13 +28,13 @@
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>API</artifactId>
<version>4.3.1</version>
<version>4.3.2</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>NMS</artifactId>
<version>4.3.1</version>
<version>4.3.2</version>
</dependency>
</dependencies>

View File

@ -53,7 +53,6 @@ import su.nightexpress.excellentenchants.api.enchantment.*;
import su.nightexpress.excellentenchants.api.enchantment.bridge.FlameWalker;
import su.nightexpress.nightcore.NightPlugin;
import su.nightexpress.nightcore.util.Reflex;
import su.nightexpress.nightcore.util.random.Rnd;
import su.nightexpress.nightcore.util.text.NightMessage;
import java.lang.reflect.Method;
@ -482,7 +481,8 @@ public class Internal_1_21_3 implements EnchantNMS {
blocks.add(CraftBlock.at(world, posNear));
}
blocks.forEach(block -> FlameWalker.addBlock(block, Rnd.getDouble(flameWalker.getBlockDecayTime(level)) + 1));
//blocks.forEach(block -> FlameWalker.addBlock(block, Rnd.getDouble(flameWalker.getBlockDecayTime(level)) + 1));
blocks.forEach(block -> flameWalker.addBlock(block, level));
return !blocks.isEmpty();
}

79
MC_1_21_4/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.3.2</version>
</parent>
<artifactId>MC_1_21_4</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.21.4-R0.1-SNAPSHOT</version>
<classifier>remapped-mojang</classifier>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>API</artifactId>
<version>4.3.2</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>NMS</artifactId>
<version>4.3.2</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.21.4-R0.1-SNAPSHOT:txt:maps-mojang</srgIn>
<reverse>true</reverse>
<remappedDependencies>org.spigotmc:spigot:1.21.4-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.21.4-R0.1-SNAPSHOT:csrg:maps-spigot</srgIn>
<remappedDependencies>org.spigotmc:spigot:1.21.4-R0.1-SNAPSHOT:jar:remapped-obf</remappedDependencies>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

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.3.1</version>
</parent>
<artifactId>MC_1_21_4</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.21.4-R0.1-SNAPSHOT</version>
<classifier>remapped-mojang</classifier>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>API</artifactId>
<version>4.3.1</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>NMS</artifactId>
<version>4.3.1</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.21.4-R0.1-SNAPSHOT:txt:maps-mojang</srgIn>
<reverse>true</reverse>
<remappedDependencies>org.spigotmc:spigot:1.21.4-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.21.4-R0.1-SNAPSHOT:csrg:maps-spigot</srgIn>
<remappedDependencies>org.spigotmc:spigot:1.21.4-R0.1-SNAPSHOT:jar:remapped-obf</remappedDependencies>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,504 @@
package su.nightexpress.excellentenchants.nms;
import net.minecraft.core.*;
import net.minecraft.core.component.DataComponentMap;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ClientboundAnimatePacket;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.tags.EnchantmentTags;
import net.minecraft.tags.TagKey;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.EquipmentSlotGroup;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.projectile.FishingHook;
import net.minecraft.world.flag.FeatureFlags;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.enchantment.Enchantment;
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.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_21_R3.CraftEquipmentSlot;
import org.bukkit.craftbukkit.v1_21_R3.CraftServer;
import org.bukkit.craftbukkit.v1_21_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_21_R3.block.CraftBlock;
import org.bukkit.craftbukkit.v1_21_R3.block.CraftBlockType;
import org.bukkit.craftbukkit.v1_21_R3.enchantments.CraftEnchantment;
import org.bukkit.craftbukkit.v1_21_R3.entity.CraftFishHook;
import org.bukkit.craftbukkit.v1_21_R3.entity.CraftLivingEntity;
import org.bukkit.craftbukkit.v1_21_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_21_R3.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_21_R3.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_21_R3.util.CraftChatMessage;
import org.bukkit.craftbukkit.v1_21_R3.util.CraftNamespacedKey;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.ConfigBridge;
import su.nightexpress.excellentenchants.api.enchantment.*;
import su.nightexpress.excellentenchants.api.enchantment.bridge.FlameWalker;
import su.nightexpress.nightcore.NightPlugin;
import su.nightexpress.nightcore.util.Reflex;
import su.nightexpress.nightcore.util.text.NightMessage;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.BiConsumer;
public class Internal_1_21_4 implements EnchantNMS {
private static final MinecraftServer SERVER;
private static final MappedRegistry<Enchantment> ENCHANTS;
private static final MappedRegistry<Item> ITEMS;
private static final String REGISTRY_FROZEN_TAGS_FIELD = "j"; // frozenTags
private static final String REGISTRY_ALL_TAGS_FIELD = "k"; // allTags
private static final String TAG_SET_UNBOUND_METHOD = "a"; // .unbound()
private static final String TAG_SET_MAP_FIELD = "val$map";
static {
SERVER = ((CraftServer) Bukkit.getServer()).getServer();
ENCHANTS = (MappedRegistry<Enchantment>) SERVER.registryAccess().lookup(Registries.ENCHANTMENT).orElseThrow();
ITEMS = (MappedRegistry<Item>) SERVER.registryAccess().lookup(Registries.ITEM).orElseThrow();
}
private final NightPlugin plugin;
public Internal_1_21_4(@NotNull NightPlugin plugin) {
this.plugin = plugin;
}
@NotNull
private static <T> ResourceKey<T> getResourceKey(@NotNull Registry<T> registry, @NotNull String name) {
return ResourceKey.create(registry.key(), ResourceLocation.withDefaultNamespace(name));
}
private static <T> TagKey<T> getTagKey(@NotNull Registry<T> registry, @NotNull String name) {
return TagKey.create(registry.key(), ResourceLocation.withDefaultNamespace(name));
}
@SuppressWarnings("unchecked")
@NotNull
private static <T> Map<TagKey<T>, HolderSet.Named<T>> getFrozenTags(@NotNull MappedRegistry<T> registry) {
return (Map<TagKey<T>, HolderSet.Named<T>>) Reflex.getFieldValue(registry, REGISTRY_FROZEN_TAGS_FIELD);
}
@NotNull
private static <T> Object getAllTags(@NotNull MappedRegistry<T> registry) {
return Reflex.getFieldValue(registry, REGISTRY_ALL_TAGS_FIELD);
}
@SuppressWarnings("unchecked")
@NotNull
private static <T> Map<TagKey<T>, HolderSet.Named<T>> getTagsMap(@NotNull Object tagSet) {
// new HashMap, because original is ImmutableMap.
return new HashMap<>((Map<TagKey<T>, HolderSet.Named<T>>) Reflex.getFieldValue(tagSet, TAG_SET_MAP_FIELD));
}
@Override
public void unfreezeRegistry() {
unfreeze(ENCHANTS);
unfreeze(ITEMS);
}
@Override
public void freezeRegistry() {
freeze(ITEMS);
freeze(ENCHANTS);
//this.displayTags();
}
private static <T> void unfreeze(@NotNull MappedRegistry<T> registry) {
Reflex.setFieldValue(registry, "l", false); // MappedRegistry#frozen
Reflex.setFieldValue(registry, "m", new IdentityHashMap<>()); // MappedRegistry#unregisteredIntrusiveHolders
}
private static <T> void freeze(@NotNull MappedRegistry<T> registry) {
// Get original TagSet object of the registry before unbound.
// We MUST keep original TagSet object and only modify an inner map object inside it.
// Otherwise it will throw an Network Error on client join because of 'broken' tags that were bound to other TagSet object.
Object tagSet = getAllTags(registry);
// Get a copy of original TagSet's tags map.
Map<TagKey<T>, HolderSet.Named<T>> tagsMap = getTagsMap(tagSet);
// Get 'frozenTags' map with all tags of the registry.
Map<TagKey<T>, HolderSet.Named<T>> frozenTags = getFrozenTags(registry);
// Here we add all registered and bound vanilla tags to the 'frozenTags' map for further freeze & bind.
// For some reason 'frozenTags' map does not contain all the tags, so some of them will be absent if not added back here
// and result in broken gameplay features.
tagsMap.forEach(frozenTags::putIfAbsent);
// We MUST 'unbound' the registry tags to be able to call .freeze() method of it.
// Otherwise it will throw an error saying tags are not bound.
unbound(registry);
// This method will register all tags from the 'frozenTags' map and assign a new TagSet object to the 'allTags' field of registry.
// But we MUST replace the 'allTags' field value with the original (before unbound) TagSet object to prevent Network Error for clients.
registry.freeze();
// Here we need to put in 'tagsMap' map of TagSet object all new/custom registered tags.
// Otherwise it will cause Network Error because custom tags are not present in the TagSet tags map.
// frozenTags.forEach((k, v) -> {
// if (!tagsMap.containsKey(k)) {
// System.out.println("ADD MISSING NEW TAG TO " + registry + ": " + k);
// tagsMap.put(k, v);
// }
// });
frozenTags.forEach(tagsMap::putIfAbsent);
// Update inner tags map of the TagSet object that is 'allTags' field of the registry.
Reflex.setFieldValue(tagSet, TAG_SET_MAP_FIELD, tagsMap);
// Assign original TagSet object with modified tags map to the 'allTags' field of the registry.
Reflex.setFieldValue(registry, REGISTRY_ALL_TAGS_FIELD, tagSet);
}
private static <T> void unbound(@NotNull MappedRegistry<T> registry) {
Class<?> tagSetClass = Reflex.getInnerClass(MappedRegistry.class.getName(), "TagSet");
Method unboundMethod = Reflex.getMethod(tagSetClass, TAG_SET_UNBOUND_METHOD);
Object unboundTagSet = Reflex.invokeMethod(unboundMethod, registry); // new TagSet object.
Reflex.setFieldValue(registry, REGISTRY_ALL_TAGS_FIELD, unboundTagSet);
}
//VanillaRegistries.createLookup().lookup(Registries.ENCHANTMENT).get();
// Create Enchantment reference.
//Holder.Reference<Enchantment> reference = Holder.Reference.createStandAlone(ENCHANTMENT_REGISTRY.holderOwner(), key);
// Bind enchantment value to the reference (or it will be null).
//Reflex.setFieldValue(reference, "e", enchantment);
@Override
public void addExclusives(@NotNull CustomEnchantment customEnchantment) {
ResourceKey<Enchantment> enchantKey = getResourceKey(ENCHANTS, customEnchantment.getId());
Enchantment enchantment = ENCHANTS.getValue(enchantKey);
if (enchantment == null) {
this.plugin.error(customEnchantment.getId() + ": Could not set exclusive item list. Enchantment is not registered.");
return;
}
TagKey<Enchantment> exclusivesKey = getTagKey(ENCHANTS, "exclusive_set/" + customEnchantment.getId());
customEnchantment.getDefinition().getConflicts().forEach(enchantId -> {
ResourceKey<Enchantment> conflictKey = getResourceKey(ENCHANTS, enchantId);
Holder.Reference<Enchantment> reference = ENCHANTS.get(conflictKey).orElse(null);
if (reference == null) return;
addInTag(exclusivesKey, reference);
});
}
@Override
@NotNull
public org.bukkit.enchantments.Enchantment registerEnchantment(@NotNull CustomEnchantment customEnchantment) {
Definition customDefinition = customEnchantment.getDefinition();
Component display = CraftChatMessage.fromJSON(NightMessage.asJson(customEnchantment.getFormattedName()));
HolderSet.Named<Item> supportedItems = createItemsSet("enchant_supported", customEnchantment, customDefinition.getSupportedItems());
HolderSet.Named<Item> primaryItems = createItemsSet("enchant_primary", customEnchantment, customDefinition.getPrimaryItems());
int weight = customDefinition.getRarity().getWeight();
int maxLevel = customDefinition.getMaxLevel();
Enchantment.Cost minCost = nmsCost(customDefinition.getMinCost());
Enchantment.Cost maxCost = nmsCost(customDefinition.getMaxCost());
int anvilCost = customDefinition.getAnvilCost();
EquipmentSlotGroup[] slots = nmsSlots(customDefinition);
Enchantment.EnchantmentDefinition definition = Enchantment.definition(supportedItems, primaryItems, weight, maxLevel, minCost, maxCost, anvilCost, slots);
HolderSet<Enchantment> exclusiveSet = createExclusiveSet(customEnchantment);
DataComponentMap.Builder builder = DataComponentMap.builder();
Enchantment enchantment = new Enchantment(display, definition, exclusiveSet, builder.build());
// Create a new Holder for the custom enchantment.
Holder.Reference<Enchantment> reference = ENCHANTS.createIntrusiveHolder(enchantment);
// Add it into Registry.
Registry.register(ENCHANTS, customEnchantment.getId(), enchantment);
// Now it's possible to add/remove it from vanilla tags since we have a valid, registered Reference.
this.setupDistribution(customEnchantment, reference);
// Return the bukkit mirror.
return CraftEnchantment.minecraftToBukkit(enchantment);
}
// public void displayTags() {
// displayTag(EnchantmentTags.CURSE);
// displayTag(EnchantmentTags.TREASURE);
// displayTag(EnchantmentTags.NON_TREASURE);
// displayTag(EnchantmentTags.IN_ENCHANTING_TABLE);
// displayTag(EnchantmentTags.DOUBLE_TRADE_PRICE);
// displayTag(EnchantmentTags.ON_TRADED_EQUIPMENT);
// displayTag(EnchantmentTags.ON_MOB_SPAWN_EQUIPMENT);
// displayTag(EnchantmentTags.ON_RANDOM_LOOT);
// displayTag(EnchantmentTags.ARMOR_EXCLUSIVE);
// displayTag(EnchantmentTags.TRADEABLE);
// }
//
// public void displayTag(TagKey<Enchantment> tagKey) {
// ENCHANTS.get(tagKey).ifPresent(holders -> {
// System.out.println(tagKey + ": " + holders.stream().map(Holder::value).toList());
// });
// System.out.println(" ");
// }
private void setupDistribution(@NotNull CustomEnchantment customEnchantment, @NotNull Holder.Reference<Enchantment> reference) {
boolean experimentalTrades = SERVER.getWorldData().enabledFeatures().contains(FeatureFlags.TRADE_REBALANCE);
Distribution distribution = customEnchantment.getDistribution();
// Any enchantment can be treasure.
if (distribution.isTreasure()) {
addInTag(EnchantmentTags.TREASURE, reference);
addInTag(EnchantmentTags.DOUBLE_TRADE_PRICE, reference);
}
else addInTag(EnchantmentTags.NON_TREASURE, reference);
// Any enchantment can be on random loot.
if (distribution.isOnRandomLoot() && ConfigBridge.isGlobalDistRandomLoot()) {
addInTag(EnchantmentTags.ON_RANDOM_LOOT, reference);
}
// Only non-treasure enchantments should be on mob equipment, traded equipment and non-rebalanced trades.
if (!distribution.isTreasure()) {
if (distribution.isOnMobSpawnEquipment() && ConfigBridge.isGlobalDistMobEquipment()) {
addInTag(EnchantmentTags.ON_MOB_SPAWN_EQUIPMENT, reference);
}
if (distribution.isOnTradedEquipment() && ConfigBridge.isGlobalDistTradeEquipment()) {
addInTag(EnchantmentTags.ON_TRADED_EQUIPMENT, reference);
}
}
// Any enchantment can be tradable.
if (experimentalTrades) {
if (distribution.isTradable() && ConfigBridge.isGlobalDistTrading()) {
distribution.getTrades().forEach(tradeType -> {
addInTag(getTradeKey(tradeType), reference);
});
}
}
else {
if (distribution.isTradable() && ConfigBridge.isGlobalDistTrading()) {
addInTag(EnchantmentTags.TRADEABLE, reference);
}
else removeFromTag(EnchantmentTags.TRADEABLE, reference);
}
if (customEnchantment.isCurse()) {
addInTag(EnchantmentTags.CURSE, reference);
}
else {
// Only non-curse and non-treasure enchantments should go in enchanting table.
if (!distribution.isTreasure()) {
if (distribution.isDiscoverable() && ConfigBridge.isGlobalDistEnchanting()) {
addInTag(EnchantmentTags.IN_ENCHANTING_TABLE, reference);
}
else removeFromTag(EnchantmentTags.IN_ENCHANTING_TABLE, reference);
}
}
}
private void addInTag(@NotNull TagKey<Enchantment> tagKey, @NotNull Holder.Reference<Enchantment> reference) {
modfiyTag(ENCHANTS, tagKey, reference, List::add);
}
private void removeFromTag(@NotNull TagKey<Enchantment> tagKey, @NotNull Holder.Reference<Enchantment> reference) {
modfiyTag(ENCHANTS, tagKey, reference, List::remove);
}
private <T> void modfiyTag(@NotNull MappedRegistry<T> registry,
@NotNull TagKey<T> tagKey,
@NotNull Holder.Reference<T> reference,
@NotNull BiConsumer<List<Holder<T>>, Holder.Reference<T>> consumer) {
HolderSet.Named<T> holders = registry.get(tagKey).orElse(null);
if (holders == null) {
this.plugin.warn(tagKey + ": Could not modify HolderSet. HolderSet is NULL.");
return;
}
List<Holder<T>> contents = new ArrayList<>(holders.stream().toList());
consumer.accept(contents, reference);
registry.bindTag(tagKey, contents);
}
@NotNull
private static HolderSet.Named<Item> createItemsSet(@NotNull String prefix, @NotNull CustomEnchantment customEnchantment, @NotNull ItemsCategory category) {
TagKey<Item> customKey = getTagKey(ITEMS, prefix + "/" + customEnchantment.getId());
List<Holder<Item>> holders = new ArrayList<>();
category.getMaterials().forEach(material -> {
ResourceLocation location = CraftNamespacedKey.toMinecraft(material.getKey());
Holder.Reference<Item> holder = ITEMS.get(location).orElse(null);
if (holder == null) return;
holders.add(holder);
});
// Creates new tag, puts it in the 'frozenTags' map and binds holders to it.
ITEMS.bindTag(customKey, holders);
return getFrozenTags(ITEMS).get(customKey);
}
@NotNull
private static HolderSet.Named<Enchantment> createExclusiveSet(@NotNull CustomEnchantment customEnchantment) {
TagKey<Enchantment> customKey = getTagKey(ENCHANTS, "exclusive_set/" + customEnchantment.getId());
List<Holder<Enchantment>> holders = new ArrayList<>();
// Creates new tag, puts it in the 'frozenTags' map and binds holders to it.
ENCHANTS.bindTag(customKey, holders);
return getFrozenTags(ENCHANTS).get(customKey);
}
// private static HolderSet.Named<Enchantment> getExclusiveSet(@NotNull CustomEnchantment data) {
// TagKey<Enchantment> customKey = TagKey.create(Registries.ENCHANTMENT, ResourceLocation.withDefaultNamespace("exclusives/" + data.getId()));
// return ENCHANTS.get(customKey).orElse(null);
// }
@NotNull
private static TagKey<Enchantment> getTradeKey(@NotNull TradeType tradeType) {
return switch (tradeType) {
case DESERT_COMMON -> EnchantmentTags.TRADES_DESERT_COMMON;
case DESERT_SPECIAL -> EnchantmentTags.TRADES_DESERT_SPECIAL;
case PLAINS_COMMON -> EnchantmentTags.TRADES_PLAINS_COMMON;
case PLAINS_SPECIAL -> EnchantmentTags.TRADES_PLAINS_SPECIAL;
case SAVANNA_COMMON -> EnchantmentTags.TRADES_SAVANNA_COMMON;
case SAVANNA_SPECIAL -> EnchantmentTags.TRADES_SAVANNA_SPECIAL;
case JUNGLE_COMMON -> EnchantmentTags.TRADES_JUNGLE_COMMON;
case JUNGLE_SPECIAL -> EnchantmentTags.TRADES_JUNGLE_SPECIAL;
case SNOW_COMMON -> EnchantmentTags.TRADES_SNOW_COMMON;
case SNOW_SPECIAL -> EnchantmentTags.TRADES_SNOW_SPECIAL;
case SWAMP_COMMON -> EnchantmentTags.TRADES_SWAMP_COMMON;
case SWAMP_SPECIAL -> EnchantmentTags.TRADES_SWAMP_SPECIAL;
case TAIGA_COMMON -> EnchantmentTags.TRADES_TAIGA_COMMON;
case TAIGA_SPECIAL -> EnchantmentTags.TRADES_TAIGA_SPECIAL;
};
}
@NotNull
private static Enchantment.Cost nmsCost(@NotNull Cost cost) {
return new Enchantment.Cost(cost.base(), cost.perLevel());
}
@SuppressWarnings("UnstableApiUsage")
private static EquipmentSlotGroup[] nmsSlots(@NotNull Definition definition) {
EquipmentSlot[] slots = definition.getSupportedItems().getSlots();
EquipmentSlotGroup[] nmsSlots = new EquipmentSlotGroup[slots.length];
for (int index = 0; index < nmsSlots.length; index++) {
EquipmentSlot bukkitSlot = slots[index];
nmsSlots[index] = CraftEquipmentSlot.getNMSGroup(bukkitSlot.getGroup());
}
return nmsSlots;
}
@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);
}
@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
public boolean handleFlameWalker(@NotNull FlameWalker flameWalker, @NotNull LivingEntity bukkitEntity, int level) {
Entity entity = ((CraftLivingEntity) bukkitEntity).getHandle();
BlockPos pos = entity.blockPosition();
Level world = entity.level();
int radius = (int) flameWalker.getRadius().getValue(level);
BlockState magmaState = 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 aboveLava = world.getBlockState(posAbove);
BlockState lavaState = world.getBlockState(posNear);
if (!aboveLava.isAir()) continue;
if (!lavaState.getBlock().equals(Blocks.LAVA)) continue;
if (lavaState.getValue(LiquidBlock.LEVEL) != 0) continue;
if (!magmaState.canSurvive(world, posNear)) continue;
if (!world.isUnobstructed(magmaState, posNear, CollisionContext.empty())) continue;
if (!CraftEventFactory.handleBlockFormEvent(world, posNear, magmaState, entity)) continue;
blocks.add(CraftBlock.at(world, posNear));
}
blocks.forEach(block -> flameWalker.addBlock(block, level));
return !blocks.isEmpty();
}
@NotNull
public org.bukkit.entity.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 (org.bukkit.entity.Item) itemEntity.getBukkitEntity();
}
}

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>ExcellentEnchants</artifactId>
<groupId>su.nightexpress.excellentenchants</groupId>
<version>4.3.1</version>
<version>4.3.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -34,7 +34,7 @@
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>API</artifactId>
<version>4.3.1</version>
<version>4.3.2</version>
</dependency>
</dependencies>

View File

@ -7,13 +7,14 @@
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>ExcellentEnchants</artifactId>
<packaging>pom</packaging>
<version>4.3.1</version>
<version>4.3.2</version>
<modules>
<module>API</module>
<module>Core</module>
<module>NMS</module>
<module>MC_1_21</module>
<module>MC_1_21_3</module>
<module>MC_1_21_4</module>
</modules>
<properties>
@ -26,7 +27,7 @@
<dependency>
<groupId>su.nightexpress.nightcore</groupId>
<artifactId>nightcore</artifactId>
<version>2.7.0</version>
<version>2.7.3</version>
</dependency>
</dependencies>