diff --git a/build.gradle b/build.gradle index 16ad660..14514a4 100644 --- a/build.gradle +++ b/build.gradle @@ -168,6 +168,10 @@ dependencies { compileOnly fg.deobf("curse.maven:touhou-little-maid-355044:6440955") runtimeOnly fg.deobf("curse.maven:touhou-little-maid-355044:6440955") runtimeOnly fg.deobf("curse.maven:maid-storage-manager-1210244:6455832") + compileOnly(annotationProcessor("io.github.llamalad7:mixinextras-common:0.4.1")) + implementation(jarJar("io.github.llamalad7:mixinextras-forge:0.4.1")) { + jarJar.ranged(it, "[0.4.1,)") + } } // This block of code expands all declared replace properties in the specified resource targets. diff --git a/src/main/java/studio/fantasyit/maid_useful_task/UsefulTaskExtension.java b/src/main/java/studio/fantasyit/maid_useful_task/UsefulTaskExtension.java index c8bd403..1873fbd 100644 --- a/src/main/java/studio/fantasyit/maid_useful_task/UsefulTaskExtension.java +++ b/src/main/java/studio/fantasyit/maid_useful_task/UsefulTaskExtension.java @@ -3,10 +3,13 @@ package studio.fantasyit.maid_useful_task; import com.github.tartaricacid.touhoulittlemaid.api.ILittleMaid; import com.github.tartaricacid.touhoulittlemaid.api.LittleMaidExtension; import com.github.tartaricacid.touhoulittlemaid.api.entity.ai.IExtraMaidBrain; +import com.github.tartaricacid.touhoulittlemaid.client.animation.HardcodedAnimationManger; import com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.ExtraMaidBrainManager; import com.github.tartaricacid.touhoulittlemaid.entity.task.TaskManager; import net.minecraft.world.entity.ai.memory.MemoryModuleType; +import studio.fantasyit.maid_useful_task.animation.FlyAnimation; import studio.fantasyit.maid_useful_task.registry.MemoryModuleRegistry; +import studio.fantasyit.maid_useful_task.task.MaidEndEyeTask; import studio.fantasyit.maid_useful_task.task.MaidTreeTask; import java.util.List; @@ -17,6 +20,7 @@ public class UsefulTaskExtension implements ILittleMaid { public void addMaidTask(TaskManager manager) { ILittleMaid.super.addMaidTask(manager); manager.add(new MaidTreeTask()); + manager.add(new MaidEndEyeTask()); } @Override @@ -29,9 +33,15 @@ public class UsefulTaskExtension implements ILittleMaid { MemoryModuleRegistry.PLACE_TARGET.get(), MemoryModuleRegistry.BLOCK_UP_TARGET.get(), MemoryModuleRegistry.BLOCK_VALIDATION.get(), - MemoryModuleRegistry.CURRENT_WORK.get() + MemoryModuleRegistry.CURRENT_WORK.get(), + MemoryModuleRegistry.COMMON_BLOCK_CACHE.get() ); } }); } + + @Override + public void addHardcodeAnimation(HardcodedAnimationManger manger) { + manger.addMaidAnimation(new FlyAnimation()); + } } diff --git a/src/main/java/studio/fantasyit/maid_useful_task/animation/FlyAnimation.java b/src/main/java/studio/fantasyit/maid_useful_task/animation/FlyAnimation.java new file mode 100644 index 0000000..f786cef --- /dev/null +++ b/src/main/java/studio/fantasyit/maid_useful_task/animation/FlyAnimation.java @@ -0,0 +1,32 @@ +package studio.fantasyit.maid_useful_task.animation; + +import com.github.tartaricacid.touhoulittlemaid.api.animation.ICustomAnimation; +import com.github.tartaricacid.touhoulittlemaid.api.animation.IModelRenderer; +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.geckolib3.geo.animated.AnimatedGeoModel; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.world.entity.Mob; + +import java.util.HashMap; + +public class FlyAnimation implements ICustomAnimation { + @Override + public void setupRotations(Mob entity, PoseStack poseStack, float ageInTicks, float rotationYaw, float partialTicks) { + ICustomAnimation.super.setupRotations(entity, poseStack, ageInTicks, rotationYaw, partialTicks); + } + + @Override + public void setRotationAngles(Mob entity, HashMap models, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) { + ICustomAnimation.super.setRotationAngles(entity, models, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch); + } + + @Override + public void setupGeckoRotations(Mob entity, PoseStack poseStack, float ageInTicks, float rotationYaw, float partialTicks) { + ICustomAnimation.super.setupGeckoRotations(entity, poseStack, ageInTicks, rotationYaw, partialTicks); + } + + @Override + public void setGeckoRotationAngles(Mob entity, AnimatedGeoModel model, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) { + ICustomAnimation.super.setGeckoRotationAngles(entity, model, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch); + } +} diff --git a/src/main/java/studio/fantasyit/maid_useful_task/behavior/EnderEyeMoveBehavior.java b/src/main/java/studio/fantasyit/maid_useful_task/behavior/EnderEyeMoveBehavior.java new file mode 100644 index 0000000..44c2520 --- /dev/null +++ b/src/main/java/studio/fantasyit/maid_useful_task/behavior/EnderEyeMoveBehavior.java @@ -0,0 +1,81 @@ +package studio.fantasyit.maid_useful_task.behavior; + +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitEntities; +import com.google.common.collect.ImmutableMap; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.StructureTags; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.behavior.Behavior; +import net.minecraft.world.entity.ai.memory.MemoryModuleType; +import net.minecraft.world.entity.ai.memory.MemoryStatus; +import net.minecraft.world.item.Items; +import net.minecraft.world.phys.Vec3; +import studio.fantasyit.maid_useful_task.util.MemoryUtil; + +public class EnderEyeMoveBehavior extends Behavior { + + public EnderEyeMoveBehavior() { + super(ImmutableMap.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT, InitEntities.TARGET_POS.get(), MemoryStatus.VALUE_ABSENT)); + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel p_22538_, EntityMaid maid) { + if (!maid.getMainHandItem().is(Items.ENDER_EYE)) return false; + if (maid.hasRestriction()) return false; + LivingEntity owner = maid.getOwner(); + return (owner != null && maid.distanceTo(owner) < 5); + } + + @Override + protected void start(ServerLevel serverlevel, EntityMaid maid, long p_22542_) { + BlockPos target = MemoryUtil.getCommonBlockCache(maid); + LivingEntity owner = maid.getOwner(); + if (owner == null) return; + if (target == null) { + BlockPos blockpos = serverlevel.findNearestMapStructure(StructureTags.EYE_OF_ENDER_LOCATED, maid.blockPosition(), 100, false); + if (blockpos != null) { + MemoryUtil.setCommonBlockCache(maid, blockpos); + target = blockpos; + } + } + if (target != null) { + if (maid.distanceToSqr(target.getCenter()) < 9) { + maid.getJumpControl().jump(); + } + + BlockPos finalTarget = target; + BlockPos ownerPos = owner.blockPosition(); + BlockPos maidPos = maid.blockPosition(); + if (finalTarget.distSqr(ownerPos) > 10 * 10) { + Vec3 dVec = target.getCenter().subtract(owner.position()); + dVec = dVec.normalize().scale(7); + BlockPos fTarget = maidPos.offset((int) dVec.x, (int) dVec.y, (int) dVec.z); + + for (int x = 0; x < 3; x = x <= 0 ? 1 - x : -x) { + for (int z = 0; z < 3; z = z <= 0 ? 1 - z : -z) { + int y = 0; + while (!serverlevel.getBlockState(fTarget.offset(x, y, z)).isAir()) y++; + while (!serverlevel.getBlockState(fTarget.offset(x, y, z)).isAir()) y--; + + if (fTarget.offset(x, y, z).distSqr(ownerPos) < 10 * 10) { + finalTarget = fTarget.offset(x, y, z); + } + } + } + } + if (finalTarget.distSqr(maidPos) < 10 * 10) { + double distanceToOwner = maidPos.distSqr(ownerPos); + double speed = 0.4; + if (distanceToOwner < 4 * 4) { + speed = 0.5; + } + if (distanceToOwner < 3 * 3) { + speed = 0.64; + } + MemoryUtil.setTarget(maid, finalTarget, (float) speed); + } + } + } +} diff --git a/src/main/java/studio/fantasyit/maid_useful_task/behavior/EnderEyeWaitBehavior.java b/src/main/java/studio/fantasyit/maid_useful_task/behavior/EnderEyeWaitBehavior.java new file mode 100644 index 0000000..0f2fe5c --- /dev/null +++ b/src/main/java/studio/fantasyit/maid_useful_task/behavior/EnderEyeWaitBehavior.java @@ -0,0 +1,39 @@ +package studio.fantasyit.maid_useful_task.behavior; + +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitEntities; +import com.google.common.collect.ImmutableMap; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.StructureTags; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.behavior.Behavior; +import net.minecraft.world.entity.ai.memory.MemoryModuleType; +import net.minecraft.world.entity.ai.memory.MemoryStatus; +import net.minecraft.world.item.Items; +import net.minecraft.world.phys.Vec3; +import studio.fantasyit.maid_useful_task.util.Conditions; +import studio.fantasyit.maid_useful_task.util.MemoryUtil; + +public class EnderEyeWaitBehavior extends Behavior { + + public EnderEyeWaitBehavior() { + super(ImmutableMap.of(InitEntities.TARGET_POS.get(), MemoryStatus.VALUE_PRESENT)); + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel p_22538_, EntityMaid maid) { + if (!maid.getMainHandItem().is(Items.ENDER_EYE)) return false; + if (maid.hasRestriction()) return false; + LivingEntity owner = maid.getOwner(); + if (owner != null && maid.distanceTo(owner) > 6) { + return true; + } + return Conditions.hasReachedValidTargetOrReset(maid, 4); + } + + @Override + protected void start(ServerLevel serverlevel, EntityMaid maid, long p_22542_) { + MemoryUtil.clearTarget(maid); + } +} diff --git a/src/main/java/studio/fantasyit/maid_useful_task/mixin/FollowMaidMixin.java b/src/main/java/studio/fantasyit/maid_useful_task/mixin/FollowMaidMixin.java new file mode 100644 index 0000000..0e87597 --- /dev/null +++ b/src/main/java/studio/fantasyit/maid_useful_task/mixin/FollowMaidMixin.java @@ -0,0 +1,49 @@ +package studio.fantasyit.maid_useful_task.mixin; + +import com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.task.MaidFollowOwnerTask; +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.llamalad7.mixinextras.sugar.Local; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.LivingEntity; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import studio.fantasyit.maid_useful_task.task.MaidEndEyeTask; + +@Mixin(MaidFollowOwnerTask.class) +abstract public class FollowMaidMixin { + @Shadow(remap = false) + @Final + private int stopDistance; + + @Inject(method = "Lcom/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidFollowOwnerTask;checkExtraStartConditions(Lnet/minecraft/server/level/ServerLevel;Lcom/github/tartaricacid/touhoulittlemaid/entity/passive/EntityMaid;)Z", at = @At("HEAD"),remap = false, cancellable = true) + public void checkExtraStartConditions(ServerLevel level, EntityMaid maid, CallbackInfoReturnable cir) { + if (maid.getTask().getUid().equals(MaidEndEyeTask.UID)) { + LivingEntity owner = maid.getOwner(); + if (owner != null && maid.distanceTo(owner) < 6) { + cir.setReturnValue(false); + } + } + } + + @ModifyVariable(method = "start(Lnet/minecraft/server/level/ServerLevel;Lcom/github/tartaricacid/touhoulittlemaid/entity/passive/EntityMaid;J)V", at = @At(value = "STORE"),remap = false) + public int start(int startDistance, @Local(argsOnly = true) EntityMaid maid) { + if (maid.getTask().getUid().equals(MaidEndEyeTask.UID)) { + return 10; + } + return startDistance; + } + + @ModifyArg(method = "start(Lnet/minecraft/server/level/ServerLevel;Lcom/github/tartaricacid/touhoulittlemaid/entity/passive/EntityMaid;J)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/ai/behavior/BehaviorUtils;setWalkAndLookTargetMemories(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/Entity;FI)V")) + public int maid_useful_task$stop_distance(int stopDistance, @Local(argsOnly = true) EntityMaid maid) { + if (maid.getTask().getUid().equals(MaidEndEyeTask.UID)) { + return 10; + } + return stopDistance; + } +} diff --git a/src/main/java/studio/fantasyit/maid_useful_task/registry/MemoryModuleRegistry.java b/src/main/java/studio/fantasyit/maid_useful_task/registry/MemoryModuleRegistry.java index b69a20e..d5d4071 100644 --- a/src/main/java/studio/fantasyit/maid_useful_task/registry/MemoryModuleRegistry.java +++ b/src/main/java/studio/fantasyit/maid_useful_task/registry/MemoryModuleRegistry.java @@ -23,6 +23,8 @@ public class MemoryModuleRegistry { = REGISTER.register("block_up", () -> new MemoryModuleType<>(Optional.of(BlockUpContext.CODEC))); public static final RegistryObject> BLOCK_VALIDATION = REGISTER.register("block_validation", () -> new MemoryModuleType<>(Optional.of(BlockValidationMemory.CODEC))); + public static final RegistryObject> COMMON_BLOCK_CACHE + = REGISTER.register("common_block_cache", () -> new MemoryModuleType<>(Optional.empty())); public static final RegistryObject> CURRENT_WORK = REGISTER.register("current_work", () -> new MemoryModuleType<>(Optional.empty())); public static void register(IEventBus eventBus) { diff --git a/src/main/java/studio/fantasyit/maid_useful_task/task/MaidEndEyeTask.java b/src/main/java/studio/fantasyit/maid_useful_task/task/MaidEndEyeTask.java new file mode 100644 index 0000000..0fb3916 --- /dev/null +++ b/src/main/java/studio/fantasyit/maid_useful_task/task/MaidEndEyeTask.java @@ -0,0 +1,50 @@ +package studio.fantasyit.maid_useful_task.task; + +import com.github.tartaricacid.touhoulittlemaid.api.task.IMaidTask; +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.mojang.datafixers.util.Pair; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.entity.ai.behavior.BehaviorControl; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import org.jetbrains.annotations.Nullable; +import studio.fantasyit.maid_useful_task.MaidUsefulTask; +import studio.fantasyit.maid_useful_task.behavior.EnderEyeMoveBehavior; +import studio.fantasyit.maid_useful_task.behavior.EnderEyeWaitBehavior; + +import java.util.ArrayList; +import java.util.List; + +public class MaidEndEyeTask implements IMaidTask { + public static final ResourceLocation UID = new ResourceLocation(MaidUsefulTask.MODID, "end_eye"); + + @Override + public ResourceLocation getUid() { + return UID; + } + + @Override + public ItemStack getIcon() { + return Items.ENDER_EYE.getDefaultInstance(); + } + + @Nullable + @Override + public SoundEvent getAmbientSound(EntityMaid entityMaid) { + return null; + } + + @Override + public List>> createBrainTasks(EntityMaid entityMaid) { + List> > list = new ArrayList<>(); + list.add(Pair.of(1, new EnderEyeMoveBehavior())); + list.add(Pair.of(2, new EnderEyeWaitBehavior())); + return list; + } + + @Override + public boolean enableLookAndRandomWalk(EntityMaid maid) { + return false; + } +} diff --git a/src/main/java/studio/fantasyit/maid_useful_task/util/MemoryUtil.java b/src/main/java/studio/fantasyit/maid_useful_task/util/MemoryUtil.java index ae1cba0..21a2df5 100644 --- a/src/main/java/studio/fantasyit/maid_useful_task/util/MemoryUtil.java +++ b/src/main/java/studio/fantasyit/maid_useful_task/util/MemoryUtil.java @@ -80,4 +80,11 @@ public class MemoryUtil { public static void setCurrent(EntityMaid maid, CurrentWork currentWork){ maid.getBrain().setMemory(MemoryModuleRegistry.CURRENT_WORK.get(), currentWork); } + + public static void setCommonBlockCache(EntityMaid maid, BlockPos pos){ + maid.getBrain().setMemory(MemoryModuleRegistry.COMMON_BLOCK_CACHE.get(), pos); + } + public static BlockPos getCommonBlockCache(EntityMaid maid){ + return maid.getBrain().getMemory(MemoryModuleRegistry.COMMON_BLOCK_CACHE.get()).orElse(null); + } } diff --git a/src/main/resources/maid_useful_task.mixins.json b/src/main/resources/maid_useful_task.mixins.json index 91c8945..9977e89 100644 --- a/src/main/resources/maid_useful_task.mixins.json +++ b/src/main/resources/maid_useful_task.mixins.json @@ -5,6 +5,7 @@ "compatibilityLevel": "JAVA_8", "refmap": "maid_useful_task.refmap.json", "mixins": [ + "FollowMaidMixin", "MaidCheckPickupItem", "MaidMoveControlMixin", "MaidRunOneMixin"