This commit is contained in:
nulli0n 2024-11-04 05:51:12 +05:00
parent 4399137733
commit 9b6647c709
10 changed files with 614 additions and 19 deletions

4
.gitignore vendored
View File

@ -8,4 +8,6 @@
/API/target/
/API/pom.xml.versionsBackup
/MC_1_21/target/
/MC_1_21/pom.xml.versionsBackup
/MC_1_21/pom.xml.versionsBackup
/MC_1_21_3/target/
/MC_1_21_3/pom.xml.versionsBackup

View File

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

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>ExcellentEnchants</artifactId>
<groupId>su.nightexpress.excellentenchants</groupId>
<version>4.2.2</version>
<version>4.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -82,26 +82,32 @@
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.11.2</version>
<version>2.11.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>API</artifactId>
<version>4.2.2</version>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>NMS</artifactId>
<version>4.2.2</version>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>MC_1_21_3</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>MC_1_21</artifactId>
<version>4.2.2</version>
<version>4.3.0</version>
</dependency>
</dependencies>

View File

@ -16,6 +16,7 @@ import su.nightexpress.excellentenchants.hook.impl.PacketEventsHook;
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.rarity.RarityManager;
import su.nightexpress.excellentenchants.registry.EnchantRegistry;
import su.nightexpress.nightcore.NightPlugin;
@ -81,12 +82,13 @@ public class EnchantsPlugin extends NightPlugin implements ImprovedCommands {
}
private boolean loadInternals() {
if (Version.getCurrent() == Version.MC_1_21) {
this.enchantNMS = new Internal_1_21(this);
return true;
}
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);
default -> null;
};
return false;
return this.enchantNMS != null;
}
private void loadCommands() {

View File

@ -221,6 +221,7 @@ public class EnchantRegistry extends SimpleManager<EnchantsPlugin> {
private void register(@NotNull String id, @NotNull Function<File, GameEnchantment> supplier) {
if (Config.ENCHANTMENTS_DISABLED_LIST.get().contains(id)) return;
//if (true) return;
File file = new File(plugin.getDataFolder() + Config.DIR_ENCHANTS, id + ".yml");
FileUtil.create(file);

View File

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

79
MC_1_21_3/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.0</version>
</parent>
<artifactId>MC_1_21_3</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.3-R0.1-SNAPSHOT</version>
<classifier>remapped-mojang</classifier>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>API</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>NMS</artifactId>
<version>4.3.0</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.3-R0.1-SNAPSHOT:txt:maps-mojang</srgIn>
<reverse>true</reverse>
<remappedDependencies>org.spigotmc:spigot:1.21.3-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.3-R0.1-SNAPSHOT:csrg:maps-spigot</srgIn>
<remappedDependencies>org.spigotmc:spigot:1.21.3-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_R2.CraftEquipmentSlot;
import org.bukkit.craftbukkit.v1_21_R2.CraftServer;
import org.bukkit.craftbukkit.v1_21_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_21_R2.block.CraftBlock;
import org.bukkit.craftbukkit.v1_21_R2.block.CraftBlockType;
import org.bukkit.craftbukkit.v1_21_R2.enchantments.CraftEnchantment;
import org.bukkit.craftbukkit.v1_21_R2.entity.CraftFishHook;
import org.bukkit.craftbukkit.v1_21_R2.entity.CraftLivingEntity;
import org.bukkit.craftbukkit.v1_21_R2.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_21_R2.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_21_R2.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_21_R2.util.CraftChatMessage;
import org.bukkit.craftbukkit.v1_21_R2.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.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;
import java.util.*;
import java.util.function.BiConsumer;
public class Internal_1_21_3 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_3(@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()) {
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()) {
addInTag(EnchantmentTags.ON_MOB_SPAWN_EQUIPMENT, reference);
}
if (distribution.isOnTradedEquipment()) {
addInTag(EnchantmentTags.ON_TRADED_EQUIPMENT, reference);
}
}
// Any enchantment can be tradable.
if (experimentalTrades) {
if (distribution.isTradable()) {
distribution.getTrades().forEach(tradeType -> {
addInTag(getTradeKey(tradeType), reference);
});
}
}
else {
if (distribution.isTradable()) {
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()) {
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, Rnd.getDouble(flameWalker.getBlockDecayTime(level)) + 1));
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.2.2</version>
<version>4.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -34,7 +34,7 @@
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>API</artifactId>
<version>4.2.2</version>
<version>4.3.0</version>
</dependency>
</dependencies>

View File

@ -7,12 +7,13 @@
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>ExcellentEnchants</artifactId>
<packaging>pom</packaging>
<version>4.2.2</version>
<version>4.3.0</version>
<modules>
<module>API</module>
<module>Core</module>
<module>NMS</module>
<module>MC_1_21</module>
<module>MC_1_21_3</module>
</modules>
<properties>
@ -25,7 +26,7 @@
<dependency>
<groupId>su.nightexpress.nightcore</groupId>
<artifactId>nightcore</artifactId>
<version>2.6.3</version>
<version>2.7.0</version>
</dependency>
</dependencies>