<commit_before>package org.inventivetalent.npclib.npc;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.plugin.Plugin;
import org.inventivetalent.boundingbox.BoundingBox;
import org.inventivetalent.npclib.*;
import org.inventivetalent.npclib.ai.AIAbstract;
import org.inventivetalent.npclib.entity.NPCEntity;
import org.inventivetalent.npclib.event.NPCDamageEvent;
import org.inventivetalent.npclib.event.NPCDeathEvent;
import org.inventivetalent.npclib.event.NPCSpawnEvent;
import org.inventivetalent.npclib.watcher.AnnotatedMethodWatcher;
import org.inventivetalent.npclib.watcher.Watch;
import org.inventivetalent.reflection.minecraft.Minecraft;
import org.inventivetalent.reflection.resolver.FieldResolver;
import org.inventivetalent.reflection.resolver.MethodResolver;
import org.inventivetalent.reflection.resolver.ResolverQuery;
import org.inventivetalent.reflection.util.AccessUtil;
import org.inventivetalent.vectors.d3.Vector3DDouble;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public abstract class NPCAbstract<N extends NPCEntity, B extends Entity> {

	protected final FieldResolver  npcEntityFieldResolver;
	protected final MethodResolver npcEntityMethodResolver;
	protected final FieldResolver  entityFieldResolver  = new FieldResolver(Reflection.nmsClassResolver.resolveSilent("Entity"));
	protected final MethodResolver entityMethodResolver = new MethodResolver(Reflection.nmsClassResolver.resolveSilent("Entity"));
	private final N npcEntity;
	private final List<AIAbstract> aiList = new ArrayList<>();
	protected Plugin plugin;

	protected NPCAbstract(N npcEntity) {
		this.npcEntity = npcEntity;
		this.npcEntityFieldResolver = new FieldResolver(npcEntity.getClass());
		this.npcEntityMethodResolver = new MethodResolver(npcEntity.getClass());

		setNPCField("$npc", this);

		this.npcEntity.setMethodWatcher(new AnnotatedMethodWatcher(this));

		//		postInit();
	}

	public void postInit(Plugin plugin, Location location) throws Exception {
		this.plugin = plugin;
		//TODO: Pathfinder

		//		Reflection.nmsClassResolver.resolve("Entity")
		//				.getDeclaredMethod("setLocation", double.class, double.class, double.class, float.class, float.class)
		//				.invoke(getNpcEntity(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
		getNpcEntity().setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());

		spawn();
	}

	public void spawn() {
		NPCSpawnEvent event = new NPCSpawnEvent(this, CreatureSpawnEvent.SpawnReason.CUSTOM);
		Bukkit.getPluginManager().callEvent(event);
		getNpcEntity().spawn(event.getSpawnReason());
	}

	public <A extends NPCAbstract<N, B>> boolean registerAI(AIAbstract<A> aiAbstract) {
		return aiList.add(aiAbstract);
	}

	public void tickAI() {
		for (Iterator<AIAbstract> iterator = aiList.iterator(); iterator.hasNext(); ) {
			AIAbstract next = iterator.next();
			next.tick();
			if (next.isFinished()) {
				iterator.remove();
			}
		}
	}

	public BoundingBox getAbsoluteBoundingBox() {
		return BoundingBox.fromNMS(getEntityField("boundingBox"));
	}

	public BoundingBox getBoundingBox() {
		return getAbsoluteBoundingBox().translate(new Vector3DDouble(getBukkitEntity().getLocation()).multiply(-1));
	}

	// NPCInfo
	public NPCType getNpcType() {
		return NPCType.forEntityType(getNpcEntity().getNpcInfo().getType());
	}

	public EntityType getEntityType() {
		return getNpcEntity().getNpcInfo().getType();
	}

	// Watched

	@Watch("void m()")
	public boolean onBaseTick() {
		//		System.out.println("base tick!");

		tickAI();

		return true;
	}

	@Watch("void move(double,double,double)")
	public boolean onMove(ObjectContainer<Double> x, ObjectContainer<Double> y, ObjectContainer<Double> z) {
		//TODO: NPCMoveEvent/NPCMotionEvent
		return true;
	}

	@Watch("boolean damageEntity(DamageSource,float)")
	public Boolean onDamage(ObjectContainer<Object> damageSource, ObjectContainer<Float> amount, SuperSwitch superSwitch) {
		System.out.println("onDamage: damageSource = [" + damageSource + "], amount = [" + amount + "]");
		String sourceName = Reflection.getDamageSourceName(damageSource.value);
		EntityDamageEvent.DamageCause damageCause = Reflection.damageSourceToCause(sourceName);
		Entity damager = Reflection.getEntityFromDamageSource(damageSource.value);
		NPCDamageEvent event = new NPCDamageEvent(this, sourceName, damageCause, amount.value, damager);
		Bukkit.getPluginManager().callEvent(event);
		event.setCancelled(true);
		if (event.isCancelled()) {
			superSwitch.setCancelled(true);
			return false;
		}
		amount.value = event.getAmount();
		return !event.isCancelled();
	}

	@Watch("void die()")<commit_msg>remove debug<commit_after>package org.inventivetalent.npclib.npc;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.plugin.Plugin;
import org.inventivetalent.boundingbox.BoundingBox;
import org.inventivetalent.npclib.*;
import org.inventivetalent.npclib.ai.AIAbstract;
import org.inventivetalent.npclib.entity.NPCEntity;
import org.inventivetalent.npclib.event.NPCDamageEvent;
import org.inventivetalent.npclib.event.NPCDeathEvent;
import org.inventivetalent.npclib.event.NPCSpawnEvent;
import org.inventivetalent.npclib.watcher.AnnotatedMethodWatcher;
import org.inventivetalent.npclib.watcher.Watch;
import org.inventivetalent.reflection.minecraft.Minecraft;
import org.inventivetalent.reflection.resolver.FieldResolver;
import org.inventivetalent.reflection.resolver.MethodResolver;
import org.inventivetalent.reflection.resolver.ResolverQuery;
import org.inventivetalent.reflection.util.AccessUtil;
import org.inventivetalent.vectors.d3.Vector3DDouble;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public abstract class NPCAbstract<N extends NPCEntity, B extends Entity> {

	protected final FieldResolver  npcEntityFieldResolver;
	protected final MethodResolver npcEntityMethodResolver;
	protected final FieldResolver  entityFieldResolver  = new FieldResolver(Reflection.nmsClassResolver.resolveSilent("Entity"));
	protected final MethodResolver entityMethodResolver = new MethodResolver(Reflection.nmsClassResolver.resolveSilent("Entity"));
	private final N npcEntity;
	private final List<AIAbstract> aiList = new ArrayList<>();
	protected Plugin plugin;

	protected NPCAbstract(N npcEntity) {
		this.npcEntity = npcEntity;
		this.npcEntityFieldResolver = new FieldResolver(npcEntity.getClass());
		this.npcEntityMethodResolver = new MethodResolver(npcEntity.getClass());

		setNPCField("$npc", this);

		this.npcEntity.setMethodWatcher(new AnnotatedMethodWatcher(this));

		//		postInit();
	}

	public void postInit(Plugin plugin, Location location) throws Exception {
		this.plugin = plugin;
		//TODO: Pathfinder

		//		Reflection.nmsClassResolver.resolve("Entity")
		//				.getDeclaredMethod("setLocation", double.class, double.class, double.class, float.class, float.class)
		//				.invoke(getNpcEntity(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
		getNpcEntity().setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());

		spawn();
	}

	public void spawn() {
		NPCSpawnEvent event = new NPCSpawnEvent(this, CreatureSpawnEvent.SpawnReason.CUSTOM);
		Bukkit.getPluginManager().callEvent(event);
		getNpcEntity().spawn(event.getSpawnReason());
	}

	public <A extends NPCAbstract<N, B>> boolean registerAI(AIAbstract<A> aiAbstract) {
		return aiList.add(aiAbstract);
	}

	public void tickAI() {
		for (Iterator<AIAbstract> iterator = aiList.iterator(); iterator.hasNext(); ) {
			AIAbstract next = iterator.next();
			next.tick();
			if (next.isFinished()) {
				iterator.remove();
			}
		}
	}

	public BoundingBox getAbsoluteBoundingBox() {
		return BoundingBox.fromNMS(getEntityField("boundingBox"));
	}

	public BoundingBox getBoundingBox() {
		return getAbsoluteBoundingBox().translate(new Vector3DDouble(getBukkitEntity().getLocation()).multiply(-1));
	}

	// NPCInfo
	public NPCType getNpcType() {
		return NPCType.forEntityType(getNpcEntity().getNpcInfo().getType());
	}

	public EntityType getEntityType() {
		return getNpcEntity().getNpcInfo().getType();
	}

	// Watched

	@Watch("void m()")
	public boolean onBaseTick() {
		//		System.out.println("base tick!");

		tickAI();

		return true;
	}

	@Watch("void move(double,double,double)")
	public boolean onMove(ObjectContainer<Double> x, ObjectContainer<Double> y, ObjectContainer<Double> z) {
		//TODO: NPCMoveEvent/NPCMotionEvent
		return true;
	}

	@Watch("boolean damageEntity(DamageSource,float)")
	public Boolean onDamage(ObjectContainer<Object> damageSource, ObjectContainer<Float> amount, SuperSwitch superSwitch) {
		System.out.println("onDamage: damageSource = [" + damageSource + "], amount = [" + amount + "]");
		String sourceName = Reflection.getDamageSourceName(damageSource.value);
		EntityDamageEvent.DamageCause damageCause = Reflection.damageSourceToCause(sourceName);
		Entity damager = Reflection.getEntityFromDamageSource(damageSource.value);
		NPCDamageEvent event = new NPCDamageEvent(this, sourceName, damageCause, amount.value, damager);
		Bukkit.getPluginManager().callEvent(event);
		if (event.isCancelled()) {
			superSwitch.setCancelled(true);
			return false;
		}
		amount.value = event.getAmount();
		return !event.isCancelled();
	}

	@Watch("void die()")
{'fraction_non_alphanumeric': 0.12115677321156773, 'fraction_numerical': 0.0008117706747843734, 'mean_word_length': 6.142028985507246, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '15482', 'n_tokens_mistral': 3376, 'n_tokens_neox': 3172, 'n_words': 539}