mirror of
https://github.com/PurpurMC/Purpur.git
synced 2026-02-22 19:07:44 +01:00
Upstream has released updates that appear to apply and compile correctly Paper Changes: 05af2837c [CI-SKIP] Improved the annotation test output 586966949 abstract custom set tags, add entity tags c7667378e Added PlayerLoomPatternSelectEvent 00972e80d Reimplement GS4QueryEvent 544c5c278 Re-add coral block tags (#4987) 7d56c8deb Added PlayerLecternPageChangeEvent c7cdf255b Add BlockFailedDispenseEvent c8a8d6fbe Added world settings for mobs picking up loot 91eda5bd3 Added ServerResourcesReloadedEvent be81b4f5c Add a Enchantable MaterialTag 975d18703 Add doors to material tags d075e748e colorful itemdump f3ba3dee0 Added WorldGameRuleChangeEvent 086d20118 Guardian beam workaround b63c890ec Support spawning item stacks d7d74c552 added height config for bamboo 7878e3bc2 Use setAmount for Recipe Amount 50e70697b Add EntityLoadCrossbowEvent f344e092c Add Anti-Xray bypass permission 9fd31e675 fix for nerfed slime mobs splitting 4a7962cd1 Zombie API - breaking doors 5650a41f5 Fix interact event not being called in adventure 2c9ed4335 Add PlayerFlowerPotManipulateEvent 1f32290b6 [Auto] Updated Upstream (CraftBukkit) d87694a20 Redact Velocity forwarding secret properly (#4980) 24a0b0206 [Auto] Updated Upstream (CraftBukkit) 7681042ef [Auto] Updated Upstream (Bukkit/CraftBukkit) 7dea3dba6 [Auto] Updated Upstream (CraftBukkit) 4b3792920 JavaDoc fixes f13b4727e Allow disabling mob spawner spawn egg transformation 525b50737 Cache burn durations 2c37d1077 Optimized tick ready check b4000b01a Add API to get the Material of Boats and Minecarts f1317386d Fix sign lazy initialisation 9f61759d9 Updated Upstream (CraftBukkit/Spigot) (#4972) aaff430b6 [CI-SKIP] Use GitHub Actions for build status 9f4055d99 Fix harming potion dupe 7bfb781ff Additional Block Material API's 0eaffd008 Micro Optimize DataBits Tuinity Changes: 9e5cabb6e Port starlight changes
343 lines
15 KiB
Diff
343 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 6fe5678cffc2487fe00c953d772f764bb37a4b11..bd0267ee4b3782f6d1ec39cba7966ba4f62f1adf 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 308cb9cfb418e63f17f8f39c3db94f93d874763f..d542cd8014a929b421e631075f1ee14423e9b66a 100644
|
|
--- a/src/main/java/net/minecraft/server/Entity.java
|
|
+++ b/src/main/java/net/minecraft/server/Entity.java
|
|
@@ -2146,8 +2146,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 362ca695d88a7c788421cc557b8110b954d8153a..1942fae27051af79b6eb1d790a219da100bf889e 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 3a70900c73e3a6c4f40cf74406534f4bfd3eb67b..dfce36368da9bdd9285c490a802f7a0cc4a339f6 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.getDistanceSquared(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.getDistanceSquared(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.getDistanceSquared(entity1), entity.getDistanceSquared(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 b3deaaea159546509fc7cff2d843455461520dfa..74aee0687cb8aa7e4b7efbf34d6374a516d873c0 100644
|
|
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
|
|
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
|
|
@@ -333,6 +333,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);
|