mirror of
https://github.com/PurpurMC/Purpur.git
synced 2026-02-22 10:57:43 +01:00
Upstream has released updates that appears to apply and compile correctly Paper Changes: cb15cfa4 Improve Async Login so pending connections dont get exposed f275e9cb Optimize Hoppers - Major Boost - Got2GoFast! 0106485c Improvements to watchdog changes 65934b1f Fix build for last commit. 5am commits are great 3f436029 Don't process watchdog until server has fully started and ticked. 938bd972 Don't fire BlockFade on worldgen threads - Fixes #3208 509a828e Fix loading spawn chunks when async chunks is off 8a91bfd2 Improvements to async login bf698865 Revert "Re-track players that dismount from other players" 82b98418 Fix some issues with async login as well another source of sync loads aa241d2b Allow multiple callbacks to schedule for Callback Executor a2064a41 Add PlayerAttackEntityCooldownResetEvent This event is called when processing a player's attack on an entity right before their attack strength cd is reset, there are no existing events that fire within this period of time so it was impossible to capture the players attack strength via API prior to this commit. f48d4299 Allow sleeping players to float eeb2f67d Fix Bed respawn deviating too far from vanilla (#3195) 68a7b9fe Move player to spawn point if spawn in unloaded world
391 lines
18 KiB
Diff
391 lines
18 KiB
Diff
From 6e163b10eb444f0fc0573636727586bf44298e98 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
|
|
|
|
---
|
|
.../net/minecraft/server/DamageSource.java | 1 +
|
|
.../java/net/minecraft/server/Entity.java | 8 +-
|
|
.../minecraft/server/EntityEnderCrystal.java | 49 +++++
|
|
.../net/minecraft/server/EntityPhantom.java | 172 +++++++++++++++++-
|
|
.../net/minecraft/server/IEntityAccess.java | 1 +
|
|
.../net/pl3x/purpur/PurpurWorldConfig.java | 6 +
|
|
6 files changed, 226 insertions(+), 11 deletions(-)
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/DamageSource.java b/src/main/java/net/minecraft/server/DamageSource.java
|
|
index f7344d3a..f6c0165f 100644
|
|
--- a/src/main/java/net/minecraft/server/DamageSource.java
|
|
+++ b/src/main/java/net/minecraft/server/DamageSource.java
|
|
@@ -82,6 +82,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 585ebc37..217ab1be 100644
|
|
--- a/src/main/java/net/minecraft/server/Entity.java
|
|
+++ b/src/main/java/net/minecraft/server/Entity.java
|
|
@@ -1427,6 +1427,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.c(entity.getPositionVector());
|
|
}
|
|
@@ -1956,14 +1957,13 @@ 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);
|
|
}
|
|
|
|
@Nullable public final EntityItem dropItem(ItemStack itemstack, float offset) { return this.a(itemstack, offset); } // Paper - OBFHELPER
|
|
- @Nullable
|
|
- public EntityItem a(ItemStack itemstack, float f) {
|
|
+ @Nullable public EntityItem a(ItemStack itemstack, float f) {
|
|
if (itemstack.isEmpty()) {
|
|
return null;
|
|
} else if (this.world.isClientSide) {
|
|
diff --git a/src/main/java/net/minecraft/server/EntityEnderCrystal.java b/src/main/java/net/minecraft/server/EntityEnderCrystal.java
|
|
index a57d0089..02952c3a 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.getEntitiesByClass(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 b(NBTTagCompound nbttagcompound) {
|
|
diff --git a/src/main/java/net/minecraft/server/EntityPhantom.java b/src/main/java/net/minecraft/server/EntityPhantom.java
|
|
index 9d331f9a..77b69cd3 100644
|
|
--- a/src/main/java/net/minecraft/server/EntityPhantom.java
|
|
+++ b/src/main/java/net/minecraft/server/EntityPhantom.java
|
|
@@ -8,9 +8,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 bw;
|
|
+ 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 bw; public AttackPhase getAttackPhase() { return this.bw; } // Purpur - OBFHELPER
|
|
+ private BlockPosition crystalPosition; // Purpur
|
|
|
|
public EntityPhantom(EntityTypes<? extends EntityPhantom> entitytypes, World world) {
|
|
super(entitytypes, world);
|
|
@@ -63,12 +64,18 @@ public class EntityPhantom extends EntityFlying implements IMonster {
|
|
|
|
@Override
|
|
protected void initPathfinder() {
|
|
+ // Purpur start
|
|
this.goalSelector.a(0, new net.pl3x.purpur.pathfinder.PathfinderGoalHasRider(this)); // Purpur
|
|
- this.goalSelector.a(1, new EntityPhantom.c());
|
|
- this.goalSelector.a(2, new EntityPhantom.i());
|
|
- this.goalSelector.a(3, new EntityPhantom.e());
|
|
+ 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(0, new net.pl3x.purpur.pathfinder.PathfinderGoalHasRider(this)); // Purpur
|
|
- this.targetSelector.a(1, new EntityPhantom.b());
|
|
+ this.targetSelector.a(1, new EntityPhantom.b()); // AttackPlayerGoal
|
|
+ // Purpur end
|
|
}
|
|
|
|
@Override
|
|
@@ -158,6 +165,24 @@ public class EntityPhantom extends EntityFlying implements IMonster {
|
|
}
|
|
|
|
// 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;
|
|
+ }
|
|
+
|
|
@Override
|
|
public boolean onSpacebar() {
|
|
if (hasRider() && getRider().getBukkitEntity().hasPermission("allow.special.phantom")) {
|
|
@@ -266,6 +291,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.getEntitiesByClass(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 BlockPosition(crystal).add(0, phantom.getRandom().nextInt(10) + 10, 0);
|
|
+ }
|
|
+
|
|
+ @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(new Vec3D(phantom.crystalPosition).add(
|
|
+ (double) (this.radius * MathHelper.cos(this.offset)),
|
|
+ (double) (-4.0F + this.verticalChange),
|
|
+ (double) (this.radius * MathHelper.sin(this.offset))));
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
class b extends PathfinderGoal {
|
|
|
|
private final PathfinderTargetCondition b;
|
|
@@ -279,6 +434,7 @@ public class EntityPhantom extends EntityFlying implements IMonster {
|
|
@Override
|
|
public boolean a() {
|
|
if (getRider() != null) return false; // Purpur - pathfinder does not have a flag
|
|
+ if (isCirclingCrystal()) return false; // Purpur - pathfinder does not have a flag
|
|
if (this.c > 0) {
|
|
--this.c;
|
|
return false;
|
|
@@ -310,6 +466,7 @@ public class EntityPhantom extends EntityFlying implements IMonster {
|
|
@Override
|
|
public boolean b() {
|
|
if (getRider() != null) return false; // Purpur - pathfinder does not have a flag
|
|
+ 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;
|
|
@@ -325,6 +482,7 @@ public class EntityPhantom extends EntityFlying implements IMonster {
|
|
@Override
|
|
public boolean a() {
|
|
if (getRider() != null) return false; // Purpur - pathfinder does not have a flag
|
|
+ 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/minecraft/server/IEntityAccess.java b/src/main/java/net/minecraft/server/IEntityAccess.java
|
|
index 5135308f..89961900 100644
|
|
--- a/src/main/java/net/minecraft/server/IEntityAccess.java
|
|
+++ b/src/main/java/net/minecraft/server/IEntityAccess.java
|
|
@@ -34,6 +34,7 @@ public interface IEntityAccess {
|
|
});
|
|
}
|
|
|
|
+ default <T extends Entity> List<T> getEntitiesByClass(Class<? extends T> oclass, AxisAlignedBB axisalignedbb) { return a(oclass, axisalignedbb); } // Purpur - OBFHELPER
|
|
default <T extends Entity> List<T> a(Class<? extends T> oclass, AxisAlignedBB axisalignedbb) {
|
|
return this.a(oclass, axisalignedbb, IEntitySelector.f);
|
|
}
|
|
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
|
|
index 12cd8196..e341c492 100644
|
|
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
|
|
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
|
|
@@ -404,6 +404,9 @@ public class PurpurWorldConfig {
|
|
public int phantomFlameFireTime = 8;
|
|
public boolean phantomIgnoreCreative = false;
|
|
public boolean phantomOnlyAttackInsomniacs = false;
|
|
+ public double phantomAttackedByCrystalRadius = 0.0D;
|
|
+ public float phantomAttackedByCrystalDamage = 1.0F;
|
|
+ public double phantomOrbitCrystalRadius = 0.0D;
|
|
private void phantomSettings() {
|
|
phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable);
|
|
phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater);
|
|
@@ -413,6 +416,9 @@ public class PurpurWorldConfig {
|
|
phantomFlameFireTime = getInt("mobs.phantom.flames.fire-time", phantomFlameFireTime);
|
|
phantomIgnoreCreative = getBoolean("mobs.phantom.do-not-spawn-on-creative-players", phantomIgnoreCreative);
|
|
phantomOnlyAttackInsomniacs = getBoolean("mobs.phantom.only-attack-insomniacs", phantomOnlyAttackInsomniacs);
|
|
+ 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 pigRidable = false;
|
|
--
|
|
2.24.0
|
|
|