package eu.abdelbaki.cmmodular; import net.minecraft.core.registries.Registries; import net.minecraft.tags.FluidTags; import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.RangedAttribute; import net.neoforged.bus.api.EventPriority; import net.neoforged.bus.api.IEventBus; import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.event.entity.EntityAttributeModificationEvent; import net.neoforged.neoforge.event.entity.living.LivingBreatheEvent; import net.neoforged.neoforge.registries.DeferredHolder; import net.neoforged.neoforge.registries.DeferredRegister; /** * Sea serpent fang armour lets its wearer breathe underwater, which is what Ice * and Fire's own Tide Guardian armour does and the only reason to hunt the * thing. * *

There is no attribute for it and MIAPI has no property for it either - the * closest data can get is a fake Respiration enchantment, which only postpones * drowning. So this follows the pattern {@link FireImmunity} and * {@link VacuumSeal} already set: an attribute of this mod's own that the * material grants like any other, and a listener here that watches for it. * *

Half a lung per module, as with {@link VacuumSeal}: the fang grants 0.5 in * each armour slot and nothing in hand, so it takes two worn pieces of it - * two sockets, two pieces built of it, or a socketed piece that is both - to * breathe, and a fang weapon breathes not at all. What a fang is worth in hand * is {@link WaterCombat}'s. * *

It answers the same event {@link VacuumSeal} does but only underwater, so * a fang is a fang and not half a spacesuit. */ public final class WaterBreathing { private static final DeferredRegister ATTRIBUTES = DeferredRegister.create(Registries.ATTRIBUTE, CMModular.MOD_ID); /** At or above 1 the bearer never drowns; each worn fang module is 0.5. */ public static final DeferredHolder WATER_BREATHING = ATTRIBUTES.register("water_breathing", id -> new RangedAttribute( "attribute.cmmodular.water_breathing", 0.0D, 0.0D, 1.0D).setSyncable(true)); private WaterBreathing() { } static void register(IEventBus modBus) { ATTRIBUTES.register(modBus); modBus.addListener(WaterBreathing::attachToEntities); // Last, so it answers after whatever said there was no air. NeoForge.EVENT_BUS.addListener(EventPriority.LOWEST, WaterBreathing::onBreathe); } /** Attributes only exist on an entity if they were added to its type. */ private static void attachToEntities(EntityAttributeModificationEvent event) { event.getTypes().forEach(type -> event.add(type, WATER_BREATHING)); } private static void onBreathe(LivingBreatheEvent event) { if (event.canBreathe() || !event.getEntity().isEyeInFluid(FluidTags.WATER)) { return; } if (EquipmentAttributes.value(event.getEntity(), WATER_BREATHING) >= 1.0D) { event.setCanBreathe(true); } } }