diff --git a/src/launch/java/baritone/launch/mixins/MixinEntity.java b/src/launch/java/baritone/launch/mixins/MixinEntity.java new file mode 100644 index 000000000..a611507b8 --- /dev/null +++ b/src/launch/java/baritone/launch/mixins/MixinEntity.java @@ -0,0 +1,37 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.launch.mixins; + +import net.minecraft.entity.Entity; +import net.minecraft.network.datasync.EntityDataManager; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +/** + * @author Brady + */ +@Mixin(Entity.class) +public abstract class MixinEntity { + + @Shadow + public World world; + + @Shadow + protected EntityDataManager dataManager; +} diff --git a/src/launch/java/baritone/launch/mixins/MixinEntityFireworkRocket.java b/src/launch/java/baritone/launch/mixins/MixinEntityFireworkRocket.java index 274e979a0..559ae0d54 100644 --- a/src/launch/java/baritone/launch/mixins/MixinEntityFireworkRocket.java +++ b/src/launch/java/baritone/launch/mixins/MixinEntityFireworkRocket.java @@ -18,18 +18,35 @@ package baritone.launch.mixins; import baritone.utils.accessor.IEntityFireworkRocket; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityFireworkRocket; +import net.minecraft.network.datasync.DataParameter; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @Mixin(EntityFireworkRocket.class) -public abstract class MixinEntityFireworkRocket implements IEntityFireworkRocket { +public abstract class MixinEntityFireworkRocket extends MixinEntity implements IEntityFireworkRocket { + + @Shadow + @Final + private static DataParameter BOOSTED_ENTITY_ID; + @Shadow private EntityLivingBase boostedEntity; + @Shadow + public abstract boolean isAttachedToEntity(); + @Override public EntityLivingBase getBoostedEntity() { - return boostedEntity; + if (this.isAttachedToEntity() && this.boostedEntity == null) { + final Entity entity = this.world.getEntityByID(this.dataManager.get(BOOSTED_ENTITY_ID)); + if (entity instanceof EntityLivingBase) { + this.boostedEntity = (EntityLivingBase) entity; + } + } + return this.boostedEntity; } } diff --git a/src/launch/resources/mixins.baritone.json b/src/launch/resources/mixins.baritone.json index 5c221de58..cbade3329 100644 --- a/src/launch/resources/mixins.baritone.json +++ b/src/launch/resources/mixins.baritone.json @@ -16,6 +16,7 @@ "MixinChunkProviderServer", "MixinChunkRenderContainer", "MixinChunkRenderWorker", + "MixinEntity", "MixinEntityFireworkRocket", "MixinEntityLivingBase", "MixinEntityPlayerSP", diff --git a/src/main/java/baritone/behavior/ElytraBehavior.java b/src/main/java/baritone/behavior/ElytraBehavior.java index 2ceea192a..922d824de 100644 --- a/src/main/java/baritone/behavior/ElytraBehavior.java +++ b/src/main/java/baritone/behavior/ElytraBehavior.java @@ -462,7 +462,7 @@ public final class ElytraBehavior extends Behavior implements IElytraBehavior, H this.tickUseFireworks( solution.context.start, solution.goingTo, - solution.context.isBoosted, + solution.context.boost.isBoosted(), solution.forceUseFirework ); } @@ -484,15 +484,14 @@ public final class ElytraBehavior extends Behavior implements IElytraBehavior, H final NetherPath path = context.path; final int playerNear = context.playerNear; final Vec3d start = context.start; - final boolean isBoosted = context.isBoosted; final boolean isInLava = ctx.player().isInLava(); Solution solution = null; for (int relaxation = 0; relaxation < 3; relaxation++) { // try for a strict solution first, then relax more and more (if we're in a corner or near some blocks, it will have to relax its constraints a bit) - int[] heights = isBoosted ? new int[]{20, 10, 5, 0} : new int[]{0}; // attempt to gain height, if we can, so as not to waste the boost + int[] heights = context.boost.isBoosted() ? new int[]{20, 10, 5, 0} : new int[]{0}; // attempt to gain height, if we can, so as not to waste the boost float[] interps = new float[] {1.0f, 0.75f, 0.5f, 0.25f}; - int steps = relaxation < 2 ? isBoosted ? 5 : Baritone.settings().elytraSimulationTicks.value : 3; + int steps = relaxation < 2 ? context.boost.isBoosted() ? 5 : Baritone.settings().elytraSimulationTicks.value : 3; int lookahead = relaxation == 0 ? 2 : 3; // ideally this would be expressed as a distance in blocks, rather than a number of voxel steps //int minStep = Math.max(0, playerNear - relaxation); int minStep = playerNear; @@ -590,14 +589,17 @@ public final class ElytraBehavior extends Behavior implements IElytraBehavior, H public final NetherPath path; public final int playerNear; public final Vec3d start; - public final boolean isBoosted; + public final FireworkBoost boost; public final IAimProcessor aimProcessor; public SolverContext(boolean async) { this.path = ElytraBehavior.this.pathManager.getPath(); this.playerNear = ElytraBehavior.this.pathManager.getNear(); this.start = ElytraBehavior.this.ctx.playerFeetAsVec(); - this.isBoosted = ElytraBehavior.this.getAttachedFirework().isPresent(); + this.boost = new FireworkBoost( + ElytraBehavior.this.getAttachedFirework().orElse(null), + ElytraBehavior.this.minimumBoostTicks + ); ITickableAimProcessor aim = ElytraBehavior.this.baritone.getLookBehavior().getAimProcessor().fork(); if (async) { @@ -620,7 +622,49 @@ public final class ElytraBehavior extends Behavior implements IElytraBehavior, H return this.path == other.path // Contents aren't modified, just compare by reference && this.playerNear == other.playerNear && Objects.equals(this.start, other.start) - && this.isBoosted == other.isBoosted; + && Objects.equals(this.boost, other.boost); + } + } + + private static final class FireworkBoost { + + private final EntityFireworkRocket firework; + private final int minimumBoostTicks; + private final int maximumBoostTicks; + + public FireworkBoost(final EntityFireworkRocket firework, final int minimumBoostTicks) { + this.firework = firework; + + // this.lifetime = 10 * i + this.rand.nextInt(6) + this.rand.nextInt(7); + this.minimumBoostTicks = minimumBoostTicks; + this.maximumBoostTicks = minimumBoostTicks + 11; + } + + public boolean isBoosted() { + return this.firework != null; + } + + public int getGuaranteedBoostTicks() { + return this.isBoosted() ? Math.max(0, this.minimumBoostTicks - this.firework.ticksExisted) : 0; + } + + public int getMaximumBoostTicks() { + return this.isBoosted() ? Math.max(0, this.maximumBoostTicks - this.firework.ticksExisted) : 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || o.getClass() != FireworkBoost.class) { + return false; + } + + FireworkBoost other = (FireworkBoost) o; + return Objects.equals(this.firework, other.firework) + && this.minimumBoostTicks == other.minimumBoostTicks + && this.maximumBoostTicks == other.maximumBoostTicks; } } @@ -743,7 +787,7 @@ public final class ElytraBehavior extends Behavior implements IElytraBehavior, H } private Pair solvePitch(SolverContext context, Vec3d goalDelta, int steps, int relaxation, boolean ignoreLava) { - final Float pitch = this.solvePitch(context, goalDelta, steps, relaxation == 2, context.isBoosted, ignoreLava); + final Float pitch = this.solvePitch(context, goalDelta, steps, relaxation == 2, context.boost.isBoosted(), ignoreLava); if (pitch != null) { return new Pair<>(pitch, false); } @@ -827,13 +871,13 @@ public final class ElytraBehavior extends Behavior implements IElytraBehavior, H return bestPitch; } - private static Vec3d step(final Vec3d motion, final Rotation rotation, final boolean firework) { + private static Vec3d step(final Vec3d motion, final Rotation rotation, final boolean applyFireworkBoost) { double motionX = motion.x; double motionY = motion.y; double motionZ = motion.z; final Vec3d lookDirection = RotationUtils.calcLookDirectionFromRotation(rotation); - if (firework) { + if (applyFireworkBoost) { // See EntityFireworkRocket motionX += lookDirection.x * 0.1 + (lookDirection.x * 1.5 - motionX) * 0.5; motionY += lookDirection.y * 0.1 + (lookDirection.y * 1.5 - motionY) * 0.5; diff --git a/src/main/java/baritone/utils/accessor/IEntityFireworkRocket.java b/src/main/java/baritone/utils/accessor/IEntityFireworkRocket.java index 86c96acd9..1b22d1ffd 100644 --- a/src/main/java/baritone/utils/accessor/IEntityFireworkRocket.java +++ b/src/main/java/baritone/utils/accessor/IEntityFireworkRocket.java @@ -20,5 +20,6 @@ package baritone.utils.accessor; import net.minecraft.entity.EntityLivingBase; public interface IEntityFireworkRocket { + EntityLivingBase getBoostedEntity(); }