diff --git a/src/main/java/com/reider745/behavior/entities/ComponentsTag.java b/src/main/java/com/reider745/behavior/entities/ComponentsTag.java index 528a3afe4..e1e9671e4 100644 --- a/src/main/java/com/reider745/behavior/entities/ComponentsTag.java +++ b/src/main/java/com/reider745/behavior/entities/ComponentsTag.java @@ -2,9 +2,6 @@ public abstract class ComponentsTag { public abstract String getNameTag(); - public int getPriority(){ - return 0; - } public void load(EntityContentFactory factory, Object json){ diff --git a/src/main/java/com/reider745/behavior/entities/CustomEntity.java b/src/main/java/com/reider745/behavior/entities/CustomEntity.java index f1b2fc3e0..9842cf897 100644 --- a/src/main/java/com/reider745/behavior/entities/CustomEntity.java +++ b/src/main/java/com/reider745/behavior/entities/CustomEntity.java @@ -2,27 +2,23 @@ import cn.nukkit.Player; import cn.nukkit.block.Block; +import cn.nukkit.block.BlockCarpet; import cn.nukkit.block.BlockID; import cn.nukkit.entity.BaseEntity; import cn.nukkit.entity.Entity; -import cn.nukkit.entity.EntityBoss; import cn.nukkit.entity.custom.EntityDefinition; +import cn.nukkit.event.entity.EntityDamageByEntityEvent; import cn.nukkit.event.entity.EntityDamageEvent; -import cn.nukkit.item.Item; import cn.nukkit.level.format.FullChunk; -import cn.nukkit.level.particle.Particle; -import cn.nukkit.level.particle.SmokeParticle; import cn.nukkit.math.Vector3; import cn.nukkit.nbt.tag.CompoundTag; import cn.nukkit.network.protocol.AddEntityPacket; import cn.nukkit.network.protocol.DataPacket; import cn.nukkit.utils.DummyBossBar; -import com.reider745.InnerCoreServer; -import com.reider745.behavior.entities.formats.tags.components.navigation.NavigationComponentsTag; +import com.reider745.behavior.entities.formats.tags.components.IUpdateEntity; import org.jetbrains.annotations.NotNull; -import java.util.Optional; -import java.util.Random; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class CustomEntity extends BaseEntity implements cn.nukkit.entity.custom.CustomEntity { @@ -46,14 +42,25 @@ public Block isSolid(double x, double y, double z){ return block.getId() != BlockID.AIR && block.isSolid() ? block : null; } + public Block raycast(Entity ent1, Entity ent2){ + final Vector3 pos1 = ent1.getPosition() + .add(0, getHeight() * .75); + final Vector3 pos2 = ent2.getPosition(); + final int iterations = (int) (pos2.distance(pos1) * 3d); + return raycast(pos1, pos2.subtract(pos1).divide(iterations), iterations); + } + + public Block raycast(Entity ent2){ + return raycast(this, ent2); + } + public Block raycast(Vector3 pos, Vector3 move, int iterations){ - double x = pos.x; for(int i = 0;i < iterations;i++){ final Block check = isSolid(pos.x, pos.y, pos.z); if(check != null) { - // this.level.setBlock(check, Block.get(BlockID.NETHERITE_BLOCK)); return check; } + pos.x += move.x; pos.y += move.y; pos.z += move.z; @@ -62,12 +69,49 @@ public Block raycast(Vector3 pos, Vector3 move, int iterations){ } public Block raycast(Vector3 pos, Vector3 move){ - return raycast(pos, move, 3); + return raycast(pos, move, 4); + } + + + // Jump for PNX 2.0 + public double getJumpingMotion(double jumpY) { + if (this.isInsideOfWater()) { + if (jumpY > 0 && jumpY < 0.2) { + return 0.25; + } else if (jumpY < 0.51) { + return 0.45; + } else if (jumpY < 1.01) { + return 0.6; + } else { + return 0.7; + } + } else { + if (jumpY > 0 && jumpY < 0.2) { + return 0.15; + } else if (jumpY < 0.51) { + return 0.35; + } else if (jumpY < 1.01) { + return 0.5; + } else { + return 0.6; + } + } + } + + private boolean canJump(Block block) { + if (block.isSolid()) return true; + else if (block instanceof BlockCarpet) return true; + else return block.getId() == BlockID.FLOWER_POT_BLOCK || block.getId() == BlockID.CAKE_BLOCK; } @Override public Vector3 updateMove(int tickDiff) { if (this.isMovement() && !isImmobile()) { + if(factory.isPushable){ + this.move(this.motionX, this.motionY, this.motionZ); + this.updateMovement(); + } + this.motionX = 0; this.motionY = 0; this.motionZ = 0; @@ -75,14 +119,15 @@ public Vector3 updateMove(int tickDiff) { final double gravity_value = this.getGravity() * 4; final Vector3 pos = this.getPosition().clone(); - if(factory.isPhysics && isSolid(pos.x, pos.y - gravity_value,pos.z) == null) {// Гравитация + if(factory.isPhysics && isSolid(pos.x, pos.y - 0.001,pos.z) == null) { this.motionY -= gravity_value; } if(factory.isMovement){// Движение tickMove++; - if(target == null || tickMove >= maxTimeMove) + if(target == null || tickMove >= maxTimeMove) { targetPositionMovementUpdate(); + } if(pos.distance(target) < 1){ target = null; @@ -93,9 +138,12 @@ public Vector3 updateMove(int tickDiff) { motionX += move.x * factory.movement; motionZ += move.z * factory.movement; - // Если припятсвие в два блока меняем точку назначения - if(raycast(pos, move) != null && raycast(pos.add(0, 1, 0), move) != null) - targetPositionMovementUpdate(); + if(this.getHeight() <= 1){ + if(raycast(pos, move) != null && raycast(pos.add(0, 1.2, 0), move) != null) + targetPositionMovementUpdate(); + }else + if(raycast(pos.add(0, 1.2, 0), move) != null) + targetPositionMovementUpdate(); } } @@ -106,19 +154,26 @@ public Vector3 updateMove(int tickDiff) { final Vector3 check = new Vector3(this.motionX, 0, this.motionZ); // Проверка на один блок перед ним и на 0 гравитацию - if(raycast(pos, check) != null && raycast(pos.add(0, 1, 0), check) == null && motionY == 0) + if(raycast(pos.add(0, 0.2), check, 9) != null && raycast(pos.add(0, 1.2), check, 9) == null && motionY == 0) { tickJump = 0; + } }else{ + tickJump++; - final double max_minus = maxTimeJump / 2d; - final double minus = (tickJump - max_minus); + final var xzLength = Math.sqrt(motionX * motionX + motionZ * motionZ); + final var k = factory.movement / xzLength * 0.33; + final var dx = motionX * k; + final var dz = motionZ * k; + + final Block[] collisionBlocks = this.level.getCollisionBlocks( + this.getBoundingBox().getOffsetBoundingBox(dx, 0, dz), false, false, this::canJump); if (motionY < 0) this.motionY = 0; - this.motionY += (gravity_value / 2) * ((minus * minus) / (max_minus * max_minus)); - + final double maxY = Arrays.stream(collisionBlocks).map(b -> b.getCollisionBoundingBox().getMaxY()).max(Double::compareTo).orElse(0.0d); + motionY += getJumpingMotion(maxY - this.getY()) / 6d; if(tickJump > maxTimeJump){ tickJump = -1; @@ -210,7 +265,7 @@ public boolean onUpdate(int currentTick) { return false; } - for(NavigationComponentsTag tag : factory.navigations_compononets) + for(IUpdateEntity tag : factory.updates) tag.onUpdate(this); if (!this.isAlive()) { @@ -271,6 +326,20 @@ public void spawnTo(Player player) { super.spawnTo(player); } + @Override + public void setTarget(Entity target) { + this.setTargetBlock(target); + super.setTarget(target); + } + + @Override + public boolean attack(EntityDamageEvent source) { + if(source instanceof EntityDamageByEntityEvent event){ + this.setTarget(event.getDamager()); + } + return super.attack(source); + } + @Override public void despawnFrom(Player player) { if(factory.boss != null){ diff --git a/src/main/java/com/reider745/behavior/entities/EntityContentFactory.java b/src/main/java/com/reider745/behavior/entities/EntityContentFactory.java index 2e70026ec..052feb5e0 100644 --- a/src/main/java/com/reider745/behavior/entities/EntityContentFactory.java +++ b/src/main/java/com/reider745/behavior/entities/EntityContentFactory.java @@ -8,6 +8,7 @@ import com.reider745.behavior.entities.formats.tags.components.BossComponent; import com.reider745.behavior.entities.formats.tags.components.CollisionComponent; import com.reider745.behavior.entities.formats.tags.components.HealthComponent; +import com.reider745.behavior.entities.formats.tags.components.IUpdateEntity; import com.reider745.behavior.entities.formats.tags.components.attack.MeleeAttackComponent; import com.reider745.behavior.entities.formats.tags.components.attack.NearestAttackableTarget; import com.reider745.behavior.entities.formats.tags.components.navigation.NavigationComponentsTag; @@ -28,7 +29,7 @@ public class EntityContentFactory { public BossComponent boss = null; public NavigationRandomStroll navigationRandomStroll = new NavigationRandomStroll(); - public ArrayList navigations_compononets = new ArrayList<>(); + public ArrayList updates = new ArrayList<>(); public NavigationWalkComponent navigationWalkComponent = new NavigationWalkComponent(); public NearestAttackableTarget nearestAttackableTarget = null; @@ -40,21 +41,24 @@ public class EntityContentFactory { public boolean isJump = false; public boolean isMovement = false; public boolean isPhysics = false; - public boolean isNameable; + public boolean isHurtByTarget = false; + public boolean isNameable = false; + public boolean isPushable = false; public float movement = .5f; public int damage = 0; public static final HashMap factoryMap = new HashMap<>(); - public void addNavigationComponent(NavigationComponentsTag tag){ - for (int i = 0; i < navigations_compononets.size(); i++) { - if (navigations_compononets.get(i).getPriority() < tag.getPriority()) { - navigations_compononets.add(i, tag); + + public void addUpdate(IUpdateEntity tag){ + for (int i = 0; i < updates.size(); i++) { + if (updates.get(i).getPriority() < tag.getPriority()) { + updates.add(i, tag); return; } } - navigations_compononets.add(tag); + updates.add(tag); } public EntityDefinition getEntityDefinition() { diff --git a/src/main/java/com/reider745/behavior/entities/formats/tags/ComponentsFactory.java b/src/main/java/com/reider745/behavior/entities/formats/tags/ComponentsFactory.java index 2087bf85d..993064cc5 100644 --- a/src/main/java/com/reider745/behavior/entities/formats/tags/ComponentsFactory.java +++ b/src/main/java/com/reider745/behavior/entities/formats/tags/ComponentsFactory.java @@ -4,6 +4,7 @@ import com.reider745.behavior.entities.EntityContentFactory; import com.reider745.behavior.entities.TagContentFactory; import com.reider745.behavior.entities.formats.tags.components.*; +import com.reider745.behavior.entities.formats.tags.components.attack.HurtByTargetComponent; import com.reider745.behavior.entities.formats.tags.components.attack.MeleeAttackComponent; import com.reider745.behavior.entities.formats.tags.components.attack.NearestAttackableTarget; import com.reider745.behavior.entities.formats.tags.components.navigation.NavigationRandomStroll; @@ -11,7 +12,6 @@ import com.zhekasmirnov.horizon.runtime.logger.Logger; import org.json.JSONObject; -import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -24,13 +24,15 @@ private static void add(ComponentsTag tag){ static { add(new FireImmuneComponent()); - add(new CollisionComponent()); add(new HealthComponent()); add(new FamilyComponent()); add(new NameableComponent()); add(new BossComponent()); + add(new BurnsInDaylight()); add(new GravityComponent()); + add(new CollisionComponent()); + add(new PushableComponent()); add(new JumpComponent()); add(new MovementBasicComponent()); add(new MovementComponent()); @@ -40,6 +42,7 @@ private static void add(ComponentsTag tag){ add(new AttackComponent()); add(new NearestAttackableTarget()); add(new MeleeAttackComponent()); + add(new HurtByTargetComponent()); } @Override diff --git a/src/main/java/com/reider745/behavior/entities/formats/tags/components/BurnsInDaylight.java b/src/main/java/com/reider745/behavior/entities/formats/tags/components/BurnsInDaylight.java new file mode 100644 index 000000000..5887de116 --- /dev/null +++ b/src/main/java/com/reider745/behavior/entities/formats/tags/components/BurnsInDaylight.java @@ -0,0 +1,33 @@ +package com.reider745.behavior.entities.formats.tags.components; + +import com.reider745.behavior.entities.ComponentsTag; +import com.reider745.behavior.entities.CustomEntity; +import com.reider745.behavior.entities.EntityContentFactory; +import com.zhekasmirnov.horizon.runtime.logger.Logger; +import org.json.JSONObject; + +public class BurnsInDaylight extends ComponentsTag implements IUpdateEntity { + @Override + public String getNameTag() { + return "minecraft:burns_in_daylight"; + } + + @Override + public void load(EntityContentFactory factory, Object json) { + if(json instanceof JSONObject){ + factory.addUpdate(new BurnsInDaylight()); + }else + Logger.warning("Not support BurnsInDaylight "+json.getClass()); + } + + @Override + public void onUpdate(CustomEntity entity) { + if (entity.level.shouldMobBurn(entity)) { + if (entity.armor == null || entity.armor[0] == null) { + entity.setOnFire(100); + } else if (entity.armor[0].getId() == 0) { + entity.setOnFire(100); + } + } + } +} diff --git a/src/main/java/com/reider745/behavior/entities/formats/tags/components/IUpdateEntity.java b/src/main/java/com/reider745/behavior/entities/formats/tags/components/IUpdateEntity.java index 327e312c9..dd22448e8 100644 --- a/src/main/java/com/reider745/behavior/entities/formats/tags/components/IUpdateEntity.java +++ b/src/main/java/com/reider745/behavior/entities/formats/tags/components/IUpdateEntity.java @@ -4,4 +4,5 @@ public interface IUpdateEntity { void onUpdate(CustomEntity entity); + default int getPriority(){return 0;} } diff --git a/src/main/java/com/reider745/behavior/entities/formats/tags/components/PushableComponent.java b/src/main/java/com/reider745/behavior/entities/formats/tags/components/PushableComponent.java new file mode 100644 index 000000000..e65d1c04c --- /dev/null +++ b/src/main/java/com/reider745/behavior/entities/formats/tags/components/PushableComponent.java @@ -0,0 +1,21 @@ +package com.reider745.behavior.entities.formats.tags.components; + +import com.reider745.behavior.entities.ComponentsTag; +import com.reider745.behavior.entities.EntityContentFactory; +import com.zhekasmirnov.horizon.runtime.logger.Logger; +import org.json.JSONObject; + +public class PushableComponent extends ComponentsTag { + @Override + public String getNameTag() { + return "minecraft:pushable"; + } + + @Override + public void load(EntityContentFactory factory, Object json) { + if(json instanceof JSONObject object){ + factory.isPushable = object.optBoolean("is_pushable", true); + }else + Logger.warning("Not support MovementComponent "+json.getClass()); + } +} diff --git a/src/main/java/com/reider745/behavior/entities/formats/tags/components/attack/HurtByTargetComponent.java b/src/main/java/com/reider745/behavior/entities/formats/tags/components/attack/HurtByTargetComponent.java new file mode 100644 index 000000000..1cd2d4c62 --- /dev/null +++ b/src/main/java/com/reider745/behavior/entities/formats/tags/components/attack/HurtByTargetComponent.java @@ -0,0 +1,22 @@ +package com.reider745.behavior.entities.formats.tags.components.attack; + +import com.reider745.behavior.entities.ComponentsTag; +import com.reider745.behavior.entities.EntityContentFactory; +import com.zhekasmirnov.horizon.runtime.logger.Logger; +import org.json.JSONObject; + +public class HurtByTargetComponent extends ComponentsTag { + @Override + public String getNameTag() { + return "minecraft:behavior.hurt_by_target"; + } + + @Override + public void load(EntityContentFactory factory, Object json) { + if(json instanceof JSONObject){ + //TODO: Not support priority + factory.isHurtByTarget = true; + }else + Logger.warning("Not support FireImmuneComponent "+json.getClass()); + } +} diff --git a/src/main/java/com/reider745/behavior/entities/formats/tags/components/attack/NearestAttackableTarget.java b/src/main/java/com/reider745/behavior/entities/formats/tags/components/attack/NearestAttackableTarget.java index 013bbae16..7522a2e90 100644 --- a/src/main/java/com/reider745/behavior/entities/formats/tags/components/attack/NearestAttackableTarget.java +++ b/src/main/java/com/reider745/behavior/entities/formats/tags/components/attack/NearestAttackableTarget.java @@ -1,5 +1,6 @@ package com.reider745.behavior.entities.formats.tags.components.attack; +import cn.nukkit.Player; import cn.nukkit.entity.Entity; import cn.nukkit.event.entity.EntityDamageByEntityEvent; import cn.nukkit.event.entity.EntityDamageEvent; @@ -94,12 +95,14 @@ public void load(EntityContentFactory factory, Object json) { @Override public void onUpdate(CustomEntity entity) { + if(entity.getServer().getDifficulty() == 0) + return; + boolean isTarget = false; for(Filters filters : list){ for(Entity check : entity.level.getEntities()){ - if(filters.test(entity, check)){ - entity.setTargetBlock(check.getPosition()); + if(filters.test(entity, check) && entity.raycast(check) == null && (!check.isPlayer || !((Player) check).isCreative())){ entity.setTarget(check); isTarget = true; break; @@ -108,8 +111,7 @@ public void onUpdate(CustomEntity entity) { if(isTarget) break; } - if(!isTarget){ - entity.setTargetBlock(null); + if(!isTarget && entity.getTarget() != null){ entity.setTarget(null); return; } diff --git a/src/main/java/com/reider745/behavior/entities/formats/tags/components/navigation/NavigationRandomStroll.java b/src/main/java/com/reider745/behavior/entities/formats/tags/components/navigation/NavigationRandomStroll.java index acac11db0..c7d83fa0b 100644 --- a/src/main/java/com/reider745/behavior/entities/formats/tags/components/navigation/NavigationRandomStroll.java +++ b/src/main/java/com/reider745/behavior/entities/formats/tags/components/navigation/NavigationRandomStroll.java @@ -1,11 +1,16 @@ package com.reider745.behavior.entities.formats.tags.components.navigation; +import cn.nukkit.block.Block; +import cn.nukkit.block.BlockID; +import cn.nukkit.math.BlockFace; import cn.nukkit.math.Vector3; import com.reider745.behavior.entities.CustomEntity; import com.reider745.behavior.entities.EntityContentFactory; import com.zhekasmirnov.horizon.runtime.logger.Logger; import org.json.JSONObject; +import java.util.ArrayList; +import java.util.List; import java.util.Random; public class NavigationRandomStroll extends NavigationComponentsTag { @@ -36,14 +41,48 @@ public void load(EntityContentFactory factory, Object json) { Logger.warning("Not support NavigationRandomStroll "+json.getClass()); } + protected boolean isSidesAir(Block block){ + for(int side = 0;side < 6;side++) { + final Block side_block = block.getSide(BlockFace.fromIndex(side)); + if (side_block.getId() == BlockID.AIR) + return true; + } + return false; + } + + protected List getBlocksSides(Block block){ + ArrayList list = new ArrayList<>(); + + for(int side = 0;side < 6;side++) { + final Block side_block = block.getSide(BlockFace.fromIndex(side)); + if(side_block.isSolid() && isSidesAir(side_block)) + list.add(side_block); + } + return list; + } + + protected Block randBlock(Random random, Block startBlock, int iterations, int max_iterations){ + List blocks = getBlocksSides(startBlock); + if(max_iterations <= iterations || blocks.isEmpty()) + return startBlock; + return randBlock(random, blocks.get(random.nextInt(blocks.size())), ++iterations, max_iterations); + } + @Override public void onUpdate(CustomEntity entity) { final Random random = new Random(); final Vector3 pos = entity.getPosition(); final Vector3 target = pos.clone(); - target.x += random.nextInt(5) - random.nextInt(10); - target.z += random.nextInt(5) - random.nextInt(10); + if(random.nextBoolean()) + target.x -= random.nextInt(8) + 4; + else + target.x += random.nextInt(8) + 4; + + if(random.nextBoolean()) + target.z -= random.nextInt(8) + 4; + else + target.z += random.nextInt(8) + 4; entity.setTargetBlock(target); entity.tickMove = 0; diff --git a/src/main/java/com/reider745/behavior/loots/LootsContent.java b/src/main/java/com/reider745/behavior/loots/LootsContent.java new file mode 100644 index 000000000..20bf553f5 --- /dev/null +++ b/src/main/java/com/reider745/behavior/loots/LootsContent.java @@ -0,0 +1,21 @@ +package com.reider745.behavior.loots; + +import com.reider745.behavior.BehaviorContent; +import org.json.JSONObject; + +public class LootsContent extends BehaviorContent { + @Override + public String getTagName() { + return "pools"; + } + + @Override + public String getDefaultDirectory() { + return "loots_tables"; + } + + @Override + public void load(JSONObject json) { + + } +}