package com.hypixel.hytale.server.npc.systems;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.Archetype;
import com.hypixel.hytale.component.ArchetypeChunk;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.component.Holder;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.ResourceType;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.component.SystemGroup;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.protocol.GameMode;
import com.hypixel.hytale.server.core.asset.type.gameplay.DeathConfig;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.inventory.Inventory;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.server.core.modules.entity.damage.Damage;
import com.hypixel.hytale.server.core.modules.entity.damage.DamageEventSystem;
import com.hypixel.hytale.server.core.modules.entity.damage.DamageModule;
import com.hypixel.hytale.server.core.modules.entity.damage.DeathComponent;
import com.hypixel.hytale.server.core.modules.entity.damage.DeathSystems;
import com.hypixel.hytale.server.core.modules.entity.item.ItemComponent;
import com.hypixel.hytale.server.core.modules.entity.player.PlayerSettings;
import com.hypixel.hytale.server.core.modules.item.ItemModule;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.server.npc.blackboard.Blackboard;
import com.hypixel.hytale.server.npc.blackboard.view.event.entity.EntityEventType;
import com.hypixel.hytale.server.npc.blackboard.view.event.entity.EntityEventView;
import com.hypixel.hytale.server.npc.entities.NPCEntity;
import com.hypixel.hytale.server.npc.role.Role;
import com.hypixel.hytale.server.npc.util.DamageData;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class NPCDamageSystems {
public NPCDamageSystems() {
}
public static class FilterDamageSystem extends DamageEventSystem {
@Nonnull
private final Query<EntityStore> query = NPCEntity.getComponentType();
public FilterDamageSystem() {
}
@Nullable
public SystemGroup<EntityStore> getGroup() {
return DamageModule.get().getFilterDamageGroup();
}
@Nonnull
public Query<EntityStore> getQuery() {
return this.query;
}
public void handle(int index, @Nonnull ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull Store<EntityStore> store, @Nonnull CommandBuffer<EntityStore> commandBuffer, @Nonnull Damage damage) {
NPCEntity npcComponent = (NPCEntity)archetypeChunk.getComponent(index, NPCEntity.getComponentType());
assert npcComponent != null;
if (damage.getSource() instanceof Damage.EntitySource) {
Ref<EntityStore> attackerRef = ((Damage.EntitySource)damage.getSource()).getRef();
if (attackerRef.isValid()) {
if (!npcComponent.getCanCauseDamage(attackerRef, commandBuffer)) {
damage.setCancelled(true);
}
}
}
}
}
public static class DamageReceivedSystem extends DamageEventSystem {
@Nonnull
private final Query<EntityStore> query = NPCEntity.getComponentType();
public DamageReceivedSystem() {
}
@Nullable
public SystemGroup<EntityStore> getGroup() {
return DamageModule.get().getInspectDamageGroup();
}
@Nonnull
public Query<EntityStore> getQuery() {
return this.query;
}
public void handle(int index, @Nonnull ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull Store<EntityStore> store, @Nonnull CommandBuffer<EntityStore> commandBuffer, @Nonnull Damage damage) {
NPCEntity npcComponent = (NPCEntity)archetypeChunk.getComponent(index, NPCEntity.getComponentType());
assert npcComponent != null;
DamageData damageData = npcComponent.getDamageData();
damageData.onSufferedDamage(commandBuffer, damage);
}
}
public static class DamageDealtSystem extends DamageEventSystem {
public DamageDealtSystem() {
}
@Nullable
public SystemGroup<EntityStore> getGroup() {
return DamageModule.get().getInspectDamageGroup();
}
@Nonnull
public Query<EntityStore> getQuery() {
return Archetype.<EntityStore>empty();
}
public void handle(int index, @Nonnull ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull Store<EntityStore> store, @Nonnull CommandBuffer<EntityStore> commandBuffer, @Nonnull Damage damage) {
if (damage.getSource() instanceof Damage.EntitySource) {
Ref<EntityStore> attackerRef = ((Damage.EntitySource)damage.getSource()).getRef();
if (attackerRef.isValid()) {
NPCEntity npcComponent = (NPCEntity)commandBuffer.getComponent(attackerRef, NPCEntity.getComponentType());
if (npcComponent != null) {
npcComponent.getDamageData().onInflictedDamage(archetypeChunk.getReferenceTo(index), (double)damage.getAmount());
}
}
}
}
}
public static class DamageReceivedEventViewSystem extends DamageEventSystem {
@Nonnull
private final ComponentType<EntityStore, Player> playerComponentType = Player.getComponentType();
@Nonnull
private final ComponentType<EntityStore, TransformComponent> transformComponentType = TransformComponent.getComponentType();
@Nonnull
private final ResourceType<EntityStore, Blackboard> blackboardResourceType = Blackboard.getResourceType();
@Nonnull
private final Query<EntityStore> query;
public DamageReceivedEventViewSystem() {
this.query = Query.<EntityStore>and(Query.or(NPCEntity.getComponentType(), this.playerComponentType), this.transformComponentType);
}
@Nullable
public SystemGroup<EntityStore> getGroup() {
return DamageModule.get().getInspectDamageGroup();
}
@Nonnull
public Query<EntityStore> getQuery() {
return this.query;
}
public void handle(int index, @Nonnull ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull Store<EntityStore> store, @Nonnull CommandBuffer<EntityStore> commandBuffer, @Nonnull Damage damage) {
TransformComponent transformComponent = (TransformComponent)archetypeChunk.getComponent(index, this.transformComponentType);
assert transformComponent != null;
Blackboard blackboard = (Blackboard)commandBuffer.getResource(this.blackboardResourceType);
EntityEventView view = (EntityEventView)blackboard.getView(EntityEventView.class, ChunkUtil.chunkCoordinate(transformComponent.getPosition().x), ChunkUtil.chunkCoordinate(transformComponent.getPosition().z));
if (damage.getSource() instanceof Damage.EntitySource) {
Ref<EntityStore> attackerRef = ((Damage.EntitySource)damage.getSource()).getRef();
if (attackerRef.isValid()) {
Player attackerPlayerComponent = (Player)commandBuffer.getComponent(attackerRef, Player.getComponentType());
if (attackerPlayerComponent != null && attackerPlayerComponent.getGameMode() == GameMode.Creative) {
PlayerSettings playerSettingsComponent = (PlayerSettings)commandBuffer.getComponent(attackerRef, PlayerSettings.getComponentType());
if (playerSettingsComponent == null || !playerSettingsComponent.creativeSettings().allowNPCDetection()) {
return;
}
}
view.processAttackedEvent(archetypeChunk.getReferenceTo(index), attackerRef, commandBuffer, EntityEventType.DAMAGE);
}
}
}
}
public static class DropDeathItems extends DeathSystems.OnDeathSystem {
@Nonnull
private static final Query<EntityStore> QUERY = Query.<EntityStore>and(NPCEntity.getComponentType(), TransformComponent.getComponentType(), HeadRotation.getComponentType(), Query.not(Player.getComponentType()));
public DropDeathItems() {
}
@Nonnull
public Query<EntityStore> getQuery() {
return QUERY;
}
public void onComponentAdded(@Nonnull Ref<EntityStore> ref, @Nonnull DeathComponent component, @Nonnull Store<EntityStore> store, @Nonnull CommandBuffer<EntityStore> commandBuffer) {
if (component.getItemsLossMode() == DeathConfig.ItemsLossMode.ALL) {
NPCEntity npcComponent = (NPCEntity)commandBuffer.getComponent(ref, NPCEntity.getComponentType());
assert npcComponent != null;
Role role = npcComponent.getRole();
assert role != null;
List<ItemStack> itemsToDrop = new ObjectArrayList<ItemStack>();
if (role.isPickupDropOnDeath()) {
Inventory inventory = npcComponent.getInventory();
itemsToDrop.addAll(inventory.getStorage().dropAllItemStacks());
}
String dropListId = role.getDropListId();
if (dropListId != null) {
ItemModule itemModule = ItemModule.get();
if (itemModule.isEnabled()) {
List<ItemStack> randomItemsToDrop = itemModule.getRandomItemDrops(dropListId);
itemsToDrop.addAll(randomItemsToDrop);
}
}
if (!itemsToDrop.isEmpty()) {
TransformComponent transformComponent = (TransformComponent)store.getComponent(ref, TransformComponent.getComponentType());
assert transformComponent != null;
Vector3d position = transformComponent.getPosition();
HeadRotation headRotationComponent = (HeadRotation)store.getComponent(ref, HeadRotation.getComponentType());
assert headRotationComponent != null;
Vector3f headRotation = headRotationComponent.getRotation();
Vector3d dropPosition = position.clone().add(0.0, 1.0, 0.0);
Holder<EntityStore>[] drops = ItemComponent.generateItemDrops(store, itemsToDrop, dropPosition, headRotation.clone());
commandBuffer.addEntities(drops, AddReason.SPAWN);
}
}
}
}
}