From 02c0bfcbf615300854d109206c7fdb5200abb44b Mon Sep 17 00:00:00 2001 From: Sen Date: Sat, 10 May 2025 00:02:02 +0200 Subject: [PATCH] split entity ai to server #1 --- common/src/common/ai/IEntityNode.java | 17 + common/src/common/entity/Entity.java | 8 - .../src/common/entity/animal/EntityHorse.java | 8 - .../common/entity/npc/EntityArachnoid.java | 5 - .../src/common/entity/npc/EntityHaunter.java | 5 - common/src/common/entity/npc/EntityNPC.java | 211 +-------- .../src/common/entity/types/EntityLiving.java | 424 +---------------- .../pathfinding/PathNavigateGround.java | 2 +- server/src/server/ai/EntityNPCNode.java | 224 +++++++++ server/src/server/ai/EntityNode.java | 436 ++++++++++++++++++ 10 files changed, 706 insertions(+), 634 deletions(-) create mode 100644 common/src/common/ai/IEntityNode.java create mode 100644 server/src/server/ai/EntityNPCNode.java create mode 100644 server/src/server/ai/EntityNode.java diff --git a/common/src/common/ai/IEntityNode.java b/common/src/common/ai/IEntityNode.java new file mode 100644 index 0000000..d4d89ee --- /dev/null +++ b/common/src/common/ai/IEntityNode.java @@ -0,0 +1,17 @@ +package common.ai; + +import common.entity.DamageSource; +import common.entity.types.EntityLiving; +import common.nbt.NBTTagCompound; + +public interface IEntityNode { + void update(); + void updateRenderAngles(); + void updateLeashedState(); + void setLeashTag(NBTTagCompound tag); + EntityLiving getAttacking(); + EntityLiving getAttackTarget(); + void resetCombat(); + void trackDamage(DamageSource source, int amount); + void sendDeathMessage(); +} diff --git a/common/src/common/entity/Entity.java b/common/src/common/entity/Entity.java index b142d3d..61d7871 100755 --- a/common/src/common/entity/Entity.java +++ b/common/src/common/entity/Entity.java @@ -2428,14 +2428,6 @@ public abstract class Entity return true; } - /** - * The maximum height from where the entity is alowed to jump (used in pathfinder) - */ - public int getMaxFallHeight() - { - return 3; - } - // public Vec3 getLastPortal() // { // return this.portalVec != null ? this.portalVec : new Vec3(0.0d, 0.0d, 0.0d); diff --git a/common/src/common/entity/animal/EntityHorse.java b/common/src/common/entity/animal/EntityHorse.java index ed9d625..66cb983 100755 --- a/common/src/common/entity/animal/EntityHorse.java +++ b/common/src/common/entity/animal/EntityHorse.java @@ -258,14 +258,6 @@ public class EntityHorse extends EntityAnimal implements IInvBasic return !this.isUndead() && super.allowLeashing(); } - protected void onUpdateLeashed(float distance) - { - if (distance > 6.0F && this.isEatingHaystack()) - { - this.setEatingHaystack(false); - } - } - public boolean isChested() { return this.getHorseWatchableBoolean(8); diff --git a/common/src/common/entity/npc/EntityArachnoid.java b/common/src/common/entity/npc/EntityArachnoid.java index becd804..0fcd081 100755 --- a/common/src/common/entity/npc/EntityArachnoid.java +++ b/common/src/common/entity/npc/EntityArachnoid.java @@ -35,11 +35,6 @@ public class EntityArachnoid extends EntityNPC // return 0.9375f * this.height / 1.6f; // } - protected PathNavigate getNewNavigator(World worldIn) - { - return new PathNavigateClimber(this, worldIn); - } - protected void entityInit() { super.entityInit(); diff --git a/common/src/common/entity/npc/EntityHaunter.java b/common/src/common/entity/npc/EntityHaunter.java index 4f1e389..ca79e08 100755 --- a/common/src/common/entity/npc/EntityHaunter.java +++ b/common/src/common/entity/npc/EntityHaunter.java @@ -30,11 +30,6 @@ public class EntityHaunter extends EntityNPC { super.applyEntityAttributes(); this.getEntityAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(0.25D); } - - public int getMaxFallHeight() - { - return this.getAttackTarget() == null ? 3 : 3 + (this.getHealth() - 1); - } public void fall(float distance, float damageMultiplier) { diff --git a/common/src/common/entity/npc/EntityNPC.java b/common/src/common/entity/npc/EntityNPC.java index f261a8b..ffd5e7b 100755 --- a/common/src/common/entity/npc/EntityNPC.java +++ b/common/src/common/entity/npc/EntityNPC.java @@ -133,47 +133,11 @@ public abstract class EntityNPC extends EntityLiving // public static String getSpeciesName(String character) { // return (character.substring(0, 1).toUpperCase() + character.substring(1)).replace('_', ' ').replaceAll("( [a-z])", "$1"); // } - - protected final EntityAIAttackOnCollide aiMelee = new EntityAIAttackOnCollide(this, EntityLiving.class, 1.0D, true, true) { - public boolean shouldExecute() - { - return !EntityNPC.this.fleeing && super.shouldExecute(); - } - - public boolean continueExecuting() - { - return !EntityNPC.this.fleeing && super.shouldExecute(); - } - }; - protected final AIRangedAttack aiRanged = new AIRangedAttack(this, 1.0D, this.getAttackSpeed(), this.getAttackSpeed() * 3, 15.0F) { -// public void startExecuting() -// { -// super.startExecuting(); -// EntityNPC.this.setUsingItem(true); -// } -// -// public void resetTask() -// { -// super.resetTask(); -// EntityNPC.this.setUsingItem(false); -// } - - public boolean shouldExecute() - { - return !EntityNPC.this.fleeing && super.shouldExecute(); - } - - public boolean continueExecuting() - { - return !EntityNPC.this.fleeing && super.shouldExecute(); - } - }; protected final SpeciesInfo species; private EntityNPC talkingPlayer; private boolean isWilling; - private boolean fleeing; private boolean playing; protected boolean noPickup; private ItemStack[] equipment = new ItemStack[5]; @@ -255,120 +219,6 @@ public abstract class EntityNPC extends EntityLiving // this.setCharacter(""); if(this.species != null) this.setSize(this.getSpeciesBaseSize() * this.species.renderer.width / this.species.renderer.height, this.getSpeciesBaseSize()); // /* 0.6F, */ 1.8F); - if(this.getNavigator() instanceof PathNavigateGround) { - ((PathNavigateGround)this.getNavigator()).setBreakDoors(true); - ((PathNavigateGround)this.getNavigator()).setAvoidsWater(true); - } - this.tasks.addTask(0, new EntityAISwimming(this)); -// this.tasks.addTask(1, new EntityAIAttackOnCollide(this, EntityNPC.class, 0.6D, true, true)); -// this.tasks.addTask(1, new EntityAIAttackOnCollide(this, EntityLivingBase.class, 0.6D, true, true)); - this.tasks.addTask(1, new EntityAINpcMate(this)); - this.tasks.addTask(2, new EntityAIAvoidEntity(this, EntityLiving.class, new Predicate() { - public boolean test(EntityLiving entity) { - return entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity); - } - }, 8.0F, 1.1D, 1.1D) { - { - this.setMutexBits(0); - } - - public void startExecuting() { - EntityNPC.this.setAttackTarget(null); - EntityNPC.this.fleeing = true; - } - - public boolean continueExecuting() { - return false; - } - - public void updateTask() - { - } - -// public void resetTask() { -// super.resetTask(); -// EntityNPC.this.isFleeing = false; -// } - }); - this.tasks.addTask(3, new EntityAIAvoidEntity(this, EntityLiving.class, new Predicate() { - public boolean test(EntityLiving entity) { - return entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity); - } - }, 8.0F, 1.1D, 1.1D) { - public void startExecuting() { - super.startExecuting(); - EntityNPC.this.setAttackTarget(null); - EntityNPC.this.fleeing = true; - } - - public void resetTask() { - super.resetTask(); - EntityNPC.this.fleeing = false; - } - }); -// this.tasks.addTask(2, new EntityAITempt(this, 1.0D, Items.golden_apple, false)); - this.tasks.addTask(4, new EntityAIOpenDoor(this, true)); - this.tasks.addTask(5, new EntityAINagPlayer(this)); - this.tasks.addTask(5, new EntityAILookAtTalkingPlayer(this)); - this.tasks.addTask(6, new EntityAIWatchClosest2(this, null, 3.0F, 1.0F) { - private int sneakTime; - - public void updateTask() - { - super.updateTask(); - boolean flag = this.closestEntity.isPlayer() && this.closestEntity.isSneaking(); - if(this.sneakTime > 0) { - if(--this.sneakTime == 0) { - EntityNPC.this.setSneaking(false); - } - } - else if(EntityNPC.this.getAttackTarget() == null && EntityNPC.this.rand.chance(flag ? 5 : 200)) { - EntityNPC.this.setSneaking(true); - this.sneakTime = EntityNPC.this.rand.range(60, flag ? 160 : 120); - } - else if(EntityNPC.this.getAttackTarget() != null) { - EntityNPC.this.setSneaking(false); - this.sneakTime = 0; - } - } - - public void resetTask() - { - super.resetTask(); - EntityNPC.this.setSneaking(false); - } - }); - this.tasks.addTask(7, new EntityAINpcInteract(this)); - this.tasks.addTask(8, new EntityAIWander(this, 1.0D)); - this.tasks.addTask(8, new EntityAIPlay(this, 1.1D)); - this.tasks.addTask(9, new EntityAIWatchClosest(this, EntityLiving.class, 8.0F)); - this.targets.addTask(1, new EntityAIHurtByTarget(this, false, /* EntityNPC.class, */ EntityLiving.class) { - protected boolean isSuitableTarget(EntityLiving entity) { - if(entity != null && entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity)) { - EntityNPC.this.setAttackTarget(null); - EntityNPC.this.fleeing = true; - return false; - } - return entity != null && entity != EntityNPC.this && (!(entity.isPlayer()) || EntityNPC.this.rand.chance(entity.getAttackedBy() == EntityNPC.this ? 2 : 4)) - && EntityNPC.this.canCounter(entity) && super.isSuitableTarget(entity); - } - }); - this.targets.addTask(2, new EntityAINearestAttackableTarget(this, EntityLiving.class, 10, true, false, new Predicate() { - public boolean test(EntityLiving entity) { - if(entity != null && entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity)) { - EntityNPC.this.setAttackTarget(null); - EntityNPC.this.fleeing = true; - return false; - } - return entity != null && entity != EntityNPC.this && !EntityNPC.this.fleeing && EntityNPC.this.canAmbush(entity) && EntityNPC.this.canAttack(entity); - } - })); -// this.setCanPickUpLoot(true); - - if (worldIn != null && !worldIn.client) - { - this.setCombatTask(); - } } @@ -657,7 +507,7 @@ public abstract class EntityNPC extends EntityLiving } else if (!flag && !this.isPlayer() && this.isEntityAlive() && !this.isTalking()) { - if (!this.worldObj.client && this.canTrade() && this.getAttackTarget() == null) + if (!this.worldObj.client && this.canTrade() && this.node.getAttackTarget() == null) { this.setTalking(player); player.connection.displayTradeGui(this); @@ -1168,10 +1018,6 @@ public abstract class EntityNPC extends EntityLiving return this.playing; } - public boolean isFleeing() { - return this.fleeing; - } - // public boolean canPlay() { // return ; // } @@ -2032,7 +1878,8 @@ public abstract class EntityNPC extends EntityLiving { // float f1 = this.getHealth(); this.setHealth(this.getHealth() - damageAmount); - this.trackDamage(damageSrc, damageAmount); + if(this.node != null) + this.node.trackDamage(damageSrc, damageAmount); // if ((float)damageAmount < 3.4028235E37F) // { @@ -2835,7 +2682,7 @@ public abstract class EntityNPC extends EntityLiving else { this.setItemNoUpdate(slot, stack); if(!this.worldObj.client && slot == 0) - this.setCombatTask(); + this.node.setCombatTask(); } } @@ -3443,7 +3290,7 @@ public abstract class EntityNPC extends EntityLiving this.skin = tagCompund.getByteArray("Skin"); // this.setCanPickUpLoot(true); - this.setCombatTask(); + this.node.setCombatTask(); if(this.isPlayer()) { // this.entityUniqueID = getOfflineUUID(this.user); @@ -4461,16 +4308,6 @@ public abstract class EntityNPC extends EntityLiving { return !this.isPlayer() && super.interactFirst(playerIn); } - - public int getMaxFallHeight() - { - return this.isPlayer() ? 3 : super.getMaxFallHeight(); - } - - protected void updateLeashedState() { - if(!this.isPlayer()) - super.updateLeashedState(); - } public void setLeashedTo(Entity entity, boolean pkt) { if(!this.isPlayer()) @@ -4486,14 +4323,15 @@ public abstract class EntityNPC extends EntityLiving super.clearLeashed(pkt, dropLead); } - protected float updateDistance(float p_110146_1_, float p_110146_2_) + protected void updateDistance(float p_110146_1_, float p_110146_2_) { - if(!this.isPlayer()) - return super.updateDistance(p_110146_1_, p_110146_2_); + if(!this.isPlayer()) { + super.updateDistance(p_110146_1_, p_110146_2_); + return; + } float f = ExtMath.wrapf(p_110146_1_ - this.yawOffset); this.yawOffset += f * 0.3F; float f1 = ExtMath.wrapf(this.rotYaw - this.yawOffset); - boolean flag = f1 < -90.0F || f1 >= 90.0F; if (f1 < -75.0F) { @@ -4511,13 +4349,6 @@ public abstract class EntityNPC extends EntityLiving { this.yawOffset += f1 * 0.2F; } - - if (flag) - { - p_110146_2_ *= -1.0F; - } - - return p_110146_2_; } public boolean getCanSpawnHere() { @@ -4586,24 +4417,6 @@ public abstract class EntityNPC extends EntityLiving if(!this.isPlayer()) this.equipment[slot] = stack; } - - public void setCombatTask() - { - if(!this.isPlayer()) { - this.tasks.removeTask(this.aiMelee); - this.tasks.removeTask(this.aiRanged); - ItemStack itemstack = this.getHeldItem(); - - if (this.isRangedWeapon(itemstack)) - { - this.tasks.addTask(3, this.aiRanged); - } - else - { - this.tasks.addTask(3, this.aiMelee); - } - } - } public abstract int getBaseHealth(Random rand); // { // return 20; @@ -4649,10 +4462,6 @@ public abstract class EntityNPC extends EntityLiving public int getColor() { return this.isPlayer() ? 0xff00ff : 0x5000ad; } - - public void sendDeathMessage() { - this.sendDeathMessage(this.isPlayer(), true); - } protected boolean canRegenerateHealth() { return this.isPlayer(); diff --git a/common/src/common/entity/types/EntityLiving.java b/common/src/common/entity/types/EntityLiving.java index c99cbb5..96d6709 100755 --- a/common/src/common/entity/types/EntityLiving.java +++ b/common/src/common/entity/types/EntityLiving.java @@ -6,22 +6,14 @@ import java.util.List; import java.util.Map; import java.util.function.Predicate; -import common.ai.EntityAIBase; -import common.ai.EntityAIMoveTowardsRestriction; -import common.ai.EntityAITasks; -import common.ai.EntityJumpHelper; -import common.ai.EntityLookHelper; -import common.ai.EntityMoveHelper; -import common.ai.EntitySenses; +import common.ai.IEntityNode; import common.block.Block; import common.block.SoundType; -import common.collect.Lists; import common.collect.Maps; import common.color.TextColor; import common.enchantment.EnchantmentHelper; import common.entity.DamageSource; import common.entity.Entity; -import common.entity.EntityDamageSource; import common.entity.animal.EntityWolf; import common.entity.attributes.Attribute; import common.entity.attributes.AttributeInstance; @@ -50,12 +42,9 @@ import common.material.Material; import common.model.ParticleType; import common.nbt.NBTTagCompound; import common.nbt.NBTTagList; -import common.network.IPlayer; import common.packet.S1BPacketEntityAttach; import common.packet.SPacketAnimation; import common.packet.SPacketCollectItem; -import common.pathfinding.PathNavigate; -import common.pathfinding.PathNavigateGround; import common.potion.Potion; import common.potion.PotionEffect; import common.potion.PotionHelper; @@ -72,23 +61,13 @@ public abstract class EntityLiving extends Entity { private static final ItemStack[] EMPTY_INV = new ItemStack[5]; + protected IEntityNode node; private AttributeMap attributes; - private final List combat = Lists.newArrayList(); private final Map effects = Maps.newEnumMap(Potion.class); public int soundTimer; protected int xpValue; - private EntityLookHelper lookHelper; - protected EntityMoveHelper moveHelper; - protected EntityJumpHelper jumpHelper; - private EntityBodyHelper bodyHelper; - protected PathNavigate navigator; - protected final EntityAITasks tasks; - protected final EntityAITasks targets; - private EntityLiving target; - private EntitySenses senses; private boolean leashed; private Entity leashedTo; - private NBTTagCompound leashTag; public float prevCamPitch; public float camPitch; @@ -100,8 +79,6 @@ public abstract class EntityLiving extends Entity protected float landMovement; protected float prevGroundFactor; protected float groundFactor; - protected float movedDist; - protected float prevMovedDist; protected boolean jumping; public float moveStrafe; public float moveForward; @@ -135,18 +112,13 @@ public abstract class EntityLiving extends Entity private int lastAttacked; private EntityLiving attacker; private int lastAttackTime; - private int lastDamaged; // protected int entityAge; private int absorptionAmount; private boolean effectsDirty = true; protected boolean firstEffectUpdate = true; - private boolean attacked; - private boolean damaged; private String description; - - private String blockType; private float radiation; @@ -156,8 +128,6 @@ public abstract class EntityLiving extends Entity protected int growingAge; private float ageWidth = -1.0F; private float ageHeight; - private EntityAIBase aiBase = new EntityAIMoveTowardsRestriction(this, 1.0D); - private boolean isMovementAITaskSet; public EntityLiving(World worldIn) { @@ -171,15 +141,6 @@ public abstract class EntityLiving extends Entity this.rotYaw = (float)(Math.random() * Math.PI * 2.0D); this.headYaw = this.rotYaw; this.stepHeight = 0.6F; - - this.tasks = new EntityAITasks(); - this.targets = new EntityAITasks(); - this.lookHelper = new EntityLookHelper(this); - this.moveHelper = new EntityMoveHelper(this); - this.jumpHelper = new EntityJumpHelper(this); - this.bodyHelper = new EntityBodyHelper(this); - this.navigator = this.getNewNavigator(worldIn); - this.senses = new EntitySenses(this); } protected void entityInit() @@ -394,7 +355,6 @@ public abstract class EntityLiving extends Entity this.radiation = 0.0f; } this.updateEffects(); - this.prevMovedDist = this.movedDist; this.prevYawOffset = this.yawOffset; this.prevHeadYaw = this.headYaw; this.prevYaw = this.rotYaw; @@ -666,7 +626,7 @@ public abstract class EntityLiving extends Entity this.leashed = tagCompund.getBoolean("Leashed"); if(this.leashed && tagCompund.hasKey("Leash", 10)) { - this.leashTag = tagCompund.getCompoundTag("Leash"); + this.node.setLeashTag(tagCompund.getCompoundTag("Leash")); } } @@ -1109,11 +1069,12 @@ public abstract class EntityLiving extends Entity entity.onKillEntity(this); } - if(!this.worldObj.client) - this.sendDeathMessage(); + if(!this.worldObj.client) { + this.node.sendDeathMessage(); // this.noPickup = true; - this.resetCombat(); + this.node.resetCombat(); + } if (!this.worldObj.client) { @@ -1368,7 +1329,8 @@ public abstract class EntityLiving extends Entity { // float f1 = this.getHealth(); this.setHealth(this.getHealth() - damageAmount); - this.trackDamage(damageSrc, damageAmount); + if(this.node != null) + this.node.trackDamage(damageSrc, damageAmount); this.setAbsorptionAmount(this.getAbsorptionAmount() - damageAmount); } // } @@ -1376,7 +1338,7 @@ public abstract class EntityLiving extends Entity public EntityLiving getAttackingEntity() { - return (EntityLiving)(this.getAttacking() != null ? this.getAttacking() : (this.playerAttacker != null ? this.playerAttacker : (this.attackedBy != null ? this.attackedBy : null))); + return (EntityLiving)(this.node.getAttacking() != null ? this.node.getAttacking() : (this.playerAttacker != null ? this.playerAttacker : (this.attackedBy != null ? this.attackedBy : null))); } public final int getMaxHealth() @@ -1916,7 +1878,7 @@ public abstract class EntityLiving extends Entity if (this.ticksExisted % 20 == 0) { - this.resetCombat(); + this.node.resetCombat(); } } @@ -1948,7 +1910,7 @@ public abstract class EntityLiving extends Entity this.groundFactor += (f3 - this.groundFactor) * 0.3F; // this.worldObj.profiler.start("headTurn"); - f2 = this.updateDistance(f1, f2); + this.updateDistance(f1, f2); // this.worldObj.profiler.end(); // this.worldObj.profiler.start("rangeChecks"); @@ -1993,10 +1955,9 @@ public abstract class EntityLiving extends Entity } // this.worldObj.profiler.end(); - this.movedDist += f2; if(!this.worldObj.client) { - this.updateLeashedState(); + this.node.updateLeashedState(); } } @@ -2430,159 +2391,6 @@ public abstract class EntityLiving extends Entity public void clearRadiation() { this.radiation = 0.0f; } - - public void trackDamage(DamageSource source, int amount) { - this.resetCombat(); - this.blockType = null; - if(this.isOnLadder()) { - Block block = this.worldObj - .getState(new BlockPos(this.posX, this.getEntityBoundingBox().minY, this.posZ)).getBlock(); - if(block == Blocks.ladder) - this.blockType = "von einer Leiter"; - else if(block == Blocks.vine) - this.blockType = "von Ranken"; - } - else if(this.isInLiquid()) { - this.blockType = "aus dem Wasser"; - } - CombatEntry entry = new CombatEntry(source, amount, this.blockType, this.fallDistance); - this.combat.add(entry); - this.lastDamaged = this.ticksExisted; - this.damaged = true; - if(entry.getSource().getEntity() instanceof EntityLiving && !this.attacked && this.isEntityAlive()) - this.attacked = true; - } - - protected void sendDeathMessage() { - this.sendDeathMessage(false, false); - } - - protected void sendDeathMessage(boolean natural, boolean forAll) { - if(this.worldObj.client) - return; - String msg; - String kill; - IPlayer receiver = null; - if(this.combat.size() == 0) { - msg = kill = natural ? String.format("%s starb", this.getColoredName(TextColor.LGRAY)) : null; - } - else { - CombatEntry strong = null; - CombatEntry block = null; - int min = 0; - float max = 0.0F; - - for(int z = 0; z < this.combat.size(); ++z) { - CombatEntry entry = (CombatEntry)this.combat.get(z); - CombatEntry last = z > 0 ? (CombatEntry)this.combat.get(z - 1) : null; - - if((entry.getSource() == DamageSource.fall || entry.getSource() == DamageSource.outOfWorld) && - entry.getFallDistance() > 0.0F && (strong == null || entry.getFallDistance() > max)) { - if(z > 0) { - strong = last; - } - else { - strong = entry; - } - - max = entry.getFallDistance(); - } - - if(entry.getBlockType() != null && (block == null || entry.getDamage() > min)) { - block = entry; - } - } - CombatEntry fall = max > 5.0F && strong != null ? strong : (min > 5 && block != null ? block : null); - CombatEntry last = (CombatEntry)this.combat.get(this.combat.size() - 1); - Entity lastEnt = last.getSource().getEntity(); - - if(fall != null && last.getSource() == DamageSource.fall) { - if(fall.getSource() != DamageSource.fall && fall.getSource() != DamageSource.outOfWorld) { - Entity fallEnt = fall.getSource().getEntity(); - if(fallEnt != null && (lastEnt == null || fallEnt != lastEnt)) { - ItemStack fallItem = fallEnt instanceof EntityLiving ? ((EntityLiving)fallEnt).getHeldItem() : null; - receiver = fallEnt.isPlayer() ? ((EntityNPC)fallEnt).connection : null; - if(fallItem != null) { // && fallItem.hasDisplayName()) { - msg = String.format("%s wurde von %s mit %s zum Fallen verdammt", this.getColoredName(TextColor.CYAN), - fallEnt.getColoredName(TextColor.CYAN), fallItem.getColoredName(TextColor.CYAN)); - kill = String.format(TextColor.CYAN + "* %s mit %s zum Fallen verdammt", - this.getColoredName(TextColor.CYAN), fallItem.getColoredName(TextColor.CYAN)); - } - else { - msg = String.format("%s wurde von %s zum Fallen verdammt", this.getColoredName(TextColor.CYAN), - fallEnt.getColoredName(TextColor.CYAN)); - kill = String.format(TextColor.CYAN + "* %s zum Fallen verdammt", - this.getColoredName(TextColor.CYAN)); - } - } - else if(lastEnt != null) { - ItemStack lastItem = lastEnt instanceof EntityLiving ? ((EntityLiving)lastEnt).getHeldItem() : null; - receiver = lastEnt.isPlayer() ? ((EntityNPC)lastEnt).connection : null; - if(lastItem != null) { // && lastItem.hasDisplayName()) { - msg = String.format("%s fiel zu tief und wurde von %s mit %s erledigt", - this.getColoredName(TextColor.BLUE), - lastEnt.getColoredName(TextColor.BLUE), lastItem.getColoredName(TextColor.BLUE)); - kill = String.format(TextColor.BLUE + "* %s mit %s erledigt", - this.getColoredName(TextColor.BLUE), lastItem.getColoredName(TextColor.BLUE)); - } - else { - msg = String.format("%s fiel zu tief und wurde von %s erledigt", this.getColoredName(TextColor.BLUE), - lastEnt.getColoredName(TextColor.BLUE)); - kill = String.format(TextColor.BLUE + "%s erledigt", this.getColoredName(TextColor.BLUE)); - } - } - else { - msg = kill = natural ? String.format("%s wurde zum Fallen verdammt", this.getColoredName(TextColor.CYAN)) : null; - } - } - else { - msg = kill = natural ? String.format("%s fiel " + (fall.getBlockType() == null ? "aus zu großer Höhe" : fall.getBlockType()), - this.getColoredName(TextColor.NEON)) : null; - } - } - else { - receiver = last.getSource().getEntity() != null && last.getSource().getEntity().isPlayer() ? ((EntityNPC)last.getSource().getEntity()).connection : null; - msg = natural || (last.getSource() instanceof EntityDamageSource ? last.getSource().getEntity() != null : this.getAttackingEntity() != null) ? last.getSource().getDeathMessage(this) : null; - kill = msg == null ? null : last.getSource().getKillMessage(this); - } - } - if(msg == null) - return; - if(receiver != null) - receiver.addFeed(kill); - if(forAll) - for(IPlayer player : ((WorldServer)this.worldObj).getServer().getIPlayers()) { - if(player != receiver) - player.addFeed(msg); - } - } - - public EntityLiving getAttacking() { - EntityLiving entity = null; - EntityNPC player = null; - int edmg = 0; - int pdmg = 0; - for(CombatEntry entry : this.combat) { - if(entry.getSource().getEntity() != null && entry.getSource().getEntity().isPlayer() && (player == null || entry.getDamage() > pdmg)) { - pdmg = entry.getDamage(); - player = (EntityNPC)entry.getSource().getEntity(); - } - if(entry.getSource().getEntity() instanceof EntityLiving && (entity == null || entry.getDamage() > edmg)) { - edmg = entry.getDamage(); - entity = (EntityLiving)entry.getSource().getEntity(); - } - } - return player != null && pdmg >= edmg / 3 ? player : entity; - } - - public void resetCombat() { - int timeout = this.attacked ? 300 : 100; - if(this.damaged && (!this.isEntityAlive() || this.ticksExisted - this.lastDamaged > timeout)) { - this.damaged = false; - this.attacked = false; - this.combat.clear(); - } - } public boolean isSneakingVisually() { return this.isSneaking(); @@ -2804,22 +2612,6 @@ public abstract class EntityLiving extends Entity return 4; } - public int getMaxFallHeight() { - if(this.getAttackTarget() == null) { - return 3; - } - else { - int i = (int)((float)this.getHealth() - (float)this.getMaxHealth() * 0.33F); -// i = i - (3 - this.worldObj.getDifficulty().getId()) * 4; - - if(i < 0) { - i = 0; - } - - return i + 3; - } - } - // public boolean getCanSpawnHere() { // return true; // } @@ -2882,34 +2674,8 @@ public abstract class EntityLiving extends Entity } protected void updateEntityActionState() { -// ++this.entityAge; -// this.worldObj.profiler.start("checkDespawn"); -// this.despawnEntity(); -// this.worldObj.profiler.end(); -// this.worldObj.profiler.start("sensing"); - this.senses.clearSensingCache(); -// this.worldObj.profiler.end(); -// this.worldObj.profiler.start("targetSelector"); - this.targets.onUpdateTasks(); -// this.worldObj.profiler.end(); -// this.worldObj.profiler.start("goalSelector"); - this.tasks.onUpdateTasks(); -// this.worldObj.profiler.end(); -// this.worldObj.profiler.start("navigation"); - this.navigator.onUpdateNavigation(); -// this.worldObj.profiler.end(); -// this.worldObj.profiler.start("mob tick"); - this.updateAITasks(); -// this.worldObj.profiler.end(); -// this.worldObj.profiler.start("controls"); -// this.worldObj.profiler.start("move"); - this.moveHelper.onUpdateMoveHelper(); -// this.worldObj.profiler.next("look"); - this.lookHelper.onUpdateLook(); -// this.worldObj.profiler.next("jump"); - this.jumpHelper.doJump(); -// this.worldObj.profiler.end(); -// this.worldObj.profiler.end(); + if(this.node != null) + this.node.update(); } // protected void despawnEntity() { @@ -2967,123 +2733,12 @@ public abstract class EntityLiving extends Entity // super.applyEntityAttributes(); // this.getAttributeMap().registerAttribute(Attributes.FOLLOW_RANGE).setBaseValue(16.0D); // } - - protected PathNavigate getNewNavigator(World worldIn) { - return new PathNavigateGround(this, worldIn); - } - - public EntityLookHelper getLookHelper() { - return this.lookHelper; - } - - public EntityMoveHelper getMoveHelper() { - return this.moveHelper; - } - - public EntityJumpHelper getJumpHelper() { - return this.jumpHelper; - } - - public PathNavigate getNavigator() { - return this.navigator; - } - - public EntitySenses getEntitySenses() { - return this.senses; - } - - public EntityLiving getAttackTarget() { - return this.target; - } - - public void setAttackTarget(EntityLiving entitylivingbaseIn) { - this.target = entitylivingbaseIn; - } // public boolean canAttackClass(Class cls) { // return /* cls != EntityFireDemon.class && */ // ; // } - protected void updateLeashedState() { - if(this.leashTag != null) { - this.recreateLeash(); - } - - if(this.leashed) { - if(!this.isEntityAlive()) { - this.clearLeashed(true, true); - } - - if(this.leashedTo == null || this.leashedTo.dead) { - this.clearLeashed(true, true); - } - } - - if (this.getLeashed() && this.getLeashedTo() != null && this.getLeashedTo().worldObj == this.worldObj) - { - Entity entity = this.getLeashedTo(); - this.setHomePosAndDistance(new BlockPos((int)entity.posX, (int)entity.posY, (int)entity.posZ), 5); - float f = this.getDistanceToEntity(entity); - - if (this instanceof EntityTameable && ((EntityTameable)this).isSitting()) - { - if (f > 10.0F) - { - this.clearLeashed(true, true); - } - - return; - } - - if (!this.isMovementAITaskSet) - { - this.tasks.addTask(2, this.aiBase); - - if (this.getNavigator() instanceof PathNavigateGround) - { - ((PathNavigateGround)this.getNavigator()).setAvoidsWater(false); - } - - this.isMovementAITaskSet = true; - } - - this.onUpdateLeashed(f); - - if (f > 4.0F) - { - this.getNavigator().tryMoveToEntityLiving(entity, 1.0D); - } - - if (f > 6.0F) - { - double d0 = (entity.posX - this.posX) / (double)f; - double d1 = (entity.posY - this.posY) / (double)f; - double d2 = (entity.posZ - this.posZ) / (double)f; - this.motionX += d0 * Math.abs(d0) * 0.4D; - this.motionY += d1 * Math.abs(d1) * 0.4D; - this.motionZ += d2 * Math.abs(d2) * 0.4D; - } - - if (f > 10.0F) - { - this.clearLeashed(true, true); - } - } - else if (!this.getLeashed() && this.isMovementAITaskSet) - { - this.isMovementAITaskSet = false; - this.tasks.removeTask(this.aiBase); - - if (this.getNavigator() instanceof PathNavigateGround) - { - ((PathNavigateGround)this.getNavigator()).setAvoidsWater(true); - } - - this.detachHome(); - } - } - public void clearLeashed(boolean pkt, boolean dropLead) { if(this.leashed) { this.leashed = false; @@ -3120,43 +2775,9 @@ public abstract class EntityLiving extends Entity } } - private void recreateLeash() { - if(this.leashed && this.leashTag != null) { -// if(this.leashTag.hasKey("PlayerName", 8)) { -// String id = this.leashTag.getString("PlayerName"); -// if(!id.isEmpty()) { -// for(EntityNPC entitylivingbase : this.worldObj.getEntitiesWithinAABB(EntityNPC.class, -// this.getEntityBoundingBox().expand(10.0D, 10.0D, 10.0D))) { -// if(entitylivingbase.getUser().equals(id)) { -// this.leashedTo = entitylivingbase; -// break; -// } -// } -// } -// } -// else - if(this.leashTag.hasKey("X", 99) && this.leashTag.hasKey("Y", 99) && this.leashTag.hasKey("Z", 99)) { - BlockPos blockpos = new BlockPos(this.leashTag.getInteger("X"), this.leashTag.getInteger("Y"), - this.leashTag.getInteger("Z")); - EntityLeashKnot entityleashknot = EntityLeashKnot.getKnotForPosition(this.worldObj, blockpos); - - if(entityleashknot == null) { - entityleashknot = EntityLeashKnot.createKnot(this.worldObj, blockpos); - } - - this.leashedTo = entityleashknot; - } - else { - this.clearLeashed(false, true); - } - } - - this.leashTag = null; - } - - protected float updateDistance(float p_110146_1_, float p_110146_2_) { - this.bodyHelper.updateRenderAngles(); - return p_110146_2_; + protected void updateDistance(float p_110146_1_, float p_110146_2_) { + if(this.node != null) + this.node.updateRenderAngles(); } public ItemStack[] getInventory() { @@ -3287,11 +2908,6 @@ public abstract class EntityLiving extends Entity { return this.getBlockPathWeight(new BlockPos(this.posX, this.getEntityBoundingBox().minY, this.posZ)) >= 0.0F; } - - public boolean hasPath() - { - return !this.navigator.noPath(); - } public boolean isWithinHomeDistanceCurrentPosition() { @@ -3328,10 +2944,6 @@ public abstract class EntityLiving extends Entity { return this.maximumHomeDistance != -1.0F; } - - protected void onUpdateLeashed(float distance) - { - } protected void setSize(float width, float height) { diff --git a/common/src/common/pathfinding/PathNavigateGround.java b/common/src/common/pathfinding/PathNavigateGround.java index f12b1c8..c9631ee 100755 --- a/common/src/common/pathfinding/PathNavigateGround.java +++ b/common/src/common/pathfinding/PathNavigateGround.java @@ -11,7 +11,7 @@ import common.util.Vec3; import common.world.World; public class PathNavigateGround extends PathNavigate -{ +{ protected WalkNodeProcessor nodeProcessor; private boolean shouldAvoidSun; diff --git a/server/src/server/ai/EntityNPCNode.java b/server/src/server/ai/EntityNPCNode.java new file mode 100644 index 0000000..b314cdc --- /dev/null +++ b/server/src/server/ai/EntityNPCNode.java @@ -0,0 +1,224 @@ +package server.ai; + +import java.util.function.Predicate; + +import common.ai.AIRangedAttack; +import common.ai.EntityAIAttackOnCollide; +import common.ai.EntityAIAvoidEntity; +import common.ai.EntityAIHurtByTarget; +import common.ai.EntityAILookAtTalkingPlayer; +import common.ai.EntityAINagPlayer; +import common.ai.EntityAINearestAttackableTarget; +import common.ai.EntityAINpcInteract; +import common.ai.EntityAINpcMate; +import common.ai.EntityAIOpenDoor; +import common.ai.EntityAIPlay; +import common.ai.EntityAISwimming; +import common.ai.EntityAIWander; +import common.ai.EntityAIWatchClosest; +import common.ai.EntityAIWatchClosest2; +import common.entity.npc.EntityNPC; +import common.entity.types.EntityLiving; +import common.item.ItemStack; +import common.pathfinding.PathNavigateGround; + +public class EntityNPCNode extends EntityNode { + protected final EntityAIAttackOnCollide aiMelee; + protected final AIRangedAttack aiRanged; + private boolean fleeing; + + public EntityNPCNode(EntityNPC entity) { + super(entity); + this.aiMelee = new EntityAIAttackOnCollide(entity, EntityLiving.class, 1.0D, true, true) { + public boolean shouldExecute() + { + return !EntityNPCNode.this.fleeing && super.shouldExecute(); + } + + public boolean continueExecuting() + { + return !EntityNPCNode.this.fleeing && super.shouldExecute(); + } + }; + this.aiRanged = new AIRangedAttack(entity, 1.0D, entity.getAttackSpeed(), entity.getAttackSpeed() * 3, 15.0F) { +// public void startExecuting() +// { +// super.startExecuting(); +// EntityNPC.this.setUsingItem(true); +// } +// +// public void resetTask() +// { +// super.resetTask(); +// EntityNPC.this.setUsingItem(false); +// } + + public boolean shouldExecute() + { + return !EntityNPCNode.this.fleeing && super.shouldExecute(); + } + + public boolean continueExecuting() + { + return !EntityNPCNode.this.fleeing && super.shouldExecute(); + } + }; + } + + public EntityNPC getEntity() { + return (EntityNPC)this.entity; + } + + protected void registerTasks() { + if(this.getNavigator() instanceof PathNavigateGround) { + ((PathNavigateGround)this.getNavigator()).setBreakDoors(true); + ((PathNavigateGround)this.getNavigator()).setAvoidsWater(true); + } + this.tasks.addTask(0, new EntityAISwimming(this.getEntity())); +// this.tasks.addTask(1, new EntityAIAttackOnCollide(this, EntityNPC.class, 0.6D, true, true)); +// this.tasks.addTask(1, new EntityAIAttackOnCollide(this, EntityLivingBase.class, 0.6D, true, true)); + this.tasks.addTask(1, new EntityAINpcMate(this.getEntity())); + this.tasks.addTask(2, new EntityAIAvoidEntity(this.getEntity(), EntityLiving.class, new Predicate() { + public boolean test(EntityLiving entity) { + return entity != EntityNPCNode.this.entity && EntityNPC.this.shouldFlee(entity); + } + }, 8.0F, 1.1D, 1.1D) { + { + this.setMutexBits(0); + } + + public void startExecuting() { + EntityNPCNode.this.setAttackTarget(null); + EntityNPCNode.this.fleeing = true; + } + + public boolean continueExecuting() { + return false; + } + + public void updateTask() + { + } + +// public void resetTask() { +// super.resetTask(); +// EntityNPC.this.isFleeing = false; +// } + }); + this.tasks.addTask(3, new EntityAIAvoidEntity(this, EntityLiving.class, new Predicate() { + public boolean test(EntityLiving entity) { + return entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity); + } + }, 8.0F, 1.1D, 1.1D) { + public void startExecuting() { + super.startExecuting(); + EntityNPC.this.setAttackTarget(null); + EntityNPC.this.fleeing = true; + } + + public void resetTask() { + super.resetTask(); + EntityNPC.this.fleeing = false; + } + }); +// this.tasks.addTask(2, new EntityAITempt(this, 1.0D, Items.golden_apple, false)); + this.tasks.addTask(4, new EntityAIOpenDoor(this, true)); + this.tasks.addTask(5, new EntityAINagPlayer(this)); + this.tasks.addTask(5, new EntityAILookAtTalkingPlayer(this)); + this.tasks.addTask(6, new EntityAIWatchClosest2(this, null, 3.0F, 1.0F) { + private int sneakTime; + + public void updateTask() + { + super.updateTask(); + boolean flag = this.closestEntity.isPlayer() && this.closestEntity.isSneaking(); + if(this.sneakTime > 0) { + if(--this.sneakTime == 0) { + EntityNPC.this.setSneaking(false); + } + } + else if(EntityNPC.this.getAttackTarget() == null && EntityNPC.this.rand.chance(flag ? 5 : 200)) { + EntityNPC.this.setSneaking(true); + this.sneakTime = EntityNPC.this.rand.range(60, flag ? 160 : 120); + } + else if(EntityNPC.this.getAttackTarget() != null) { + EntityNPC.this.setSneaking(false); + this.sneakTime = 0; + } + } + + public void resetTask() + { + super.resetTask(); + EntityNPC.this.setSneaking(false); + } + }); + this.tasks.addTask(7, new EntityAINpcInteract(this)); + this.tasks.addTask(8, new EntityAIWander(this, 1.0D)); + this.tasks.addTask(8, new EntityAIPlay(this, 1.1D)); + this.tasks.addTask(9, new EntityAIWatchClosest(this, EntityLiving.class, 8.0F)); + this.targets.addTask(1, new EntityAIHurtByTarget(this, false, /* EntityNPC.class, */ EntityLiving.class) { + protected boolean isSuitableTarget(EntityLiving entity) { + if(entity != null && entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity)) { + EntityNPC.this.setAttackTarget(null); + EntityNPC.this.fleeing = true; + return false; + } + return entity != null && entity != EntityNPC.this && (!(entity.isPlayer()) || EntityNPC.this.rand.chance(entity.getAttackedBy() == EntityNPC.this ? 2 : 4)) + && EntityNPC.this.canCounter(entity) && super.isSuitableTarget(entity); + } + }); + this.targets.addTask(2, new EntityAINearestAttackableTarget(this, EntityLiving.class, 10, true, false, new Predicate() { + public boolean test(EntityLiving entity) { + if(entity != null && entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity)) { + EntityNPC.this.setAttackTarget(null); + EntityNPC.this.fleeing = true; + return false; + } + return entity != null && entity != EntityNPC.this && !EntityNPC.this.fleeing && EntityNPC.this.canAmbush(entity) && EntityNPC.this.canAttack(entity); + } + })); +// this.setCanPickUpLoot(true); + + if (worldIn != null && !worldIn.client) + { + this.setCombatTask(); + } + } + + public void updateLeashedState() { + if(!this.player) + super.updateLeashedState(); + } + + public void sendDeathMessage() { + this.sendDeathMessage(this.player, true); + } + + public int getMaxFallHeight() + { + return this.player ? 3 : super.getMaxFallHeight(); + } + + public void setCombatTask() + { + if(!this.player) { + this.tasks.removeTask(this.aiMelee); + this.tasks.removeTask(this.aiRanged); + ItemStack itemstack = this.getEntity().getHeldItem(); + + if (this.getEntity().isRangedWeapon(itemstack)) + { + this.tasks.addTask(3, this.aiRanged); + } + else + { + this.tasks.addTask(3, this.aiMelee); + } + } + } + + public boolean isFleeing() { + return this.fleeing; + } +} diff --git a/server/src/server/ai/EntityNode.java b/server/src/server/ai/EntityNode.java new file mode 100644 index 0000000..2f4c0a7 --- /dev/null +++ b/server/src/server/ai/EntityNode.java @@ -0,0 +1,436 @@ +package server.ai; + +import java.util.List; + +import common.ai.EntityAIBase; +import common.ai.EntityAIMoveTowardsRestriction; +import common.ai.EntityAITasks; +import common.ai.EntityJumpHelper; +import common.ai.EntityLookHelper; +import common.ai.EntityMoveHelper; +import common.ai.EntitySenses; +import common.ai.IEntityNode; +import common.block.Block; +import common.collect.Lists; +import common.color.TextColor; +import common.entity.DamageSource; +import common.entity.Entity; +import common.entity.EntityDamageSource; +import common.entity.item.EntityLeashKnot; +import common.entity.npc.EntityNPC; +import common.entity.types.CombatEntry; +import common.entity.types.EntityBodyHelper; +import common.entity.types.EntityLiving; +import common.entity.types.EntityTameable; +import common.init.Blocks; +import common.item.ItemStack; +import common.nbt.NBTTagCompound; +import common.network.IPlayer; +import common.pathfinding.PathNavigate; +import common.pathfinding.PathNavigateGround; +import common.util.BlockPos; +import common.world.WorldServer; + +public abstract class EntityNode implements IEntityNode { + protected final EntityLiving entity; + protected final boolean player; + private final List combat = Lists.newArrayList(); + private EntityLookHelper lookHelper; + protected EntityMoveHelper moveHelper; + protected EntityJumpHelper jumpHelper; + private EntityBodyHelper bodyHelper; + protected PathNavigate navigator; + protected final EntityAITasks tasks; + protected final EntityAITasks targets; + private EntityLiving target; + private EntitySenses senses; + private Runnable tickFunc; + private NBTTagCompound leashTag; + private boolean isMovementAITaskSet; + private EntityAIBase aiBase; + private boolean attacked; + private boolean damaged; + private String blockType; + private int lastDamaged; + + public EntityNode(EntityLiving entity) { + this.entity = entity; + this.player = entity.isPlayer(); + this.tasks = new EntityAITasks(); + this.targets = new EntityAITasks(); + this.lookHelper = new EntityLookHelper(entity); + this.moveHelper = new EntityMoveHelper(entity); + this.jumpHelper = new EntityJumpHelper(entity); + this.bodyHelper = new EntityBodyHelper(entity); + this.navigator = this.getNewNavigator(); + this.senses = new EntitySenses(entity); + this.aiBase = new EntityAIMoveTowardsRestriction(entity, 1.0D); + this.registerTasks(); + } + + protected PathNavigate getNewNavigator() { + return new PathNavigateGround(this.entity, this.entity.worldObj); + } + +// protected PathNavigate getNewNavigator() { EntityArachnoid +// return new PathNavigateClimber(this.entity, this.entity.worldObj); +// } + + protected abstract void registerTasks(); + + public void setTickFunction(Runnable func) { + this.tickFunc = func; + } + + public EntityLookHelper getLookHelper() { + return this.lookHelper; + } + + public EntityMoveHelper getMoveHelper() { + return this.moveHelper; + } + + public EntityJumpHelper getJumpHelper() { + return this.jumpHelper; + } + + public PathNavigate getNavigator() { + return this.navigator; + } + + public EntitySenses getEntitySenses() { + return this.senses; + } + + public EntityLiving getAttackTarget() { + return this.target; + } + + public void setAttackTarget(EntityLiving entitylivingbaseIn) { + this.target = entitylivingbaseIn; + } + + public boolean hasPath() + { + return !this.navigator.noPath(); + } + + public void updateRenderAngles() { + this.bodyHelper.updateRenderAngles(); + } + + public void update() { + this.senses.clearSensingCache(); + this.targets.onUpdateTasks(); + this.tasks.onUpdateTasks(); + this.navigator.onUpdateNavigation(); + if(this.tickFunc != null) + this.tickFunc.run(); + this.moveHelper.onUpdateMoveHelper(); + this.lookHelper.onUpdateLook(); + this.jumpHelper.doJump(); + } + + public void setLeashTag(NBTTagCompound tag) { + this.leashTag = tag; + } + + private void recreateLeash() { + if(this.entity.getLeashed() && this.leashTag != null) { +// if(this.leashTag.hasKey("PlayerName", 8)) { +// String id = this.leashTag.getString("PlayerName"); +// if(!id.isEmpty()) { +// for(EntityNPC entitylivingbase : this.worldObj.getEntitiesWithinAABB(EntityNPC.class, +// this.getEntityBoundingBox().expand(10.0D, 10.0D, 10.0D))) { +// if(entitylivingbase.getUser().equals(id)) { +// this.leashedTo = entitylivingbase; +// break; +// } +// } +// } +// } +// else + if(this.leashTag.hasKey("X", 99) && this.leashTag.hasKey("Y", 99) && this.leashTag.hasKey("Z", 99)) { + BlockPos blockpos = new BlockPos(this.leashTag.getInteger("X"), this.leashTag.getInteger("Y"), + this.leashTag.getInteger("Z")); + EntityLeashKnot entityleashknot = EntityLeashKnot.getKnotForPosition(this.entity.worldObj, blockpos); + + if(entityleashknot == null) { + entityleashknot = EntityLeashKnot.createKnot(this.entity.worldObj, blockpos); + } + + this.entity.setLeashedTo(entityleashknot, false); + } + else { + this.entity.clearLeashed(false, true); + } + } + + this.leashTag = null; + } + + protected void onUpdateLeashed(float distance) + { + } + +// protected void onUpdateLeashed(float distance) EntityHorse +// { +// if (distance > 6.0F && this.entity.isEatingHaystack()) +// { +// this.entity.setEatingHaystack(false); +// } +// } + + public void updateLeashedState() { + if(this.leashTag != null) { + this.recreateLeash(); + } + + if(this.entity.getLeashed()) { + if(!this.entity.isEntityAlive()) { + this.entity.clearLeashed(true, true); + } + + if(this.entity.getLeashedTo() == null || this.entity.getLeashedTo().dead) { + this.entity.clearLeashed(true, true); + } + } + + if (this.entity.getLeashed() && this.entity.getLeashedTo() != null && this.entity.getLeashedTo().worldObj == this.entity.worldObj) + { + Entity entity = this.entity.getLeashedTo(); + this.entity.setHomePosAndDistance(new BlockPos((int)entity.posX, (int)entity.posY, (int)entity.posZ), 5); + float f = this.entity.getDistanceToEntity(entity); + + if (this.entity instanceof EntityTameable && ((EntityTameable)this.entity).isSitting()) + { + if (f > 10.0F) + { + this.entity.clearLeashed(true, true); + } + + return; + } + + if (!this.isMovementAITaskSet) + { + this.tasks.addTask(2, this.aiBase); + + if (this.getNavigator() instanceof PathNavigateGround) + { + ((PathNavigateGround)this.getNavigator()).setAvoidsWater(false); + } + + this.isMovementAITaskSet = true; + } + + this.onUpdateLeashed(f); + + if (f > 4.0F) + { + this.getNavigator().tryMoveToEntityLiving(entity, 1.0D); + } + + if (f > 6.0F) + { + double d0 = (entity.posX - this.entity.posX) / (double)f; + double d1 = (entity.posY - this.entity.posY) / (double)f; + double d2 = (entity.posZ - this.entity.posZ) / (double)f; + this.entity.motionX += d0 * Math.abs(d0) * 0.4D; + this.entity.motionY += d1 * Math.abs(d1) * 0.4D; + this.entity.motionZ += d2 * Math.abs(d2) * 0.4D; + } + + if (f > 10.0F) + { + this.entity.clearLeashed(true, true); + } + } + else if (!this.entity.getLeashed() && this.isMovementAITaskSet) + { + this.isMovementAITaskSet = false; + this.tasks.removeTask(this.aiBase); + + if (this.getNavigator() instanceof PathNavigateGround) + { + ((PathNavigateGround)this.getNavigator()).setAvoidsWater(true); + } + + this.entity.detachHome(); + } + } + + public void trackDamage(DamageSource source, int amount) { + this.resetCombat(); + this.blockType = null; + if(this.entity.isOnLadder()) { + Block block = this.entity.worldObj + .getState(new BlockPos(this.entity.posX, this.entity.getEntityBoundingBox().minY, this.entity.posZ)).getBlock(); + if(block == Blocks.ladder) + this.blockType = "von einer Leiter"; + else if(block == Blocks.vine) + this.blockType = "von Ranken"; + } + else if(this.entity.isInLiquid()) { + this.blockType = "aus dem Wasser"; + } + CombatEntry entry = new CombatEntry(source, amount, this.blockType, this.entity.fallDistance); + this.combat.add(entry); + this.lastDamaged = this.entity.ticksExisted; + this.damaged = true; + if(entry.getSource().getEntity() instanceof EntityLiving && !this.attacked && this.entity.isEntityAlive()) + this.attacked = true; + } + + public void sendDeathMessage() { + this.sendDeathMessage(false, false); + } + + protected void sendDeathMessage(boolean natural, boolean forAll) { +// if(this.entity.worldObj.client) +// return; + String msg; + String kill; + IPlayer receiver = null; + if(this.combat.size() == 0) { + msg = kill = natural ? String.format("%s starb", this.entity.getColoredName(TextColor.LGRAY)) : null; + } + else { + CombatEntry strong = null; + CombatEntry block = null; + int min = 0; + float max = 0.0F; + + for(int z = 0; z < this.combat.size(); ++z) { + CombatEntry entry = (CombatEntry)this.combat.get(z); + CombatEntry last = z > 0 ? (CombatEntry)this.combat.get(z - 1) : null; + + if((entry.getSource() == DamageSource.fall || entry.getSource() == DamageSource.outOfWorld) && + entry.getFallDistance() > 0.0F && (strong == null || entry.getFallDistance() > max)) { + if(z > 0) { + strong = last; + } + else { + strong = entry; + } + + max = entry.getFallDistance(); + } + + if(entry.getBlockType() != null && (block == null || entry.getDamage() > min)) { + block = entry; + } + } + CombatEntry fall = max > 5.0F && strong != null ? strong : (min > 5 && block != null ? block : null); + CombatEntry last = (CombatEntry)this.combat.get(this.combat.size() - 1); + Entity lastEnt = last.getSource().getEntity(); + + if(fall != null && last.getSource() == DamageSource.fall) { + if(fall.getSource() != DamageSource.fall && fall.getSource() != DamageSource.outOfWorld) { + Entity fallEnt = fall.getSource().getEntity(); + if(fallEnt != null && (lastEnt == null || fallEnt != lastEnt)) { + ItemStack fallItem = fallEnt instanceof EntityLiving ? ((EntityLiving)fallEnt).getHeldItem() : null; + receiver = fallEnt.isPlayer() ? ((EntityNPC)fallEnt).connection : null; + if(fallItem != null) { // && fallItem.hasDisplayName()) { + msg = String.format("%s wurde von %s mit %s zum Fallen verdammt", this.entity.getColoredName(TextColor.CYAN), + fallEnt.getColoredName(TextColor.CYAN), fallItem.getColoredName(TextColor.CYAN)); + kill = String.format(TextColor.CYAN + "* %s mit %s zum Fallen verdammt", + this.entity.getColoredName(TextColor.CYAN), fallItem.getColoredName(TextColor.CYAN)); + } + else { + msg = String.format("%s wurde von %s zum Fallen verdammt", this.entity.getColoredName(TextColor.CYAN), + fallEnt.getColoredName(TextColor.CYAN)); + kill = String.format(TextColor.CYAN + "* %s zum Fallen verdammt", + this.entity.getColoredName(TextColor.CYAN)); + } + } + else if(lastEnt != null) { + ItemStack lastItem = lastEnt instanceof EntityLiving ? ((EntityLiving)lastEnt).getHeldItem() : null; + receiver = lastEnt.isPlayer() ? ((EntityNPC)lastEnt).connection : null; + if(lastItem != null) { // && lastItem.hasDisplayName()) { + msg = String.format("%s fiel zu tief und wurde von %s mit %s erledigt", + this.entity.getColoredName(TextColor.BLUE), + lastEnt.getColoredName(TextColor.BLUE), lastItem.getColoredName(TextColor.BLUE)); + kill = String.format(TextColor.BLUE + "* %s mit %s erledigt", + this.entity.getColoredName(TextColor.BLUE), lastItem.getColoredName(TextColor.BLUE)); + } + else { + msg = String.format("%s fiel zu tief und wurde von %s erledigt", this.entity.getColoredName(TextColor.BLUE), + lastEnt.getColoredName(TextColor.BLUE)); + kill = String.format(TextColor.BLUE + "%s erledigt", this.entity.getColoredName(TextColor.BLUE)); + } + } + else { + msg = kill = natural ? String.format("%s wurde zum Fallen verdammt", this.entity.getColoredName(TextColor.CYAN)) : null; + } + } + else { + msg = kill = natural ? String.format("%s fiel " + (fall.getBlockType() == null ? "aus zu großer Höhe" : fall.getBlockType()), + this.entity.getColoredName(TextColor.NEON)) : null; + } + } + else { + receiver = last.getSource().getEntity() != null && last.getSource().getEntity().isPlayer() ? ((EntityNPC)last.getSource().getEntity()).connection : null; + msg = natural || (last.getSource() instanceof EntityDamageSource ? last.getSource().getEntity() != null : this.entity.getAttackingEntity() != null) ? last.getSource().getDeathMessage(this.entity) : null; + kill = msg == null ? null : last.getSource().getKillMessage(this.entity); + } + } + if(msg == null) + return; + if(receiver != null) + receiver.addFeed(kill); + if(forAll) + for(IPlayer player : ((WorldServer)this.entity.worldObj).getServer().getIPlayers()) { + if(player != receiver) + player.addFeed(msg); + } + } + + public EntityLiving getAttacking() { + EntityLiving entity = null; + EntityNPC player = null; + int edmg = 0; + int pdmg = 0; + for(CombatEntry entry : this.combat) { + if(entry.getSource().getEntity() != null && entry.getSource().getEntity().isPlayer() && (player == null || entry.getDamage() > pdmg)) { + pdmg = entry.getDamage(); + player = (EntityNPC)entry.getSource().getEntity(); + } + if(entry.getSource().getEntity() instanceof EntityLiving && (entity == null || entry.getDamage() > edmg)) { + edmg = entry.getDamage(); + entity = (EntityLiving)entry.getSource().getEntity(); + } + } + return player != null && pdmg >= edmg / 3 ? player : entity; + } + + public void resetCombat() { + int timeout = this.attacked ? 300 : 100; + if(this.damaged && (!this.entity.isEntityAlive() || this.entity.ticksExisted - this.lastDamaged > timeout)) { + this.damaged = false; + this.attacked = false; + this.combat.clear(); + } + } + + public int getMaxFallHeight() { + if(this.target == null) { + return 3; + } + else { + int i = (int)((float)this.entity.getHealth() - (float)this.entity.getMaxHealth() * 0.33F); +// i = i - (3 - this.worldObj.getDifficulty().getId()) * 4; + + if(i < 0) { + i = 0; + } + + return i + 3; + } + } + +// public int getMaxFallHeight() EntityHaunter +// { +// return this.getAttackTarget() == null ? 3 : 3 + (this.getHealth() - 1); +// } +}