mirror of
https://github.com/PurpurMC/Purpur.git
synced 2026-02-21 18:37:42 +01:00
Upstream has released updates that appears to apply and compile correctly Paper Changes: 1daafe455 Updated Upstream (Bukkit/CraftBukkit) 98828b006 Merge pull request #4132 from Proximyst/progress/1.16.2 b23f27f8d Fix incorrect return for WorldServer#addAllEntitiesSafely (#3) 5085fa30c Fix MC-187716 Use configured height c44add5a0 Initialise a new chunk section if none was found yet updated 74a4d5f8b Remove armour stand double add to world 6d25cc4ec Don't mark null chunk sections for block updates
351 lines
15 KiB
Diff
351 lines
15 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: William Blake Galbreath <blake.galbreath@gmail.com>
|
|
Date: Thu, 9 May 2019 18:26:06 -0500
|
|
Subject: [PATCH] Phantoms attracted to crystals and crystals shoot phantoms
|
|
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/DamageSource.java b/src/main/java/net/minecraft/server/DamageSource.java
|
|
index 6fe5678cff..bd0267ee4b 100644
|
|
--- a/src/main/java/net/minecraft/server/DamageSource.java
|
|
+++ b/src/main/java/net/minecraft/server/DamageSource.java
|
|
@@ -88,6 +88,7 @@ public class DamageSource {
|
|
return (new EntityDamageSourceIndirect("thrown", entity, entity1)).c();
|
|
}
|
|
|
|
+ public static DamageSource indirectMagic(Entity entity, @Nullable Entity owner) { return c(entity, owner); } // Purpur - OBFHELPER
|
|
public static DamageSource c(Entity entity, @Nullable Entity entity1) {
|
|
return (new EntityDamageSourceIndirect("indirectMagic", entity, entity1)).setIgnoreArmor().setMagic();
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
|
|
index 7b3ea5c741..26cefeb23c 100644
|
|
--- a/src/main/java/net/minecraft/server/Entity.java
|
|
+++ b/src/main/java/net/minecraft/server/Entity.java
|
|
@@ -1568,6 +1568,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
|
|
return d3 * d3 + d4 * d4 + d5 * d5;
|
|
}
|
|
|
|
+ public double getDistanceSq(Entity entity) { return this.h(entity); } // Purpur - OBFHELPER
|
|
public double h(Entity entity) {
|
|
return this.e(entity.getPositionVector());
|
|
}
|
|
@@ -2095,8 +2096,8 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
|
|
return this.a(new ItemStack(imaterial), (float) i);
|
|
}
|
|
|
|
- @Nullable
|
|
- public EntityItem a(ItemStack itemstack) {
|
|
+ @Nullable public EntityItem dropItem(ItemStack itemstack) { return this.a(itemstack); } // Purpur - OBFHELPER
|
|
+ @Nullable public EntityItem a(ItemStack itemstack) {
|
|
return this.a(itemstack, 0.0F);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/EntityEnderCrystal.java b/src/main/java/net/minecraft/server/EntityEnderCrystal.java
|
|
index faa82f6524..f726a3585f 100644
|
|
--- a/src/main/java/net/minecraft/server/EntityEnderCrystal.java
|
|
+++ b/src/main/java/net/minecraft/server/EntityEnderCrystal.java
|
|
@@ -13,6 +13,12 @@ public class EntityEnderCrystal extends Entity {
|
|
private static final DataWatcherObject<Optional<BlockPosition>> c = DataWatcher.a(EntityEnderCrystal.class, DataWatcherRegistry.m);
|
|
private static final DataWatcherObject<Boolean> d = DataWatcher.a(EntityEnderCrystal.class, DataWatcherRegistry.i);
|
|
public int b;
|
|
+ // Purpur start
|
|
+ private EntityPhantom targetPhantom;
|
|
+ private int phantomBeamTicks = 0;
|
|
+ private int phantomDamageCooldown = 0;
|
|
+ private int idleCooldown = 0;
|
|
+ // Purpur end
|
|
|
|
public EntityEnderCrystal(EntityTypes<? extends EntityEnderCrystal> entitytypes, World world) {
|
|
super(entitytypes, world);
|
|
@@ -51,7 +57,50 @@ public class EntityEnderCrystal extends Entity {
|
|
}
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ if (world.purpurConfig.phantomAttackedByCrystalRadius <= 0 || --idleCooldown > 0) {
|
|
+ return; // on cooldown
|
|
+ }
|
|
+
|
|
+ if (targetPhantom == null) {
|
|
+ for (EntityPhantom phantom : world.getEntitiesInAABB(EntityPhantom.class, getBoundingBox().grow(world.purpurConfig.phantomAttackedByCrystalRadius))) {
|
|
+ if (phantom.hasLineOfSight(this)) {
|
|
+ attackPhantom(phantom);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ setBeamTarget(new BlockPosition(targetPhantom).add(0, -2, 0));
|
|
+ if (--phantomBeamTicks > 0 && targetPhantom.isAlive()) {
|
|
+ phantomDamageCooldown--;
|
|
+ if (targetPhantom.hasLineOfSight(this)) {
|
|
+ if (phantomDamageCooldown <= 0) {
|
|
+ phantomDamageCooldown = 20;
|
|
+ targetPhantom.damageEntity(DamageSource.indirectMagic(this, this), world.purpurConfig.phantomAttackedByCrystalDamage);
|
|
+ }
|
|
+ } else {
|
|
+ forgetPhantom(); // no longer in sight
|
|
+ }
|
|
+ } else {
|
|
+ forgetPhantom(); // attacked long enough
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void attackPhantom(EntityPhantom phantom) {
|
|
+ phantomDamageCooldown = 0;
|
|
+ phantomBeamTicks = 60;
|
|
+ targetPhantom = phantom;
|
|
+ }
|
|
+
|
|
+ private void forgetPhantom() {
|
|
+ targetPhantom = null;
|
|
+ setBeamTarget(null);
|
|
+ phantomBeamTicks = 0;
|
|
+ phantomDamageCooldown = 0;
|
|
+ idleCooldown = 60;
|
|
}
|
|
+ // Purpur end
|
|
|
|
@Override
|
|
protected void saveData(NBTTagCompound nbttagcompound) {
|
|
diff --git a/src/main/java/net/minecraft/server/EntityPhantom.java b/src/main/java/net/minecraft/server/EntityPhantom.java
|
|
index 550f80bfdb..b3616185d2 100644
|
|
--- a/src/main/java/net/minecraft/server/EntityPhantom.java
|
|
+++ b/src/main/java/net/minecraft/server/EntityPhantom.java
|
|
@@ -9,9 +9,10 @@ import javax.annotation.Nullable;
|
|
public class EntityPhantom extends EntityFlying implements IMonster {
|
|
|
|
private static final DataWatcherObject<Integer> b = DataWatcher.a(EntityPhantom.class, DataWatcherRegistry.b);
|
|
- private Vec3D c;
|
|
- private BlockPosition d;
|
|
- private EntityPhantom.AttackPhase bo;
|
|
+ private Vec3D c; public void setHomeOffset(Vec3D offset) { this.c = offset; } public Vec3D getHomeOffset() { return this.c; } // Purpur - OBFHELPER
|
|
+ private BlockPosition d; public void setHome(BlockPosition home) { this.d = home; } public BlockPosition getHome() { return this.d; } // Purpur - OBFHELPER
|
|
+ private EntityPhantom.AttackPhase bo; public AttackPhase getAttackPhase() { return this.bo; } // Purpur - OBFHELPER
|
|
+ private Vec3D crystalPosition; // Purpur
|
|
|
|
public EntityPhantom(EntityTypes<? extends EntityPhantom> entitytypes, World world) {
|
|
super(entitytypes, world);
|
|
@@ -30,11 +31,37 @@ public class EntityPhantom extends EntityFlying implements IMonster {
|
|
|
|
@Override
|
|
protected void initPathfinder() {
|
|
- this.goalSelector.a(1, new EntityPhantom.c());
|
|
- this.goalSelector.a(2, new EntityPhantom.i());
|
|
- this.goalSelector.a(3, new EntityPhantom.e());
|
|
- this.targetSelector.a(1, new EntityPhantom.b());
|
|
+ // Purpur start
|
|
+ if (world.purpurConfig.phantomOrbitCrystalRadius > 0) {
|
|
+ this.goalSelector.a(1, new FindCrystalGoal(this));
|
|
+ this.goalSelector.a(2, new OrbitCrystalGoal(this));
|
|
+ }
|
|
+ this.goalSelector.a(3, new EntityPhantom.c()); // PickAttackGoal
|
|
+ this.goalSelector.a(4, new EntityPhantom.i()); // SweepAttackGoal
|
|
+ this.goalSelector.a(5, new EntityPhantom.e()); // OrbitPointGoal
|
|
+ this.targetSelector.a(1, new EntityPhantom.b()); // AttackPlayer Goal
|
|
+ // Purpur end
|
|
+ }
|
|
+
|
|
+ // Purpur start
|
|
+ @Override
|
|
+ protected LootTableInfo.Builder a(boolean wasRecentlyHit, DamageSource damagesource) { // dropLoot
|
|
+ boolean dropped = false;
|
|
+ if (killer == null && damagesource.getEntity() instanceof EntityEnderCrystal) {
|
|
+ if (random.nextInt(5) < 1) { // 1 out of 5 chance (20%)
|
|
+ dropped = dropItem(new ItemStack(Items.PHANTOM_MEMBRANE)) != null;
|
|
+ }
|
|
+ }
|
|
+ if (!dropped) {
|
|
+ return super.a(wasRecentlyHit, damagesource); // dropLoot
|
|
+ }
|
|
+ return new LootTableInfo.Builder((WorldServer) world);
|
|
+ }
|
|
+
|
|
+ public boolean isCirclingCrystal() {
|
|
+ return crystalPosition != null;
|
|
}
|
|
+ // Purpur end
|
|
|
|
@Override
|
|
protected void initDatawatcher() {
|
|
@@ -198,6 +225,136 @@ public class EntityPhantom extends EntityFlying implements IMonster {
|
|
}
|
|
// Paper end
|
|
|
|
+ // Purpur start
|
|
+ class FindCrystalGoal extends PathfinderGoal {
|
|
+ private final EntityPhantom phantom;
|
|
+ private EntityEnderCrystal crystal;
|
|
+ private java.util.Comparator<EntityEnderCrystal> comparator;
|
|
+
|
|
+ FindCrystalGoal(EntityPhantom phantom) {
|
|
+ this.phantom = phantom;
|
|
+ comparator = java.util.Comparator.comparingDouble(phantom::h);
|
|
+ this.a(EnumSet.of(PathfinderGoal.Type.LOOK));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean a() { // shouldExecute
|
|
+ double range = maxTargetRange();
|
|
+ List<EntityEnderCrystal> crystals = world.getEntitiesInAABB(EntityEnderCrystal.class, phantom.getBoundingBox().grow(range));
|
|
+ if (crystals.isEmpty()) {
|
|
+ return false;
|
|
+ }
|
|
+ crystals.sort(comparator);
|
|
+ crystal = crystals.get(0);
|
|
+ if (phantom.getDistanceSq(crystal) > range * range) {
|
|
+ crystal = null;
|
|
+ return false;
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean b() { // shouldContinueExecuting
|
|
+ if (crystal == null || !crystal.isAlive()) {
|
|
+ return false;
|
|
+ }
|
|
+ double range = maxTargetRange();
|
|
+ return phantom.getDistanceSq(crystal) <= (range * range) * 2;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void c() { // startExecuting
|
|
+ phantom.crystalPosition = new Vec3D(crystal.locX(), crystal.locY() + (phantom.getRandom().nextInt(10) + 10), crystal.locZ());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void d() { // resetTask
|
|
+ crystal = null;
|
|
+ phantom.crystalPosition = null;
|
|
+ super.d();
|
|
+ }
|
|
+
|
|
+ private double maxTargetRange() {
|
|
+ return phantom.world.purpurConfig.phantomOrbitCrystalRadius;
|
|
+ }
|
|
+
|
|
+ class DistanceComparator implements java.util.Comparator<Entity> {
|
|
+ private final Entity entity;
|
|
+
|
|
+ public DistanceComparator(Entity entity) {
|
|
+ this.entity = entity;
|
|
+ }
|
|
+
|
|
+ public int compare(Entity entity1, Entity entity2) {
|
|
+ return Double.compare(entity.getDistanceSq(entity1), entity.getDistanceSq(entity2));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ class OrbitCrystalGoal extends PathfinderGoal {
|
|
+ private final EntityPhantom phantom;
|
|
+ private float offset;
|
|
+ private float radius;
|
|
+ private float verticalChange;
|
|
+ private float direction;
|
|
+
|
|
+ OrbitCrystalGoal(EntityPhantom phantom) {
|
|
+ this.phantom = phantom;
|
|
+ this.a(EnumSet.of(PathfinderGoal.Type.MOVE));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean a() { // shouldExecute
|
|
+ return phantom.isCirclingCrystal();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void c() { // startExecuting
|
|
+ this.radius = 5.0F + phantom.random.nextFloat() * 10.0F;
|
|
+ this.verticalChange = -4.0F + phantom.random.nextFloat() * 9.0F;
|
|
+ this.direction = phantom.random.nextBoolean() ? 1.0F : -1.0F;
|
|
+ updateOffset();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void e() { // tick
|
|
+ if (phantom.random.nextInt(350) == 0) {
|
|
+ this.verticalChange = -4.0F + phantom.random.nextFloat() * 9.0F;
|
|
+ }
|
|
+ if (phantom.random.nextInt(250) == 0) {
|
|
+ ++this.radius;
|
|
+ if (this.radius > 15.0F) {
|
|
+ this.radius = 5.0F;
|
|
+ this.direction = -this.direction;
|
|
+ }
|
|
+ }
|
|
+ if (phantom.random.nextInt(450) == 0) {
|
|
+ this.offset = phantom.random.nextFloat() * 2.0F * 3.1415927F;
|
|
+ updateOffset();
|
|
+ }
|
|
+ if (phantom.getHomeOffset().c(phantom.locX(), phantom.locY(), phantom.locZ()) < 4.0D) {
|
|
+ updateOffset();
|
|
+ }
|
|
+ if (phantom.getHomeOffset().y < phantom.locY() && !phantom.world.isEmpty((new BlockPosition(phantom)).down(1))) {
|
|
+ this.verticalChange = Math.max(1.0F, this.verticalChange);
|
|
+ updateOffset();
|
|
+ }
|
|
+ if (phantom.getHomeOffset().y > phantom.locY() && !phantom.world.isEmpty((new BlockPosition(phantom)).up(1))) {
|
|
+ this.verticalChange = Math.min(-1.0F, this.verticalChange);
|
|
+ updateOffset();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void updateOffset() {
|
|
+ this.offset += this.direction * 15.0F * 0.017453292F;
|
|
+ phantom.setHomeOffset(phantom.crystalPosition.add(
|
|
+ this.radius * MathHelper.cos(this.offset),
|
|
+ -4.0F + this.verticalChange,
|
|
+ this.radius * MathHelper.sin(this.offset)));
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
class b extends PathfinderGoal {
|
|
|
|
private final PathfinderTargetCondition b;
|
|
@@ -210,6 +367,7 @@ public class EntityPhantom extends EntityFlying implements IMonster {
|
|
|
|
@Override
|
|
public boolean a() {
|
|
+ if (isCirclingCrystal()) return false; // Purpur - pathfinder does not have a flag
|
|
if (this.c > 0) {
|
|
--this.c;
|
|
return false;
|
|
@@ -238,6 +396,7 @@ public class EntityPhantom extends EntityFlying implements IMonster {
|
|
|
|
@Override
|
|
public boolean b() {
|
|
+ if (isCirclingCrystal()) return false; // Purpur - pathfinder does not have a flag
|
|
EntityLiving entityliving = EntityPhantom.this.getGoalTarget();
|
|
|
|
return entityliving != null ? EntityPhantom.this.a(entityliving, PathfinderTargetCondition.a) : false;
|
|
@@ -252,6 +411,7 @@ public class EntityPhantom extends EntityFlying implements IMonster {
|
|
|
|
@Override
|
|
public boolean a() {
|
|
+ if (isCirclingCrystal()) return false; // Purpur - pathfinder does not have a flag
|
|
EntityLiving entityliving = EntityPhantom.this.getGoalTarget();
|
|
|
|
return entityliving != null ? EntityPhantom.this.a(EntityPhantom.this.getGoalTarget(), PathfinderTargetCondition.a) : false;
|
|
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
|
|
index 3e067c832f..f2ca515c9b 100644
|
|
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
|
|
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
|
|
@@ -324,6 +324,15 @@ public class PurpurWorldConfig {
|
|
ironGolemCanSwim = getBoolean("mobs.iron_golem.can-swim", ironGolemCanSwim);
|
|
}
|
|
|
|
+ public double phantomAttackedByCrystalRadius = 0.0D;
|
|
+ public float phantomAttackedByCrystalDamage = 1.0F;
|
|
+ public double phantomOrbitCrystalRadius = 0.0D;
|
|
+ private void phantomSettings() {
|
|
+ phantomAttackedByCrystalRadius = getDouble("mobs.phantom.attacked-by-crystal-range", phantomAttackedByCrystalRadius);
|
|
+ phantomAttackedByCrystalDamage = (float) getDouble("mobs.phantom.attacked-by-crystal-damage", phantomAttackedByCrystalDamage);
|
|
+ phantomOrbitCrystalRadius = getDouble("mobs.phantom.orbit-crystal-radius", phantomOrbitCrystalRadius);
|
|
+ }
|
|
+
|
|
public boolean pigGiveSaddleBack = false;
|
|
private void pigSettings() {
|
|
pigGiveSaddleBack = getBoolean("mobs.pig.give-saddle-back", pigGiveSaddleBack);
|