// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.core.modules.entity.damage;

import java.lang.invoke.CallSite;
import java.lang.reflect.UndeclaredThrowableException;
import java.lang.invoke.MethodHandle;
import java.lang.runtime.SwitchBootstraps;
import java.lang.invoke.MethodType;
import java.lang.invoke.MethodHandles;
import com.hypixel.hytale.server.core.modules.splitvelocity.SplitVelocity;
import it.unimi.dsi.fastutil.ints.IntIterator;
import com.hypixel.hytale.server.core.asset.type.entityeffect.config.EntityEffect;
import com.hypixel.hytale.server.core.asset.type.gameplay.BrokenPenalties;
import java.util.Iterator;
import com.hypixel.hytale.server.core.modules.entitystats.modifier.StaticModifier;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.util.Map;
import com.hypixel.hytale.server.core.asset.type.item.config.ItemArmor;
import com.hypixel.hytale.server.core.asset.type.item.config.Item;
import it.unimi.dsi.fastutil.ints.Int2DoubleMap;
import com.hypixel.hytale.server.core.entity.InteractionChain;
import com.hypixel.hytale.server.core.meta.DynamicMetaStore;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.server.combat.DamageEffects;
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.protocol.BlockPosition;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.RootInteraction;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.Interaction;
import com.hypixel.hytale.server.core.entity.InteractionContext;
import com.hypixel.hytale.protocol.InteractionType;
import com.hypixel.hytale.server.core.modules.interaction.InteractionModule;
import com.hypixel.hytale.server.core.entity.InteractionManager;
import com.hypixel.hytale.protocol.CombatTextUpdate;
import com.hypixel.hytale.protocol.ComponentUpdateType;
import com.hypixel.hytale.protocol.ComponentUpdate;
import com.hypixel.hytale.server.core.modules.entityui.EntityUIModule;
import com.hypixel.hytale.server.core.modules.entityui.UIComponentList;
import com.hypixel.hytale.server.core.modules.entity.tracker.EntityTrackerSystems;
import com.hypixel.hytale.assetstore.AssetRegistry;
import com.hypixel.hytale.protocol.packets.player.ReticleEvent;
import com.hypixel.hytale.protocol.packets.player.DamageInfo;
import com.hypixel.hytale.server.core.inventory.Inventory;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.client.WieldingInteraction;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.server.core.inventory.container.ItemContainer;
import com.hypixel.hytale.math.random.RandomExtra;
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
import com.hypixel.hytale.server.core.asset.type.model.config.Model;
import com.hypixel.hytale.server.core.entity.AnimationUtils;
import com.hypixel.hytale.protocol.AnimationSlot;
import com.hypixel.hytale.server.core.entity.Entity;
import com.hypixel.hytale.protocol.MovementStates;
import com.hypixel.hytale.component.dependency.SystemDependency;
import com.hypixel.hytale.server.core.modules.entity.player.PlayerSystems;
import com.hypixel.hytale.server.core.asset.type.gameplay.PlayerConfig;
import com.hypixel.hytale.server.core.entity.entities.player.movement.MovementConfig;
import com.hypixel.hytale.server.core.modules.physics.component.Velocity;
import com.hypixel.hytale.server.core.modules.entity.player.PlayerInput;
import com.hypixel.hytale.component.system.tick.EntityTickingSystem;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.protocol.BlockMaterial;
import com.hypixel.hytale.server.core.entity.EntityUtils;
import com.hypixel.hytale.server.core.entity.LivingEntity;
import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent;
import com.hypixel.hytale.component.system.tick.DelayedEntitySystem;
import com.hypixel.hytale.component.dependency.SystemGroupDependency;
import com.hypixel.hytale.component.dependency.Order;
import com.hypixel.hytale.server.core.modules.entitystats.EntityStatValue;
import java.util.Objects;
import com.hypixel.hytale.server.core.modules.entitystats.asset.DefaultEntityStatTypes;
import com.hypixel.hytale.component.dependency.Dependency;
import java.util.Set;
import com.hypixel.hytale.server.core.modules.entitystats.EntityStatsSystems;
import java.time.Instant;
import com.hypixel.hytale.server.core.modules.time.TimeResource;
import com.hypixel.hytale.server.core.entity.damage.DamageDataComponent;
import java.util.function.Predicate;
import com.hypixel.hytale.protocol.SoundCategory;
import com.hypixel.hytale.server.core.universe.world.SoundUtil;
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
import com.hypixel.hytale.component.spatial.SpatialStructure;
import it.unimi.dsi.fastutil.objects.ObjectList;
import com.hypixel.hytale.server.core.asset.type.particle.config.WorldParticle;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.protocol.packets.entities.SpawnModelParticles;
import com.hypixel.hytale.protocol.ModelParticle;
import com.hypixel.hytale.server.core.universe.world.ParticleUtil;
import java.util.List;
import com.hypixel.hytale.math.util.TrigMathUtil;
import org.bouncycastle.util.Arrays;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.math.vector.Vector4d;
import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.component.spatial.SpatialResource;
import com.hypixel.hytale.component.ResourceType;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.asset.type.gameplay.GameplayConfig;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.entity.knockback.KnockbackComponent;
import com.hypixel.hytale.component.system.EcsEvent;
import com.hypixel.hytale.component.Archetype;
import com.hypixel.hytale.server.core.modules.entity.component.Intangible;
import com.hypixel.hytale.server.core.modules.entity.component.Invulnerable;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.server.core.entity.effect.EffectControllerComponent;
import com.hypixel.hytale.component.Store;
import javax.annotation.Nullable;
import com.hypixel.hytale.component.SystemGroup;
import com.hypixel.hytale.server.core.modules.entity.EntityModule;
import com.hypixel.hytale.server.core.entity.movement.MovementStatesComponent;
import com.hypixel.hytale.server.core.modules.entitystats.EntityStatMap;
import com.hypixel.hytale.server.core.modules.entity.AllLegacyLivingEntityTypesQuery;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.ArchetypeChunk;
import com.hypixel.hytale.component.ComponentAccessor;
import javax.annotation.Nonnull;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.query.Query;

public class DamageSystems
{
    public static final float DEFAULT_DAMAGE_DELAY = 1.0f;
    private static final Query<EntityStore> NPCS_QUERY;
    
    public static void executeDamage(@Nonnull final Ref<EntityStore> ref, @Nonnull final ComponentAccessor<EntityStore> componentAccessor, @Nonnull final Damage damage) {
        componentAccessor.invoke(ref, damage);
    }
    
    public static void executeDamage(final int index, @Nonnull final ArchetypeChunk<EntityStore> chunk, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
        commandBuffer.invoke(chunk.getReferenceTo(index), damage);
    }
    
    public static void executeDamage(@Nonnull final Ref<EntityStore> ref, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
        commandBuffer.invoke(ref, damage);
    }
    
    static {
        NPCS_QUERY = Query.and(AllLegacyLivingEntityTypesQuery.INSTANCE, EntityStatMap.getComponentType(), MovementStatesComponent.getComponentType(), Query.not((Query<Object>)EntityModule.get().getPlayerComponentType()));
    }
    
    public static class FilterUnkillable extends DamageEventSystem
    {
        public static boolean CAUSE_DESYNC;
        @Nonnull
        private static final Query<EntityStore> QUERY;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getFilterDamageGroup();
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return FilterUnkillable.QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            final EffectControllerComponent entityEffectControllerComponent = archetypeChunk.getComponent(index, EffectControllerComponent.getComponentType());
            if (entityEffectControllerComponent != null && entityEffectControllerComponent.isInvulnerable()) {
                damage.setCancelled(true);
            }
            final Archetype<EntityStore> archetype = archetypeChunk.getArchetype();
            final boolean dead = archetype.contains(DeathComponent.getComponentType());
            final boolean invulnerable = archetype.contains(Invulnerable.getComponentType());
            final boolean intangible = archetype.contains(Intangible.getComponentType());
            if (dead || invulnerable || intangible || FilterUnkillable.CAUSE_DESYNC) {
                damage.setCancelled(true);
            }
        }
        
        static {
            QUERY = AllLegacyLivingEntityTypesQuery.INSTANCE;
        }
    }
    
    public static class FilterPlayerWorldConfig extends DamageEventSystem
    {
        private static final Query<EntityStore> QUERY;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getFilterDamageGroup();
        }
        
        @Nullable
        @Override
        public Query<EntityStore> getQuery() {
            return FilterPlayerWorldConfig.QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage event) {
            final World world = store.getExternalData().getWorld();
            final GameplayConfig gameplayConfig = world.getGameplayConfig();
            if (gameplayConfig.getCombatConfig().isPlayerIncomingDamageDisabled()) {
                event.setCancelled(true);
                final Ref<EntityStore> ref = archetypeChunk.getReferenceTo(index);
                commandBuffer.tryRemoveComponent(ref, KnockbackComponent.getComponentType());
            }
        }
        
        static {
            QUERY = Query.and(AllLegacyLivingEntityTypesQuery.INSTANCE, Player.getComponentType());
        }
    }
    
    public static class FilterNPCWorldConfig extends DamageEventSystem
    {
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getFilterDamageGroup();
        }
        
        @Nullable
        @Override
        public Query<EntityStore> getQuery() {
            return DamageSystems.NPCS_QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage event) {
            final World world = store.getExternalData().getWorld();
            final GameplayConfig gameplayConfig = world.getGameplayConfig();
            if (gameplayConfig.getCombatConfig().isNpcIncomingDamageDisabled()) {
                event.setCancelled(true);
                final Ref<EntityStore> ref = archetypeChunk.getReferenceTo(index);
                commandBuffer.tryRemoveComponent(ref, KnockbackComponent.getComponentType());
            }
        }
    }
    
    public static class ApplyParticles extends DamageEventSystem
    {
        @Nonnull
        private static final ResourceType<EntityStore, SpatialResource<Ref<EntityStore>, EntityStore>> PLAYER_SPATIAL_RESOURCE_TYPE;
        @Nonnull
        private static final ComponentType<EntityStore, TransformComponent> TRANSFORM_COMPONENT_TYPE;
        @Nonnull
        private static final ComponentType<EntityStore, NetworkId> NETWORK_ID_COMPONENT_TYPE;
        @Nonnull
        private static final Query<EntityStore> QUERY;
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return ApplyParticles.QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            final Damage.Particles particles = damage.getIfPresentMetaObject(Damage.IMPACT_PARTICLES);
            if (particles == null) {
                return;
            }
            final Damage.Source source = damage.getSource();
            if (!(source instanceof Damage.EntitySource)) {
                return;
            }
            final Damage.EntitySource sourceEntity = (Damage.EntitySource)source;
            final Ref<EntityStore> sourceRef = sourceEntity.getRef();
            if (!sourceRef.isValid()) {
                return;
            }
            final TransformComponent transformComponent = archetypeChunk.getComponent(index, ApplyParticles.TRANSFORM_COMPONENT_TYPE);
            assert transformComponent != null;
            final Vector4d hitLocation = damage.getIfPresentMetaObject(Damage.HIT_LOCATION);
            final Vector3d targetPosition = (hitLocation == null) ? transformComponent.getPosition() : new Vector3d(hitLocation.x, hitLocation.y, hitLocation.z);
            final boolean damageCanBePredicted = damage.getMetaStore().getMetaObject(Damage.CAN_BE_PREDICTED);
            final double particlesViewDistance = particles.getViewDistance();
            final WorldParticle[] worldParticles = particles.getWorldParticles();
            if (!Arrays.isNullOrEmpty(worldParticles)) {
                final TransformComponent sourceTransformComponent = commandBuffer.getComponent(sourceRef, TransformComponent.getComponentType());
                if (sourceTransformComponent != null) {
                    final float angleBetween = TrigMathUtil.atan2(sourceTransformComponent.getPosition().x - targetPosition.x, sourceTransformComponent.getPosition().z - targetPosition.z);
                    final SpatialResource<Ref<EntityStore>, EntityStore> playerSpatialResource = commandBuffer.getResource(EntityModule.get().getPlayerSpatialResourceType());
                    final ObjectList<Ref<EntityStore>> results = SpatialResource.getThreadLocalReferenceList();
                    playerSpatialResource.getSpatialStructure().collect(targetPosition, particlesViewDistance, results);
                    final Ref<EntityStore> particleSource = damageCanBePredicted ? sourceRef : null;
                    for (final WorldParticle particle : worldParticles) {
                        ParticleUtil.spawnParticleEffect(particle, targetPosition, angleBetween, 0.0f, 0.0f, particleSource, results, commandBuffer);
                    }
                }
            }
            final com.hypixel.hytale.server.core.asset.type.model.config.ModelParticle[] modelParticles = particles.getModelParticles();
            if (!Arrays.isNullOrEmpty(modelParticles)) {
                final ModelParticle[] modelParticlesProtocol = new ModelParticle[modelParticles.length];
                for (int j = 0; j < modelParticles.length; ++j) {
                    modelParticlesProtocol[j] = modelParticles[j].toPacket();
                }
                final NetworkId networkIdComponent = archetypeChunk.getComponent(index, ApplyParticles.NETWORK_ID_COMPONENT_TYPE);
                assert networkIdComponent != null;
                final int targetNetworkId = networkIdComponent.getId();
                final SpawnModelParticles packet = new SpawnModelParticles(targetNetworkId, modelParticlesProtocol);
                final SpatialResource<Ref<EntityStore>, EntityStore> spatialResource = store.getResource(ApplyParticles.PLAYER_SPATIAL_RESOURCE_TYPE);
                final SpatialStructure<Ref<EntityStore>> spatialStructure = spatialResource.getSpatialStructure();
                final ObjectList<Ref<EntityStore>> results2 = SpatialResource.getThreadLocalReferenceList();
                spatialStructure.ordered(targetPosition, particlesViewDistance, results2);
                for (final Ref<EntityStore> targetRef : results2) {
                    if (damageCanBePredicted && targetRef.equals(sourceRef)) {
                        return;
                    }
                    final PlayerRef playerRefComponent = commandBuffer.getComponent(targetRef, PlayerRef.getComponentType());
                    if (playerRefComponent == null) {
                        continue;
                    }
                    playerRefComponent.getPacketHandler().write(packet);
                }
            }
        }
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getInspectDamageGroup();
        }
        
        static {
            PLAYER_SPATIAL_RESOURCE_TYPE = EntityModule.get().getPlayerSpatialResourceType();
            TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType();
            NETWORK_ID_COMPONENT_TYPE = NetworkId.getComponentType();
            QUERY = Query.and(ApplyParticles.TRANSFORM_COMPONENT_TYPE, ApplyParticles.NETWORK_ID_COMPONENT_TYPE);
        }
    }
    
    public static class ApplySoundEffects extends DamageEventSystem
    {
        @Nonnull
        private static final ComponentType<EntityStore, TransformComponent> TRANSFORM_COMPONENT_TYPE;
        @Nonnull
        private static final ComponentType<EntityStore, Player> PLAYER_COMPONENT_TYPE;
        @Nonnull
        private static final Query<EntityStore> QUERY;
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return ApplySoundEffects.QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
        }
        
        @Override
        public void handleInternal(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            final TransformComponent transformComponent = archetypeChunk.getComponent(index, ApplySoundEffects.TRANSFORM_COMPONENT_TYPE);
            assert transformComponent != null;
            final Player playerComponent = archetypeChunk.getComponent(index, ApplySoundEffects.PLAYER_COMPONENT_TYPE);
            final Ref<EntityStore> ref = archetypeChunk.getReferenceTo(index);
            final Damage.SoundEffect soundEffect = damage.getIfPresentMetaObject(Damage.IMPACT_SOUND_EFFECT);
            final Damage.SoundEffect playerSoundEffect = damage.getIfPresentMetaObject(Damage.PLAYER_IMPACT_SOUND_EFFECT);
            if (soundEffect == null && playerSoundEffect == null) {
                return;
            }
            final Damage.Source source2 = damage.getSource();
            Ref<EntityStore> sourceRef;
            if (source2 instanceof final Damage.EntitySource source) {
                sourceRef = (source.getRef().isValid() ? source.getRef() : null);
            }
            else {
                sourceRef = null;
            }
            final Vector4d hitLocation = damage.getIfPresentMetaObject(Damage.HIT_LOCATION);
            final Vector3d targetPosition = (hitLocation == null) ? transformComponent.getPosition() : new Vector3d(hitLocation.x, hitLocation.y, hitLocation.z);
            if (soundEffect != null && soundEffect.getSoundEventIndex() != 0) {
                final Predicate<Ref<EntityStore>> filter = (sourceRef != null) ? (p -> !p.equals(sourceRef)) : (p -> true);
                SoundUtil.playSoundEvent3d(soundEffect.getSoundEventIndex(), targetPosition.x, targetPosition.y, targetPosition.z, filter, commandBuffer);
            }
            if (playerComponent != null && playerSoundEffect != null && playerSoundEffect.getSoundEventIndex() != 0) {
                SoundUtil.playSoundEvent3dToPlayer(ref, playerSoundEffect.getSoundEventIndex(), SoundCategory.SFX, targetPosition.x, targetPosition.y, targetPosition.z, commandBuffer);
            }
        }
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getInspectDamageGroup();
        }
        
        static {
            TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType();
            PLAYER_COMPONENT_TYPE = Player.getComponentType();
            QUERY = ApplySoundEffects.TRANSFORM_COMPONENT_TYPE;
        }
    }
    
    public static class RecordLastCombat extends DamageEventSystem
    {
        @Nonnull
        private static final ComponentType<EntityStore, DamageDataComponent> DAMAGE_DATA_COMPONENT_TYPE;
        @Nonnull
        private static final ResourceType<EntityStore, TimeResource> TIME_RESOURCE_TYPE;
        @Nonnull
        private static final Query<EntityStore> QUERY;
        
        @Override
        public Query<EntityStore> getQuery() {
            return RecordLastCombat.QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            final DamageDataComponent damageDataComponent = archetypeChunk.getComponent(index, RecordLastCombat.DAMAGE_DATA_COMPONENT_TYPE);
            assert damageDataComponent != null;
            final Instant timestamp = store.getResource(RecordLastCombat.TIME_RESOURCE_TYPE).getNow();
            damageDataComponent.setLastCombatAction(timestamp);
            final Damage.Source source = damage.getSource();
            if (source instanceof final Damage.EntitySource entitySource) {
                final Ref<EntityStore> sourceRef = entitySource.getRef();
                if (!sourceRef.isValid()) {
                    return;
                }
                final DamageDataComponent sourceDamageDataComponent = store.getComponent(sourceRef, RecordLastCombat.DAMAGE_DATA_COMPONENT_TYPE);
                if (sourceDamageDataComponent != null) {
                    sourceDamageDataComponent.setLastCombatAction(timestamp);
                }
            }
        }
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getInspectDamageGroup();
        }
        
        static {
            DAMAGE_DATA_COMPONENT_TYPE = DamageDataComponent.getComponentType();
            TIME_RESOURCE_TYPE = TimeResource.getResourceType();
            QUERY = RecordLastCombat.DAMAGE_DATA_COMPONENT_TYPE;
        }
    }
    
    public static class ApplyDamage extends DamageEventSystem implements EntityStatsSystems.StatModifyingSystem
    {
        @Nonnull
        private static final Query<EntityStore> QUERY;
        @Nonnull
        private static final Set<Dependency<EntityStore>> DEPENDENCIES;
        
        @Override
        public Query<EntityStore> getQuery() {
            return ApplyDamage.QUERY;
        }
        
        @Nonnull
        @Override
        public Set<Dependency<EntityStore>> getDependencies() {
            return ApplyDamage.DEPENDENCIES;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            final EntityStatMap entityStatMapComponent = archetypeChunk.getComponent(index, EntityStatMap.getComponentType());
            assert entityStatMapComponent != null;
            final int healthStat = DefaultEntityStatTypes.getHealth();
            final EntityStatValue healthValue = entityStatMapComponent.get(healthStat);
            Objects.requireNonNull(healthValue);
            final boolean isDead = archetypeChunk.getArchetype().contains(DeathComponent.getComponentType());
            if (isDead) {
                damage.setCancelled(true);
                return;
            }
            damage.setAmount((float)Math.round(damage.getAmount()));
            final float newValue = entityStatMapComponent.subtractStatValue(healthStat, damage.getAmount());
            if (newValue <= healthValue.getMin()) {
                DeathComponent.tryAddComponent(commandBuffer, archetypeChunk.getReferenceTo(index), damage);
            }
        }
        
        static {
            QUERY = EntityStatMap.getComponentType();
            DEPENDENCIES = Set.of(new SystemGroupDependency(Order.AFTER, DamageModule.get().getGatherDamageGroup()), new SystemGroupDependency(Order.AFTER, DamageModule.get().getFilterDamageGroup()), new SystemGroupDependency(Order.BEFORE, DamageModule.get().getInspectDamageGroup()));
        }
    }
    
    public static class CanBreathe extends DelayedEntitySystem<EntityStore>
    {
        private static final float DAMAGE_AMOUNT_DROWNING = 10.0f;
        private static final float DAMAGE_AMOUNT_SUFFOCATION = 20.0f;
        @Nonnull
        private static final ComponentType<EntityStore, ModelComponent> MODEL_COMPONENT_TYPE;
        @Nonnull
        private static final Query<EntityStore> QUERY;
        
        public CanBreathe() {
            super(1.0f);
        }
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getGatherDamageGroup();
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return CanBreathe.QUERY;
        }
        
        @Override
        public void tick(final float dt, final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final LivingEntity entity = (LivingEntity)EntityUtils.getEntity(index, archetypeChunk);
            assert entity != null;
            final EntityStatMap statMapComponent = archetypeChunk.getComponent(index, EntityStatMap.getComponentType());
            assert statMapComponent != null;
            final EntityStatValue oxygenStatValue = statMapComponent.get(DefaultEntityStatTypes.getOxygen());
            if (oxygenStatValue != null) {
                final Ref<EntityStore> ref = archetypeChunk.getReferenceTo(index);
                final long packed = LivingEntity.getPackedMaterialAndFluidAtBreathingHeight(ref, commandBuffer);
                final BlockMaterial material = BlockMaterial.VALUES[MathUtil.unpackLeft(packed)];
                final int fluidId = MathUtil.unpackRight(packed);
                if (!entity.canBreathe(ref, material, fluidId, commandBuffer) && oxygenStatValue.get() <= oxygenStatValue.getMin()) {
                    Damage damage;
                    if (fluidId != 0) {
                        assert DamageCause.DROWNING != null;
                        damage = new Damage(Damage.NULL_SOURCE, DamageCause.DROWNING, 10.0f);
                    }
                    else {
                        assert DamageCause.SUFFOCATION != null;
                        damage = new Damage(Damage.NULL_SOURCE, DamageCause.SUFFOCATION, 20.0f);
                    }
                    DamageSystems.executeDamage(index, archetypeChunk, commandBuffer, damage);
                }
            }
        }
        
        @Override
        public boolean isParallel(final int archetypeChunkSize, final int taskCount) {
            return false;
        }
        
        static {
            MODEL_COMPONENT_TYPE = ModelComponent.getComponentType();
            QUERY = Query.and(AllLegacyLivingEntityTypesQuery.INSTANCE, EntityStatMap.getComponentType(), TransformComponent.getComponentType(), CanBreathe.MODEL_COMPONENT_TYPE);
        }
    }
    
    public static class OutOfWorldDamage extends DelayedEntitySystem<EntityStore>
    {
        @Nonnull
        private static final ComponentType<EntityStore, TransformComponent> TRANSFORM_COMPONENT_TYPE;
        
        public OutOfWorldDamage() {
            super(1.0f);
        }
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getGatherDamageGroup();
        }
        
        @Override
        public Query<EntityStore> getQuery() {
            return OutOfWorldDamage.TRANSFORM_COMPONENT_TYPE;
        }
        
        @Override
        public void tick(final float dt, final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final TransformComponent transformComponent = archetypeChunk.getComponent(index, OutOfWorldDamage.TRANSFORM_COMPONENT_TYPE);
            assert transformComponent != null;
            final double posY = transformComponent.getPosition().getY();
            if (posY >= 0.0) {
                return;
            }
            final boolean belowMinimum = posY < -32.0;
            final Damage damage = new Damage(Damage.NULL_SOURCE, DamageCause.OUT_OF_WORLD, belowMinimum ? 2.1474836E9f : 50.0f);
            if (belowMinimum) {
                DeathComponent.tryAddComponent(commandBuffer, archetypeChunk.getReferenceTo(index), damage);
                return;
            }
            DamageSystems.executeDamage(index, archetypeChunk, commandBuffer, damage);
        }
        
        @Override
        public boolean isParallel(final int archetypeChunkSize, final int taskCount) {
            return EntityTickingSystem.maybeUseParallel(archetypeChunkSize, taskCount);
        }
        
        static {
            TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType();
        }
    }
    
    public static class FallDamagePlayers extends EntityTickingSystem<EntityStore>
    {
        static final float CURVE_MODIFIER = 0.58f;
        static final float CURVE_MULTIPLIER = 2.0f;
        public static final double MIN_DAMAGE = 10.0;
        @Nonnull
        private static final Query<EntityStore> QUERY;
        @Nonnull
        private static final Set<Dependency<EntityStore>> DEPENDENCIES;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getGatherDamageGroup();
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return FallDamagePlayers.QUERY;
        }
        
        @Nonnull
        @Override
        public Set<Dependency<EntityStore>> getDependencies() {
            return FallDamagePlayers.DEPENDENCIES;
        }
        
        @Override
        public void tick(final float dt, final int systemIndex, @Nonnull final Store<EntityStore> store) {
            final World world = store.getExternalData().getWorld();
            if (!world.getWorldConfig().isFallDamageEnabled()) {
                return;
            }
            super.tick(dt, systemIndex, store);
        }
        
        @Override
        public void tick(final float dt, final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final PlayerInput playerInputComponent = archetypeChunk.getComponent(index, PlayerInput.getComponentType());
            assert playerInputComponent != null;
            final Velocity velocityComponent = archetypeChunk.getComponent(index, Velocity.getComponentType());
            assert velocityComponent != null;
            double yVelocity = Math.abs(velocityComponent.getClientVelocity().getY());
            final World world = commandBuffer.getExternalData().getWorld();
            final PlayerConfig worldPlayerConfig = world.getGameplayConfig().getPlayerConfig();
            final List<PlayerInput.InputUpdate> queue = playerInputComponent.getMovementUpdateQueue();
            for (int i = 0; i < queue.size(); ++i) {
                final PlayerInput.InputUpdate obj;
                final PlayerInput.InputUpdate queueEntry = obj = queue.get(i);
                Objects.requireNonNull(obj);
                final PlayerInput.SetMovementStates setMovementStates = (PlayerInput.SetMovementStates)obj;
                switch (/* invokedynamic(!) */ProcyonInvokeDynamicHelper_2.invoke(setMovementStates, false)) {
                    case 0: {
                        final PlayerInput.SetClientVelocity velocityEntry = (PlayerInput.SetClientVelocity)setMovementStates;
                        yVelocity = Math.abs(velocityEntry.getVelocity().y);
                        break;
                    }
                    case 1: {
                        final PlayerInput.SetMovementStates movementStatesEntry = setMovementStates;
                        final Player playerComponent = archetypeChunk.getComponent(index, Player.getComponentType());
                        assert playerComponent != null;
                        if (movementStatesEntry.movementStates().onGround && playerComponent.getCurrentFallDistance() > 0.0) {
                            final int movementConfigIndex = worldPlayerConfig.getMovementConfigIndex();
                            final MovementConfig movementConfig = MovementConfig.getAssetMap().getAsset(movementConfigIndex);
                            final float minFallSpeedToEngageRoll = movementConfig.getMinFallSpeedToEngageRoll();
                            if (yVelocity > minFallSpeedToEngageRoll && !movementStatesEntry.movementStates().inFluid) {
                                final EntityStatMap entityStatMapComponent = archetypeChunk.getComponent(index, EntityStatMap.getComponentType());
                                assert entityStatMapComponent != null;
                                final double damagePercentage = Math.pow(0.5799999833106995 * (yVelocity - minFallSpeedToEngageRoll), 2.0) + 10.0;
                                final EntityStatValue healthStatValue = entityStatMapComponent.get(DefaultEntityStatTypes.getHealth());
                                assert healthStatValue != null;
                                final float maxHealth = healthStatValue.getMax();
                                final double healthModifier = maxHealth / 100.0;
                                int damageInt = (int)Math.floor(healthModifier * damagePercentage);
                                if (movementStatesEntry.movementStates().rolling) {
                                    if (yVelocity <= movementConfig.getMaxFallSpeedRollFullMitigation()) {
                                        damageInt = 0;
                                    }
                                    else if (yVelocity <= movementConfig.getMaxFallSpeedToEngageRoll()) {
                                        damageInt *= (int)(1.0 - movementConfig.getFallDamagePartialMitigationPercent() / 100.0);
                                    }
                                }
                                if (damageInt > 0) {
                                    assert DamageCause.FALL != null;
                                    final Damage damage = new Damage(Damage.NULL_SOURCE, DamageCause.FALL, (float)damageInt);
                                    DamageSystems.executeDamage(index, archetypeChunk, commandBuffer, damage);
                                }
                            }
                            playerComponent.setCurrentFallDistance(0.0);
                        }
                        break;
                    }
                }
            }
        }
        
        @Override
        public boolean isParallel(final int archetypeChunkSize, final int taskCount) {
            return EntityTickingSystem.maybeUseParallel(archetypeChunkSize, taskCount);
        }
        
        static {
            QUERY = Query.and(EntityStatMap.getComponentType(), MovementStatesComponent.getComponentType(), EntityModule.get().getPlayerComponentType(), PlayerInput.getComponentType());
            DEPENDENCIES = Set.of(new SystemDependency(Order.BEFORE, PlayerSystems.ProcessPlayerInput.class));
        }
        
        // This helper class was generated by Procyon to approximate the behavior of an
        // 'invokedynamic' instruction that it doesn't know how to interpret.
        private static final class ProcyonInvokeDynamicHelper_2
        {
            private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
            private static MethodHandle handle;
            private static volatile int fence;
            
            private static MethodHandle handle() {
                final MethodHandle handle = ProcyonInvokeDynamicHelper_2.handle;
                if (handle != null)
                    return handle;
                return ProcyonInvokeDynamicHelper_2.ensureHandle();
            }
            
            private static MethodHandle ensureHandle() {
                ProcyonInvokeDynamicHelper_2.fence = 0;
                MethodHandle handle = ProcyonInvokeDynamicHelper_2.handle;
                if (handle == null) {
                    MethodHandles.Lookup lookup = ProcyonInvokeDynamicHelper_2.LOOKUP;
                    try {
                        handle = ((CallSite)SwitchBootstraps.typeSwitch(lookup, "typeSwitch", MethodType.methodType(int.class, Object.class, int.class), PlayerInput.SetClientVelocity.class, PlayerInput.SetMovementStates.class)).dynamicInvoker();
                    }
                    catch (Throwable t) {
                        throw new UndeclaredThrowableException(t);
                    }
                    ProcyonInvokeDynamicHelper_2.fence = 1;
                    ProcyonInvokeDynamicHelper_2.handle = handle;
                    ProcyonInvokeDynamicHelper_2.fence = 0;
                }
                return handle;
            }
            
            private static int invoke(Object p0, int p1) {
                try {
                    return ProcyonInvokeDynamicHelper_2.handle().invokeExact(p0, p1);
                }
                catch (Throwable t) {
                    throw new UndeclaredThrowableException(t);
                }
            }
        }
    }
    
    public static class FallDamageNPCs extends EntityTickingSystem<EntityStore>
    {
        static final float CURVE_MODIFIER = 0.58f;
        static final float CURVE_MULTIPLIER = 2.0f;
        public static final double MIN_DAMAGE = 10.0;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getGatherDamageGroup();
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return DamageSystems.NPCS_QUERY;
        }
        
        @Override
        public void tick(final float dt, final int systemIndex, @Nonnull final Store<EntityStore> store) {
            final World world = store.getExternalData().getWorld();
            if (!world.getWorldConfig().isFallDamageEnabled()) {
                return;
            }
            super.tick(dt, systemIndex, store);
        }
        
        @Override
        public void tick(final float dt, final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final LivingEntity entity = (LivingEntity)EntityUtils.getEntity(index, archetypeChunk);
            assert entity != null;
            final MovementStatesComponent movementStatesComponent = archetypeChunk.getComponent(index, MovementStatesComponent.getComponentType());
            assert movementStatesComponent != null;
            final MovementStates movementStates = movementStatesComponent.getMovementStates();
            if (movementStates.onGround && entity.getCurrentFallDistance() > 0.0) {
                final Velocity velocityComponent = archetypeChunk.getComponent(index, Velocity.getComponentType());
                assert velocityComponent != null;
                final double yVelocity = Math.abs(velocityComponent.getVelocity().getY());
                final World world = commandBuffer.getExternalData().getWorld();
                final int movementConfigIndex = world.getGameplayConfig().getPlayerConfig().getMovementConfigIndex();
                final MovementConfig movementConfig = MovementConfig.getAssetMap().getAsset(movementConfigIndex);
                final float minFallSpeedToEngageRoll = movementConfig.getMinFallSpeedToEngageRoll();
                if (yVelocity > minFallSpeedToEngageRoll && !movementStates.inFluid) {
                    final EntityStatMap entityStatMapComponent = archetypeChunk.getComponent(index, EntityStatMap.getComponentType());
                    assert entityStatMapComponent != null;
                    final double damagePercentage = Math.pow(0.5799999833106995 * (yVelocity - minFallSpeedToEngageRoll), 2.0) + 10.0;
                    final EntityStatValue healthStatValue = entityStatMapComponent.get(DefaultEntityStatTypes.getHealth());
                    assert healthStatValue != null;
                    final float maxHealth = healthStatValue.getMax();
                    final double healthModifier = maxHealth / 100.0;
                    int damageInt = (int)Math.floor(healthModifier * damagePercentage);
                    if (movementStates.rolling) {
                        if (yVelocity <= movementConfig.getMaxFallSpeedRollFullMitigation()) {
                            damageInt = 0;
                        }
                        else if (yVelocity <= movementConfig.getMaxFallSpeedToEngageRoll()) {
                            damageInt *= (int)(1.0 - movementConfig.getFallDamagePartialMitigationPercent() / 100.0);
                        }
                    }
                    if (damageInt > 0) {
                        assert DamageCause.FALL != null;
                        final Damage damage = new Damage(Damage.NULL_SOURCE, DamageCause.FALL, (float)damageInt);
                        DamageSystems.executeDamage(index, archetypeChunk, commandBuffer, damage);
                    }
                }
                entity.setCurrentFallDistance(0.0);
            }
        }
        
        @Override
        public boolean isParallel(final int archetypeChunkSize, final int taskCount) {
            return EntityTickingSystem.maybeUseParallel(archetypeChunkSize, taskCount);
        }
    }
    
    public static class HitAnimation extends DamageEventSystem
    {
        @Nonnull
        private static final Query<EntityStore> QUERY;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getInspectDamageGroup();
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return HitAnimation.QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            final ModelComponent modelComponent = archetypeChunk.getComponent(index, ModelComponent.getComponentType());
            final Model model = (modelComponent != null) ? modelComponent.getModel() : null;
            final MovementStatesComponent movementStatesComponent = archetypeChunk.getComponent(index, MovementStatesComponent.getComponentType());
            assert movementStatesComponent != null;
            final MovementStates movementStates = movementStatesComponent.getMovementStates();
            if (damage.getAmount() <= 0.0f) {
                return;
            }
            final String[] animationIds = Entity.DefaultAnimations.getHurtAnimationIds(movementStates, damage.getCause());
            if (model != null) {
                final String selectedAnimationId = model.getFirstBoundAnimationId(animationIds);
                if (selectedAnimationId != null) {
                    AnimationUtils.playAnimation(archetypeChunk.getReferenceTo(index), AnimationSlot.Status, selectedAnimationId, true, commandBuffer);
                }
            }
        }
        
        static {
            QUERY = Query.and(Query.not((Query<Object>)DeathComponent.getComponentType()), MovementStatesComponent.getComponentType());
        }
    }
    
    public static class PlayerDamageFilterSystem extends DamageEventSystem
    {
        @Nonnull
        private static final Query<EntityStore> QUERY;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getFilterDamageGroup();
        }
        
        @Override
        public Query<EntityStore> getQuery() {
            return PlayerDamageFilterSystem.QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            final World world = store.getExternalData().getWorld();
            final Player playerComponent = archetypeChunk.getComponent(index, Player.getComponentType());
            assert playerComponent != null;
            if (playerComponent.hasSpawnProtection()) {
                damage.setCancelled(true);
                return;
            }
            if (!world.getWorldConfig().isPvpEnabled()) {
                final Damage.Source source = damage.getSource();
                if (source instanceof final Damage.EntitySource entitySource) {
                    final Ref<EntityStore> sourceRef = entitySource.getRef();
                    if (sourceRef.isValid() && commandBuffer.getComponent(sourceRef, Player.getComponentType()) != null) {
                        damage.setCancelled(true);
                    }
                }
            }
        }
        
        static {
            QUERY = Player.getComponentType();
        }
    }
    
    public static class TrackLastDamage extends DamageEventSystem
    {
        @Nonnull
        private static final ComponentType<EntityStore, DamageDataComponent> DAMAGE_DATA_COMPONENT_TYPE;
        @Nonnull
        private static final Query<EntityStore> QUERY;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getInspectDamageGroup();
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return TrackLastDamage.QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            final TimeResource timeResource = commandBuffer.getResource(TimeResource.getResourceType());
            final DamageDataComponent damageDataComponent = archetypeChunk.getComponent(index, TrackLastDamage.DAMAGE_DATA_COMPONENT_TYPE);
            assert damageDataComponent != null;
            damageDataComponent.setLastDamageTime(timeResource.getNow());
        }
        
        static {
            DAMAGE_DATA_COMPONENT_TYPE = DamageDataComponent.getComponentType();
            QUERY = Query.and(AllLegacyLivingEntityTypesQuery.INSTANCE, TrackLastDamage.DAMAGE_DATA_COMPONENT_TYPE);
        }
    }
    
    public static class DamageArmor extends DamageEventSystem
    {
        @Nonnull
        private static final Query<EntityStore> QUERY;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getInspectDamageGroup();
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return DamageArmor.QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            final LivingEntity entity = (LivingEntity)EntityUtils.getEntity(index, archetypeChunk);
            assert entity != null;
            final Ref<EntityStore> ref = archetypeChunk.getReferenceTo(index);
            final DamageCause damageCause = damage.getCause();
            if (damageCause.isDurabilityLoss()) {
                final ItemContainer armor = entity.getInventory().getArmor();
                final ShortArrayList armorPartIndexes = new ShortArrayList();
                int slot = 0;
                armor.forEachWithMeta((slot, itemStack, _armorPartIndexes) -> {
                    if (!itemStack.isBroken()) {
                        _armorPartIndexes.add(slot);
                    }
                    return;
                }, armorPartIndexes);
                if (!armorPartIndexes.isEmpty()) {
                    slot = armorPartIndexes.getShort(RandomExtra.randomRange(armorPartIndexes.size()));
                    entity.decreaseItemStackDurability(ref, armor.getItemStack((short)slot), -3, slot, commandBuffer);
                }
            }
        }
        
        static {
            QUERY = AllLegacyLivingEntityTypesQuery.INSTANCE;
        }
    }
    
    public static class DamageStamina extends DamageEventSystem implements EntityStatsSystems.StatModifyingSystem
    {
        @Nonnull
        private static final Query<EntityStore> QUERY;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getInspectDamageGroup();
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return DamageStamina.QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage event) {
        }
        
        @Override
        public void handleInternal(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            final EntityStatMap entityStatMapComponent = archetypeChunk.getComponent(index, EntityStatMap.getComponentType());
            assert entityStatMapComponent != null;
            final DamageDataComponent damageDataComponent = archetypeChunk.getComponent(index, DamageDataComponent.getComponentType());
            assert damageDataComponent != null;
            if (damageDataComponent.getCurrentWielding() == null) {
                return;
            }
            final WieldingInteraction.StaminaCost staminaCost = damageDataComponent.getCurrentWielding().getStaminaCost();
            if (staminaCost == null) {
                return;
            }
            final Boolean isBlocked = damage.getMetaStore().getIfPresentMetaObject(Damage.BLOCKED);
            if (isBlocked != null && isBlocked) {
                float staminaToConsume = staminaCost.computeStaminaAmountToConsume(damage.getInitialAmount(), entityStatMapComponent);
                final Float multiplier = damage.getIfPresentMetaObject(Damage.STAMINA_DRAIN_MULTIPLIER);
                if (multiplier != null) {
                    staminaToConsume *= multiplier;
                }
                entityStatMapComponent.subtractStatValue(DefaultEntityStatTypes.getStamina(), staminaToConsume);
            }
        }
        
        static {
            QUERY = Query.and(DamageDataComponent.getComponentType(), EntityStatMap.getComponentType());
        }
    }
    
    public static class DamageAttackerTool extends DamageEventSystem
    {
        @Nonnull
        private static final Query<EntityStore> QUERY;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getInspectDamageGroup();
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return DamageAttackerTool.QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            if (damage.getCause().isDurabilityLoss()) {
                final Damage.Source source = damage.getSource();
                if (source instanceof final Damage.EntitySource entitySource) {
                    final Ref<EntityStore> sourceRef = entitySource.getRef();
                    if (!sourceRef.isValid()) {
                        return;
                    }
                    final Entity sourceEntity = EntityUtils.getEntity(sourceRef, commandBuffer);
                    if (sourceEntity instanceof final LivingEntity sourceLivingEntity) {
                        final Inventory sourceInventory = sourceLivingEntity.getInventory();
                        final byte activeHotbarSlot = sourceInventory.getActiveHotbarSlot();
                        if (activeHotbarSlot != -1) {
                            sourceLivingEntity.decreaseItemStackDurability(sourceRef, sourceInventory.getItemInHand(), -1, sourceInventory.getActiveHotbarSlot(), commandBuffer);
                        }
                    }
                }
            }
        }
        
        static {
            QUERY = AllLegacyLivingEntityTypesQuery.INSTANCE;
        }
    }
    
    public static class PlayerHitIndicators extends DamageEventSystem
    {
        @Nonnull
        private static final ComponentType<EntityStore, TransformComponent> TRANSFORM_COMPONENT_TYPE;
        @Nonnull
        private static final Query<EntityStore> QUERY;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getInspectDamageGroup();
        }
        
        @Override
        public Query<EntityStore> getQuery() {
            return PlayerHitIndicators.QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            final PlayerRef playerRefComponent = archetypeChunk.getComponent(index, PlayerRef.getComponentType());
            assert playerRefComponent != null;
            final Damage.Source source = damage.getSource();
            if (!(source instanceof Damage.EntitySource)) {
                return;
            }
            final Damage.EntitySource entitySource = (Damage.EntitySource)source;
            final Ref<EntityStore> sourceRef = entitySource.getRef();
            if (!sourceRef.isValid()) {
                return;
            }
            final DamageCause damageCause = damage.getCause();
            if (damageCause == null) {
                return;
            }
            final TransformComponent sourceTransformComponent = commandBuffer.getComponent(sourceRef, PlayerHitIndicators.TRANSFORM_COMPONENT_TYPE);
            if (sourceTransformComponent == null) {
                return;
            }
            final Vector3d position = sourceTransformComponent.getPosition();
            playerRefComponent.getPacketHandler().writeNoCache(new DamageInfo(new com.hypixel.hytale.protocol.Vector3d(position.getX(), position.getY(), position.getZ()), damage.getAmount(), damageCause.toPacket()));
        }
        
        static {
            TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType();
            QUERY = PlayerRef.getComponentType();
        }
    }
    
    public static class ReticleEvents extends DamageEventSystem
    {
        private static final int EVENT_ON_HIT_TAG_INDEX;
        private static final int EVENT_ON_KILL_TAG_INDEX;
        private static final ReticleEvent ON_HIT;
        private static final ReticleEvent ON_KILL;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getInspectDamageGroup();
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return (Query<EntityStore>)Archetype.empty();
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            final boolean isDead = archetypeChunk.getArchetype().contains(DeathComponent.getComponentType());
            if (damage.getAmount() <= 0.0f) {
                return;
            }
            final Damage.Source source = damage.getSource();
            if (!(source instanceof Damage.EntitySource)) {
                return;
            }
            final Damage.EntitySource entitySource = (Damage.EntitySource)source;
            final Ref<EntityStore> sourceRef = entitySource.getRef();
            if (!sourceRef.isValid()) {
                return;
            }
            final PlayerRef sourcePlayerRef = commandBuffer.getComponent(sourceRef, PlayerRef.getComponentType());
            if (sourcePlayerRef == null || !sourcePlayerRef.isValid()) {
                return;
            }
            sourcePlayerRef.getPacketHandler().writeNoCache(isDead ? ReticleEvents.ON_KILL : ReticleEvents.ON_HIT);
        }
        
        static {
            EVENT_ON_HIT_TAG_INDEX = AssetRegistry.getOrCreateTagIndex("OnHit");
            EVENT_ON_KILL_TAG_INDEX = AssetRegistry.getOrCreateTagIndex("OnKill");
            ON_HIT = new ReticleEvent(ReticleEvents.EVENT_ON_HIT_TAG_INDEX);
            ON_KILL = new ReticleEvent(ReticleEvents.EVENT_ON_KILL_TAG_INDEX);
        }
    }
    
    public static class EntityUIEvents extends DamageEventSystem
    {
        @Nonnull
        private final ComponentType<EntityStore, EntityTrackerSystems.Visible> visibleComponentType;
        @Nonnull
        private final ComponentType<EntityStore, UIComponentList> uiComponentListComponentType;
        @Nonnull
        private final Query<EntityStore> query;
        
        public EntityUIEvents() {
            this.visibleComponentType = EntityModule.get().getVisibleComponentType();
            this.uiComponentListComponentType = EntityUIModule.get().getUIComponentListType();
            this.query = (Query<EntityStore>)Query.and(this.visibleComponentType, this.uiComponentListComponentType);
        }
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getInspectDamageGroup();
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return this.query;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            if (damage.getAmount() <= 0.0f) {
                return;
            }
            final Damage.Source source = damage.getSource();
            if (!(source instanceof Damage.EntitySource)) {
                return;
            }
            final Damage.EntitySource entitySource = (Damage.EntitySource)source;
            final Ref<EntityStore> sourceRef = entitySource.getRef();
            if (!sourceRef.isValid()) {
                return;
            }
            final PlayerRef sourcePlayerRef = commandBuffer.getComponent(sourceRef, PlayerRef.getComponentType());
            if (sourcePlayerRef == null || !sourcePlayerRef.isValid()) {
                return;
            }
            final EntityTrackerSystems.EntityViewer sourceEntityViewerComponent = commandBuffer.getComponent(sourceRef, EntityTrackerSystems.EntityViewer.getComponentType());
            if (sourceEntityViewerComponent != null) {
                final Float hitAngleDeg = damage.getIfPresentMetaObject(Damage.HIT_ANGLE);
                queueUpdateFor(archetypeChunk.getReferenceTo(index), damage.getAmount(), hitAngleDeg, sourceEntityViewerComponent);
            }
        }
        
        private static void queueUpdateFor(@Nonnull final Ref<EntityStore> ref, final float damageAmount, @Nullable final Float hitAngleDeg, @Nonnull final EntityTrackerSystems.EntityViewer viewer) {
            final ComponentUpdate update = new ComponentUpdate();
            update.type = ComponentUpdateType.CombatText;
            final CombatTextUpdate combatTextUpdate = new CombatTextUpdate();
            combatTextUpdate.hitAngleDeg = ((hitAngleDeg == null) ? 0.0f : hitAngleDeg);
            combatTextUpdate.text = Integer.toString((int)Math.floor(damageAmount));
            update.combatTextUpdate = combatTextUpdate;
            viewer.queueUpdate(ref, update);
        }
    }
    
    @Deprecated
    public static class WieldingDamageReduction extends DamageEventSystem
    {
        @Nonnull
        private static final ComponentType<EntityStore, TransformComponent> TRANSFORM_COMPONENT_TYPE;
        @Nonnull
        private static final Query<EntityStore> QUERY;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getFilterDamageGroup();
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return WieldingDamageReduction.QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            final DamageDataComponent damageDataComponent = archetypeChunk.getComponent(index, DamageDataComponent.getComponentType());
            assert damageDataComponent != null;
            final InteractionManager interactionManager = archetypeChunk.getComponent(index, InteractionModule.get().getInteractionManagerComponent());
            assert interactionManager != null;
            final WieldingInteraction wielding = damageDataComponent.getCurrentWielding();
            if (wielding == null) {
                return;
            }
            final WieldingInteraction.AngledWielding angledWielding = wielding.getAngledWielding();
            final Ref<EntityStore> ref = archetypeChunk.getReferenceTo(index);
            final TransformComponent transformComponent = archetypeChunk.getComponent(index, WieldingDamageReduction.TRANSFORM_COMPONENT_TYPE);
            assert transformComponent != null;
            final Vector3d targetPosition = transformComponent.getPosition();
            final Vector3f targetRotation = transformComponent.getRotation();
            final Damage.Source source = damage.getSource();
            if (!(source instanceof Damage.EntitySource)) {
                return;
            }
            final Damage.EntitySource entitySource = (Damage.EntitySource)source;
            final Ref<EntityStore> sourceRef = entitySource.getRef();
            if (!sourceRef.isValid()) {
                return;
            }
            final TransformComponent sourceTransformComponent = commandBuffer.getComponent(sourceRef, WieldingDamageReduction.TRANSFORM_COMPONENT_TYPE);
            if (sourceTransformComponent == null) {
                return;
            }
            final int damageCauseIndex = damage.getDamageCauseIndex();
            float wieldingModifier = 1.0f;
            float angledWieldingModifier = 1.0f;
            String blockedInteractions = null;
            final Int2FloatMap wieldingDamageModifiers = wielding.getDamageModifiers();
            if (!wieldingDamageModifiers.isEmpty()) {
                wieldingModifier = wieldingDamageModifiers.getOrDefault(damageCauseIndex, 1.0f);
                final DamageEffects wieldingBlockedEffects = wielding.getBlockedEffects();
                if (wieldingBlockedEffects != null) {
                    wieldingBlockedEffects.addToDamage(damage);
                }
                final String wieldingBlockedInteractions = wielding.getBlockedInteractions();
                if (wieldingBlockedInteractions != null) {
                    blockedInteractions = wieldingBlockedInteractions;
                }
                damage.putMetaObject(Damage.BLOCKED, Boolean.TRUE);
            }
            if (angledWielding != null) {
                final Int2FloatMap angledWieldingDamageModifiers = angledWielding.getDamageModifiers();
                if (angledWieldingDamageModifiers.containsKey(damageCauseIndex)) {
                    final Vector3d sourcePosition = sourceTransformComponent.getPosition();
                    float angleBetween = TrigMathUtil.atan2(sourcePosition.x - targetPosition.x, sourcePosition.z - targetPosition.z);
                    angleBetween = MathUtil.wrapAngle(angleBetween + 3.1415927f - targetRotation.getYaw());
                    if (Math.abs(MathUtil.compareAngle(angleBetween, angledWielding.getAngleRad())) < angledWielding.getAngleDistanceRad()) {
                        angledWieldingModifier = angledWieldingDamageModifiers.getOrDefault(damageCauseIndex, 1.0f);
                        final DamageEffects wieldingBlockedEffects2 = wielding.getBlockedEffects();
                        if (wieldingBlockedEffects2 != null) {
                            wieldingBlockedEffects2.addToDamage(damage);
                        }
                        final String wieldingBlockedInteractions2 = wielding.getBlockedInteractions();
                        if (wieldingBlockedInteractions2 != null) {
                            blockedInteractions = wieldingBlockedInteractions2;
                        }
                        damage.putMetaObject(Damage.BLOCKED, Boolean.TRUE);
                    }
                }
            }
            damage.setAmount(damage.getAmount() * wieldingModifier * angledWieldingModifier);
            if (blockedInteractions != null) {
                final NetworkId sourceNetworkIdComponent = commandBuffer.getComponent(sourceRef, NetworkId.getComponentType());
                if (sourceNetworkIdComponent != null) {
                    final InteractionContext context = InteractionContext.forInteraction(interactionManager, ref, InteractionType.Wielding, commandBuffer);
                    final DynamicMetaStore<InteractionContext> contextMetaStore = context.getMetaStore();
                    contextMetaStore.putMetaObject(Interaction.TARGET_ENTITY, sourceRef);
                    contextMetaStore.putMetaObject(Interaction.DAMAGE, damage);
                    final int networkId = sourceNetworkIdComponent.getId();
                    final InteractionChain chain = interactionManager.initChain(InteractionType.Wielding, context, RootInteraction.getRootInteractionOrUnknown(blockedInteractions), networkId, null, false);
                    interactionManager.queueExecuteChain(chain);
                }
            }
        }
        
        static {
            TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType();
            QUERY = Query.and(AllLegacyLivingEntityTypesQuery.INSTANCE, DamageDataComponent.getComponentType(), InteractionModule.get().getInteractionManagerComponent(), WieldingDamageReduction.TRANSFORM_COMPONENT_TYPE);
        }
    }
    
    @Deprecated
    public static class WieldingKnockbackReduction extends DamageEventSystem
    {
        @Nonnull
        private static final ComponentType<EntityStore, TransformComponent> TRANSFORM_COMPONENT_TYPE;
        @Nonnull
        private static final Query<EntityStore> QUERY;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getFilterDamageGroup();
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return WieldingKnockbackReduction.QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage event) {
        }
        
        @Override
        public void handleInternal(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            final DamageDataComponent damageDataComponent = archetypeChunk.getComponent(index, DamageDataComponent.getComponentType());
            assert damageDataComponent != null;
            final TransformComponent transformComponent = archetypeChunk.getComponent(index, WieldingKnockbackReduction.TRANSFORM_COMPONENT_TYPE);
            assert transformComponent != null;
            final WieldingInteraction wielding = damageDataComponent.getCurrentWielding();
            if (wielding == null) {
                return;
            }
            final Int2DoubleMap knockbackModifiers = wielding.getKnockbackModifiers();
            final WieldingInteraction.AngledWielding angledWielding = wielding.getAngledWielding();
            final KnockbackComponent knockbackComponent = damage.getIfPresentMetaObject(Damage.KNOCKBACK_COMPONENT);
            if (knockbackComponent == null) {
                return;
            }
            final Damage.Source source = damage.getSource();
            if (!(source instanceof Damage.EntitySource)) {
                return;
            }
            final Damage.EntitySource entitySource = (Damage.EntitySource)source;
            final Ref<EntityStore> sourceRef = entitySource.getRef();
            if (!sourceRef.isValid()) {
                return;
            }
            final TransformComponent sourceTransformComponent = commandBuffer.getComponent(sourceRef, WieldingKnockbackReduction.TRANSFORM_COMPONENT_TYPE);
            if (sourceTransformComponent == null) {
                return;
            }
            final int damageCauseIndex = damage.getDamageCauseIndex();
            double angledWieldingModifier = 1.0;
            final double wieldingModifier = knockbackModifiers.getOrDefault(damageCauseIndex, 1.0);
            if (angledWielding != null) {
                final Int2DoubleMap angledWieldingKnockbackModifiers = angledWielding.getKnockbackModifiers();
                if (angledWieldingKnockbackModifiers.containsKey(damageCauseIndex)) {
                    final Vector3d targetPos = transformComponent.getPosition();
                    final Vector3d attackerPos = sourceTransformComponent.getPosition();
                    float angleBetween = TrigMathUtil.atan2(attackerPos.x - targetPos.x, attackerPos.z - targetPos.z);
                    angleBetween = MathUtil.wrapAngle(angleBetween + 3.1415927f - transformComponent.getRotation().getYaw());
                    if (Math.abs(MathUtil.compareAngle(angleBetween, angledWielding.getAngleRad())) < angledWielding.getAngleDistanceRad()) {
                        angledWieldingModifier = angledWieldingKnockbackModifiers.getOrDefault(damageCauseIndex, 1.0);
                    }
                }
            }
            knockbackComponent.addModifier(wieldingModifier);
            knockbackComponent.addModifier(angledWieldingModifier);
        }
        
        static {
            TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType();
            QUERY = Query.and(AllLegacyLivingEntityTypesQuery.INSTANCE, DamageDataComponent.getComponentType(), WieldingKnockbackReduction.TRANSFORM_COMPONENT_TYPE);
        }
    }
    
    @Deprecated
    public static class ArmorKnockbackReduction extends DamageEventSystem
    {
        @Nonnull
        private static final ComponentType<EntityStore, TransformComponent> TRANSFORM_COMPONENT_TYPE;
        @Nonnull
        private static final Query<EntityStore> QUERY;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getFilterDamageGroup();
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return ArmorKnockbackReduction.QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage event) {
        }
        
        @Override
        public void handleInternal(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            final LivingEntity entity = (LivingEntity)EntityUtils.getEntity(index, archetypeChunk);
            assert entity != null;
            final Inventory inventory = entity.getInventory();
            if (inventory == null) {
                return;
            }
            final ItemContainer armorContainer = inventory.getArmor();
            if (armorContainer == null) {
                return;
            }
            final KnockbackComponent knockbackComponent = damage.getIfPresentMetaObject(Damage.KNOCKBACK_COMPONENT);
            if (knockbackComponent == null) {
                return;
            }
            float knockbackResistanceModifier = 0.0f;
            for (short i = 0; i < armorContainer.getCapacity(); ++i) {
                final ItemStack itemStack = armorContainer.getItemStack(i);
                if (itemStack != null) {
                    if (!itemStack.isEmpty()) {
                        final Item item = itemStack.getItem();
                        final ItemArmor itemArmor = item.getArmor();
                        if (itemArmor != null) {
                            final Map<DamageCause, Float> knockbackResistances = itemArmor.getKnockbackResistances();
                            if (knockbackResistances != null) {
                                final DamageCause damageCause = damage.getCause();
                                knockbackResistanceModifier += knockbackResistances.get(damageCause);
                            }
                        }
                    }
                }
            }
            knockbackComponent.addModifier(Math.max(1.0f - knockbackResistanceModifier, 0.0f));
        }
        
        static {
            TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType();
            QUERY = Query.and(AllLegacyLivingEntityTypesQuery.INSTANCE, DamageDataComponent.getComponentType(), ArmorKnockbackReduction.TRANSFORM_COMPONENT_TYPE);
        }
    }
    
    @Deprecated
    public static class ArmorDamageReduction extends DamageEventSystem
    {
        @Nonnull
        private static final Query<EntityStore> QUERY;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getFilterDamageGroup();
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return ArmorDamageReduction.QUERY;
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Damage damage) {
            final LivingEntity entity = (LivingEntity)EntityUtils.getEntity(index, archetypeChunk);
            assert entity != null;
            final World world = commandBuffer.getExternalData().getWorld();
            final Ref<EntityStore> ref = archetypeChunk.getReferenceTo(index);
            final Map<DamageCause, ArmorResistanceModifiers> resistances = getResistanceModifiers(world, entity.getInventory().getArmor(), entity.canApplyItemStackPenalties(ref, commandBuffer), archetypeChunk.getComponent(index, EffectControllerComponent.getComponentType()));
            if (!damage.getCause().doesBypassResistances() && !resistances.isEmpty()) {
                ArmorResistanceModifiers damageModEntry = resistances.get(damage.getCause());
                if (damageModEntry == null) {
                    return;
                }
                float amount = Math.max(0.0f, damage.getAmount() - damageModEntry.flatModifier);
                amount *= Math.max(0.0f, 1.0f - damageModEntry.multiplierModifier);
                while (damageModEntry.inheritedParentId != null) {
                    damageModEntry = resistances.get(damageModEntry.inheritedParentId);
                    if (damageModEntry == null) {
                        break;
                    }
                    amount = Math.max(0.0f, damage.getAmount() - damageModEntry.flatModifier);
                    amount *= Math.max(0.0f, 1.0f - damageModEntry.multiplierModifier);
                }
                damage.setAmount(amount);
            }
        }
        
        @Nonnull
        public static Map<DamageCause, ArmorResistanceModifiers> getResistanceModifiers(@Nonnull final World world, @Nonnull final ItemContainer inventory, final boolean canApplyItemStackPenalties, @Nullable final EffectControllerComponent effectControllerComponent) {
            final Map<DamageCause, ArmorResistanceModifiers> result = new Object2ObjectOpenHashMap<DamageCause, ArmorResistanceModifiers>();
            for (short index = 0; index < inventory.getCapacity(); ++index) {
                final ItemStack itemStack = inventory.getItemStack(index);
                if (itemStack != null) {
                    if (!itemStack.isEmpty()) {
                        final Item item = itemStack.getItem();
                        final ItemArmor itemArmor = item.getArmor();
                        if (itemArmor != null) {
                            final Map<DamageCause, StaticModifier[]> resistances = itemArmor.getDamageResistanceValues();
                            final double flatResistance = itemArmor.getBaseDamageResistance();
                            if (resistances != null) {
                                for (final Map.Entry<DamageCause, StaticModifier[]> entry : resistances.entrySet()) {
                                    if (entry.getValue() == null) {
                                        continue;
                                    }
                                    calculateResistanceEntryModifications(entry, world, result, canApplyItemStackPenalties, itemStack.isBroken(), flatResistance);
                                }
                            }
                        }
                    }
                }
            }
            addResistanceModifiersFromEntityEffects(result, effectControllerComponent);
            return result;
        }
        
        private static void calculateResistanceEntryModifications(@Nonnull final Map.Entry<DamageCause, StaticModifier[]> entry, @Nonnull final World world, @Nonnull final Map<DamageCause, ArmorResistanceModifiers> result, final boolean canApplyItemStackPenalties, final boolean itemStackIsBroken, final double flatResistance) {
            final ArmorResistanceModifiers mods = result.computeIfAbsent(entry.getKey(), key -> new ArmorResistanceModifiers());
            final StaticModifier[] valueArray = entry.getValue();
            for (int x = 0; x < valueArray.length; ++x) {
                final StaticModifier entryValue = valueArray[x];
                if (entryValue.getCalculationType() == StaticModifier.CalculationType.ADDITIVE) {
                    final ArmorResistanceModifiers armorResistanceModifiers = mods;
                    armorResistanceModifiers.flatModifier += (int)entryValue.getAmount();
                }
                else {
                    final ArmorResistanceModifiers armorResistanceModifiers2 = mods;
                    armorResistanceModifiers2.multiplierModifier += entryValue.getAmount();
                }
            }
            final ArmorResistanceModifiers armorResistanceModifiers3 = mods;
            armorResistanceModifiers3.flatModifier += (int)flatResistance;
            final DamageCause damageCause = entry.getKey();
            if (damageCause != null && damageCause.getInherits() != null) {
                mods.inheritedParentId = DamageCause.getAssetMap().getAsset(damageCause.getInherits());
            }
            if (canApplyItemStackPenalties && itemStackIsBroken) {
                final BrokenPenalties brokenPenalties = world.getGameplayConfig().getItemDurabilityConfig().getBrokenPenalties();
                final double penalty = brokenPenalties.getWeapon(0.0);
                final ArmorResistanceModifiers armorResistanceModifiers4 = mods;
                armorResistanceModifiers4.flatModifier *= (int)(1.0 - penalty);
                final ArmorResistanceModifiers armorResistanceModifiers5 = mods;
                armorResistanceModifiers5.multiplierModifier *= (float)(1.0 - penalty);
            }
        }
        
        private static void addResistanceModifiersFromEntityEffects(final Map<DamageCause, ArmorResistanceModifiers> resistanceModifiers, final EffectControllerComponent effectControllerComponent) {
            if (effectControllerComponent == null) {
                return;
            }
            for (final int entityEffectIndex : effectControllerComponent.getActiveEffects().keySet()) {
                final EntityEffect entityEffectData = EntityEffect.getAssetMap().getAsset(entityEffectIndex);
                if (entityEffectData == null) {
                    continue;
                }
                final Map<DamageCause, StaticModifier[]> damageResistanceValues = entityEffectData.getDamageResistanceValues();
                if (damageResistanceValues == null) {
                    continue;
                }
                if (damageResistanceValues.isEmpty()) {
                    continue;
                }
                for (final Map.Entry<DamageCause, StaticModifier[]> entry : damageResistanceValues.entrySet()) {
                    final ArmorResistanceModifiers modifier = resistanceModifiers.computeIfAbsent(entry.getKey(), damageCause -> new ArmorResistanceModifiers());
                    for (final StaticModifier staticModifier : entry.getValue()) {
                        if (staticModifier.getCalculationType() == StaticModifier.CalculationType.ADDITIVE) {
                            final ArmorResistanceModifiers armorResistanceModifiers = modifier;
                            armorResistanceModifiers.flatModifier += (int)staticModifier.getAmount();
                        }
                        else if (staticModifier.getCalculationType() == StaticModifier.CalculationType.MULTIPLICATIVE) {
                            final ArmorResistanceModifiers armorResistanceModifiers2 = modifier;
                            armorResistanceModifiers2.multiplierModifier += staticModifier.getAmount();
                        }
                    }
                }
            }
        }
        
        static {
            QUERY = AllLegacyLivingEntityTypesQuery.INSTANCE;
        }
        
        public static class ArmorResistanceModifiers
        {
            public int flatModifier;
            public float multiplierModifier;
            @Nullable
            public DamageCause inheritedParentId;
        }
    }
    
    @Deprecated
    public static class HackKnockbackValues extends EntityTickingSystem<EntityStore>
    {
        public static float PLAYER_KNOCKBACK_SCALE;
        private static final Query<EntityStore> QUERY;
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getFilterDamageGroup();
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return HackKnockbackValues.QUERY;
        }
        
        @Override
        public void tick(final float dt, final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final KnockbackComponent knockbackComponent = archetypeChunk.getComponent(index, KnockbackComponent.getComponentType());
            assert knockbackComponent != null;
            if (knockbackComponent.getVelocityConfig() == null || SplitVelocity.SHOULD_MODIFY_VELOCITY) {
                final Vector3d velocity;
                final Vector3d vector = velocity = knockbackComponent.getVelocity();
                velocity.x *= HackKnockbackValues.PLAYER_KNOCKBACK_SCALE;
                final Vector3d vector3d = vector;
                vector3d.z *= HackKnockbackValues.PLAYER_KNOCKBACK_SCALE;
                knockbackComponent.setVelocity(vector);
            }
        }
        
        @Override
        public boolean isParallel(final int archetypeChunkSize, final int taskCount) {
            return EntityTickingSystem.maybeUseParallel(archetypeChunkSize, taskCount);
        }
        
        static {
            HackKnockbackValues.PLAYER_KNOCKBACK_SCALE = 25.0f;
            QUERY = Query.and(AllLegacyLivingEntityTypesQuery.INSTANCE, KnockbackComponent.getComponentType());
        }
    }
}
