package com.hypixel.hytale.server.npc.blackboard.view.combat; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; import com.hypixel.hytale.component.AddReason; import com.hypixel.hytale.component.ArchetypeChunk; import com.hypixel.hytale.component.CommandBuffer; import com.hypixel.hytale.component.Component; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Holder; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.RemoveReason; import com.hypixel.hytale.component.Resource; import com.hypixel.hytale.component.ResourceType; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.HolderSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; import com.hypixel.hytale.server.core.entity.EntityUtils; import com.hypixel.hytale.server.core.entity.InteractionManager; import com.hypixel.hytale.server.core.entity.LivingEntity; import com.hypixel.hytale.server.core.modules.entity.AllLegacyEntityTypesQuery; import com.hypixel.hytale.server.core.modules.interaction.InteractionModule; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.RootInteraction; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.client.ChargingInteraction; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import com.hypixel.hytale.server.npc.NPCPlugin; import com.hypixel.hytale.server.npc.role.support.CombatSupport; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.util.ArrayDeque; import java.util.Collections; import java.util.List; import java.util.Set; import javax.annotation.Nonnull; public class CombatViewSystems { private static void clearCombatData(@Nonnull CombatViewSystems.CombatData combatData, @Nonnull CombatViewSystems.CombatDataPool dataPool) { if (combatData.interpreted) { List dataList = combatData.combatData; for (int i = 0; i < dataList.size(); i++) { dataPool.releaseCombatData(dataList.get(i)); } dataList.clear(); combatData.interpreted = false; } } @Nonnull public static List getCombatData(@Nonnull Ref reference) { CombatViewSystems.CombatData combatData = reference.getStore().getComponent(reference, CombatViewSystems.CombatData.getComponentType()); if (combatData.interpreted) { return combatData.unmodifiableCombatData; } else { InteractionManager interactionManager = reference.getStore().getComponent(reference, InteractionModule.get().getInteractionManagerComponent()); CombatViewSystems.CombatDataPool combatDataPool = reference.getStore().getResource(CombatViewSystems.CombatDataPool.getResourceType()); List dataList = combatData.combatData; IndexedLookupTableAssetMap interactionAssetMap = RootInteraction.getAssetMap(); Set attackInteractions = interactionAssetMap.getKeysForTag(CombatSupport.ATTACK_TAG_INDEX); Set meleeInteractions = interactionAssetMap.getKeysForTag(CombatSupport.MELEE_TAG_INDEX); Set rangedInteractions = interactionAssetMap.getKeysForTag(CombatSupport.RANGED_TAG_INDEX); Set blockInteractions = interactionAssetMap.getKeysForTag(CombatSupport.BLOCK_TAG_INDEX); LivingEntity entity = (LivingEntity)EntityUtils.getEntity(reference, reference.getStore()); interactionManager.forEachInteraction((chain, interaction, list) -> { String rootId = chain.getRootInteraction().getId(); if (!attackInteractions.contains(rootId)) { return list; } else { InterpretedCombatData entry = combatDataPool.getEmptyCombatData(); entry.setAttack(rootId); entry.setCurrentElapsedTime(chain.getTimeInSeconds()); entry.setCharging(interaction instanceof ChargingInteraction); entry.setPerformingMeleeAttack(meleeInteractions.contains(rootId)); entry.setPerformingRangedAttack(rangedInteractions.contains(rootId)); entry.setPerformingBlock(blockInteractions.contains(rootId)); list.add(entry); return list; } }, dataList); combatData.interpreted = true; return combatData.unmodifiableCombatData; } } public static class CombatData implements Component { private final List combatData = new ObjectArrayList(); private final List unmodifiableCombatData = Collections.unmodifiableList(this.combatData); private boolean interpreted; public static ComponentType getComponentType() { return NPCPlugin.get().getCombatDataComponentType(); } @Nonnull @Override public Component clone() { CombatViewSystems.CombatData data = new CombatViewSystems.CombatData(); data.interpreted = this.interpreted; for (int i = 0; i < this.combatData.size(); i++) { data.combatData.add(this.combatData.get(i).clone()); } return data; } } public static class CombatDataPool implements Resource { private final ArrayDeque combatDataPool = new ArrayDeque<>(); public static ResourceType getResourceType() { return NPCPlugin.get().getCombatDataPoolResourceType(); } @Nonnull @Override public Resource clone() { return new CombatViewSystems.CombatDataPool(); } public InterpretedCombatData getEmptyCombatData() { return this.combatDataPool.isEmpty() ? new InterpretedCombatData() : this.combatDataPool.poll(); } public void releaseCombatData(@Nonnull InterpretedCombatData combatData) { this.combatDataPool.push(combatData); } } public static class Ensure extends HolderSystem { private final ComponentType combatDataComponentType; public Ensure(ComponentType combatDataComponentType) { this.combatDataComponentType = combatDataComponentType; } @Nonnull @Override public Query getQuery() { return AllLegacyEntityTypesQuery.INSTANCE; } @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { holder.ensureComponent(this.combatDataComponentType); } @Override public void onEntityRemoved(@Nonnull Holder holder, @Nonnull RemoveReason reason, @Nonnull Store store) { } } public static class EntityRemoved extends HolderSystem { private final ComponentType combatDataComponentType; private final ResourceType dataPoolResourceType; public EntityRemoved( ComponentType combatDataComponentType, ResourceType dataPoolResourceType ) { this.combatDataComponentType = combatDataComponentType; this.dataPoolResourceType = dataPoolResourceType; } @Override public Query getQuery() { return this.combatDataComponentType; } @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { } @Override public void onEntityRemoved(@Nonnull Holder holder, @Nonnull RemoveReason reason, @Nonnull Store store) { CombatViewSystems.CombatData combatData = holder.getComponent(this.combatDataComponentType); CombatViewSystems.CombatDataPool dataPool = store.getResource(this.dataPoolResourceType); CombatViewSystems.clearCombatData(combatData, dataPool); } } public static class Ticking extends EntityTickingSystem { private final ComponentType combatDataComponentType; private final ResourceType dataPoolResourceType; public Ticking( ComponentType combatDataComponentType, ResourceType dataPoolResourceType ) { this.combatDataComponentType = combatDataComponentType; this.dataPoolResourceType = dataPoolResourceType; } @Override public Query getQuery() { return this.combatDataComponentType; } @Override public boolean isParallel(int archetypeChunkSize, int taskCount) { return false; } @Override public void tick( float dt, int index, @Nonnull ArchetypeChunk archetypeChunk, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { CombatViewSystems.CombatData combatData = archetypeChunk.getComponent(index, this.combatDataComponentType); CombatViewSystems.CombatDataPool dataPool = store.getResource(this.dataPoolResourceType); CombatViewSystems.clearCombatData(combatData, dataPool); } } }