diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index 0bec09f6b..2f037484f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -28,11 +28,13 @@ import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; +import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.FoodLevelChangeEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; @@ -398,4 +400,17 @@ public class ItemEventListener implements Listener { } return false; } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) + public void onEntityDamage(EntityDamageEvent event) { + if (event.getEntityType() == EntityType.ITEM && event.getEntity() instanceof org.bukkit.entity.Item item) { + Optional.ofNullable(this.plugin.itemManager().wrap(item.getItemStack())) + .flatMap(Item::getCustomItem) + .ifPresent(it -> { + if (it.settings().invulnerable().contains(DamageCauseUtils.fromBukkit(event.getCause()))) { + event.setCancelled(true); + } + }); + } + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DamageCauseUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DamageCauseUtils.java new file mode 100644 index 000000000..752c23915 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DamageCauseUtils.java @@ -0,0 +1,89 @@ +package net.momirealms.craftengine.bukkit.util; + +import net.momirealms.craftengine.core.util.DamageCause; +import org.bukkit.event.entity.EntityDamageEvent; + +public class DamageCauseUtils { + + private DamageCauseUtils() {} + + @SuppressWarnings("deprecation") + public static EntityDamageEvent.DamageCause toBukkit(DamageCause cause) { + return switch (cause) { + case BLOCK_EXPLOSION -> EntityDamageEvent.DamageCause.BLOCK_EXPLOSION; + case CAMPFIRE -> EntityDamageEvent.DamageCause.CAMPFIRE; + case CONTACT -> EntityDamageEvent.DamageCause.CONTACT; + case CRAMMING -> EntityDamageEvent.DamageCause.CRAMMING; + case CUSTOM -> EntityDamageEvent.DamageCause.CUSTOM; + case DROWNING -> EntityDamageEvent.DamageCause.DROWNING; + case DRYOUT -> EntityDamageEvent.DamageCause.DRYOUT; + case ENTITY_ATTACK -> EntityDamageEvent.DamageCause.ENTITY_ATTACK; + case ENTITY_EXPLOSION -> EntityDamageEvent.DamageCause.ENTITY_EXPLOSION; + case ENTITY_SWEEP_ATTACK -> EntityDamageEvent.DamageCause.ENTITY_SWEEP_ATTACK; + case FALL -> EntityDamageEvent.DamageCause.FALL; + case FALLING_BLOCK -> EntityDamageEvent.DamageCause.FALLING_BLOCK; + case FIRE -> EntityDamageEvent.DamageCause.FIRE; + case FIRE_TICK -> EntityDamageEvent.DamageCause.FIRE_TICK; + case FLY_INTO_WALL -> EntityDamageEvent.DamageCause.FLY_INTO_WALL; + case FREEZE -> EntityDamageEvent.DamageCause.FREEZE; + case HOT_FLOOR -> EntityDamageEvent.DamageCause.HOT_FLOOR; + case KILL -> EntityDamageEvent.DamageCause.KILL; + case LAVA -> EntityDamageEvent.DamageCause.LAVA; + case LIGHTNING -> EntityDamageEvent.DamageCause.LIGHTNING; + case MAGIC -> EntityDamageEvent.DamageCause.MAGIC; + case MELTING -> EntityDamageEvent.DamageCause.MELTING; + case POISON -> EntityDamageEvent.DamageCause.POISON; + case PROJECTILE -> EntityDamageEvent.DamageCause.PROJECTILE; + case SONIC_BOOM -> EntityDamageEvent.DamageCause.SONIC_BOOM; + case STARVATION -> EntityDamageEvent.DamageCause.STARVATION; + case SUFFOCATION -> EntityDamageEvent.DamageCause.SUFFOCATION; + case SUICIDE -> EntityDamageEvent.DamageCause.SUICIDE; + case THORNS -> EntityDamageEvent.DamageCause.THORNS; + case VOID -> EntityDamageEvent.DamageCause.VOID; + case WITHER -> EntityDamageEvent.DamageCause.WITHER; + case WORLD_BORDER -> EntityDamageEvent.DamageCause.WORLD_BORDER; + case DRAGON_BREATH -> EntityDamageEvent.DamageCause.DRAGON_BREATH; + default -> throw new IllegalArgumentException("Unexpected value: " + cause); + }; + } + + @SuppressWarnings("deprecation") + public static DamageCause fromBukkit(EntityDamageEvent.DamageCause cause) { + return switch (cause) { + case BLOCK_EXPLOSION -> DamageCause.BLOCK_EXPLOSION; + case CAMPFIRE -> DamageCause.CAMPFIRE; + case CONTACT -> DamageCause.CONTACT; + case CRAMMING -> DamageCause.CRAMMING; + case CUSTOM -> DamageCause.CUSTOM; + case DROWNING -> DamageCause.DROWNING; + case DRYOUT -> DamageCause.DRYOUT; + case ENTITY_ATTACK -> DamageCause.ENTITY_ATTACK; + case ENTITY_EXPLOSION -> DamageCause.ENTITY_EXPLOSION; + case ENTITY_SWEEP_ATTACK -> DamageCause.ENTITY_SWEEP_ATTACK; + case FALL -> DamageCause.FALL; + case FALLING_BLOCK -> DamageCause.FALLING_BLOCK; + case FIRE -> DamageCause.FIRE; + case FIRE_TICK -> DamageCause.FIRE_TICK; + case FLY_INTO_WALL -> DamageCause.FLY_INTO_WALL; + case FREEZE -> DamageCause.FREEZE; + case HOT_FLOOR -> DamageCause.HOT_FLOOR; + case KILL -> DamageCause.KILL; + case LAVA -> DamageCause.LAVA; + case LIGHTNING -> DamageCause.LIGHTNING; + case MAGIC -> DamageCause.MAGIC; + case MELTING -> DamageCause.MELTING; + case POISON -> DamageCause.POISON; + case PROJECTILE -> DamageCause.PROJECTILE; + case SONIC_BOOM -> DamageCause.SONIC_BOOM; + case STARVATION -> DamageCause.STARVATION; + case SUFFOCATION -> DamageCause.SUFFOCATION; + case SUICIDE -> DamageCause.SUICIDE; + case THORNS -> DamageCause.THORNS; + case VOID -> DamageCause.VOID; + case WITHER -> DamageCause.WITHER; + case WORLD_BORDER -> DamageCause.WORLD_BORDER; + case DRAGON_BREATH -> DamageCause.DRAGON_BREATH; + default -> throw new IllegalArgumentException("Unexpected value: " + cause); + }; + } +} diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index a2b68568f..5e1ed8c99 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -153,6 +153,7 @@ warning.config.furniture.hitbox.invalid_type: "Issue found in file Issue found in file - The furniture '' is using a custom hitbox with invalid entity type ''." warning.config.item.duplicate: "Issue found in file - Duplicated item ''. Please check if there is the same configuration in other files." warning.config.item.settings.unknown: "Issue found in file - The item '' is using an unknown setting type ''." +warning.config.item.settings.invulnerable-unknown: "Issue found in file - The item '' is using an unknown damage cause type ''." warning.config.item.missing_material: "Issue found in file - The item '' is missing the required 'material' argument." warning.config.item.invalid_material: "Issue found in file - The item '' is using an invalid material type ''." warning.config.item.invalid_custom_model_data: "Issue found in file - The item '' is using a negative custom model data '' which is invalid." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 4f11d3878..5db0f709d 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -153,6 +153,7 @@ warning.config.furniture.hitbox.invalid_type: "在文件 发现 warning.config.furniture.hitbox.custom.invalid_entity: "在文件 发现问题 - 家具 '' 的自定义碰撞箱使用了无效的实体类型 ''" warning.config.item.duplicate: "在文件 发现问题 - 重复的物品 '' 请检查其他文件中是否存在相同配置" warning.config.item.settings.unknown: "在文件 发现问题 - 物品 '' 使用了未知的设置类型 ''" +warning.config.item.settings.invulnerable-unknown: "在文件 发现问题 - 物品 '' 物品使用了未知的受伤害类型 ''" warning.config.item.missing_material: "在文件 发现问题 - 物品 '' 缺少必需的 'material' 参数" warning.config.item.invalid_material: "在文件 发现问题 - 物品 '' 使用了无效的材料类型 ''" warning.config.item.invalid_custom_model_data: "在文件 发现问题 - 物品 '' 使用了无效的负数模型值 ''." diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java index bd621ea79..25d129b5a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java @@ -12,10 +12,7 @@ import net.momirealms.craftengine.core.item.setting.Helmet; import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.sound.SoundData; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.util.*; import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -37,6 +34,7 @@ public class ItemSettings { Helmet helmet = null; FoodData foodData = null; Key consumeReplacement = null; + List invulnerable = List.of(); private ItemSettings() {} @@ -74,6 +72,7 @@ public class ItemSettings { newSettings.helmet = settings.helmet; newSettings.foodData = settings.foodData; newSettings.consumeReplacement = settings.consumeReplacement; + newSettings.invulnerable = settings.invulnerable; return newSettings; } @@ -141,6 +140,10 @@ public class ItemSettings { return equipment; } + public List invulnerable() { + return invulnerable; + } + public ItemSettings repairItems(List items) { this.anvilRepairItems = items; return this; @@ -201,6 +204,11 @@ public class ItemSettings { return this; } + public ItemSettings invulnerable(List invulnerable) { + this.invulnerable = invulnerable; + return this; + } + @FunctionalInterface public interface Modifier { @@ -293,6 +301,16 @@ public class ItemSettings { ); return settings -> settings.foodData(data); })); + registerFactory("invulnerable", (value -> { + List list = MiscUtils.getAsStringList(value).stream().map(it -> { + try { + return DamageCause.byName(it); + } catch (IllegalArgumentException e) { + throw new LocalizedResourceConfigException("warning.config.item.settings.invulnerable-unknown", it); + } + }).toList(); + return settings -> settings.invulnerable(list); + })); } private static void registerFactory(String id, ItemSettings.Modifier.Factory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/DamageCause.java b/core/src/main/java/net/momirealms/craftengine/core/util/DamageCause.java new file mode 100644 index 000000000..bf01e6833 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/DamageCause.java @@ -0,0 +1,58 @@ +package net.momirealms.craftengine.core.util; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; + +public enum DamageCause { + BLOCK_EXPLOSION, + CAMPFIRE, + CONTACT, + CRAMMING, + CUSTOM, + DROWNING, + DRYOUT, + ENTITY_ATTACK, + ENTITY_EXPLOSION, + ENTITY_SWEEP_ATTACK, + FALL, + FALLING_BLOCK, + FIRE, + FIRE_TICK, + FLY_INTO_WALL, + FREEZE, + HOT_FLOOR, + KILL, + LAVA, + LIGHTNING, + MAGIC, + MELTING, + POISON, + PROJECTILE, + SONIC_BOOM, + STARVATION, + SUFFOCATION, + SUICIDE, + THORNS, + VOID, + WITHER, + WORLD_BORDER, + @Deprecated + @SuppressWarnings("all") + DRAGON_BREATH; + + public static final Map BY_NAME = new HashMap<>(); + + static { + for (DamageCause cause : values()) { + BY_NAME.put(cause.name().toLowerCase(Locale.ROOT), cause); + BY_NAME.put(cause.name(), cause); + } + } + + public static DamageCause byName(String name) { + return Optional.ofNullable(BY_NAME.get(name)).orElseThrow(() -> new IllegalArgumentException("Unknown damage cause: " + name)); + } + +} diff --git a/gradle.properties b/gradle.properties index 6e05db11f..d8bb1d53e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx1G # Rule: [major update].[feature update].[bug fix] project_version=0.0.56.5 config_version=36 -lang_version=15 +lang_version=16 project_group=net.momirealms latest_supported_version=1.21.5