2 Commits

Author SHA1 Message Date
xypp
b3d6464dc7 Add tamable entity's owner check in effect behavior. 2025-05-27 00:48:36 +08:00
xypp
3e5879471e Add some features to revive task 2025-05-26 22:52:36 +08:00
41 changed files with 378 additions and 672 deletions

View File

@@ -21,7 +21,7 @@ group = mod_group_id
version = mod_version version = mod_version
base { base {
archivesName = minecraft_version + "-" + mod_id archivesName = mod_id
} }
java { java {
@@ -65,7 +65,7 @@ minecraft {
// However, it must be at "META-INF/accesstransformer.cfg" in the final mod jar to be loaded by Forge. // However, it must be at "META-INF/accesstransformer.cfg" in the final mod jar to be loaded by Forge.
// This default location is a best practice to automatically put the file in the right place in the final jar. // This default location is a best practice to automatically put the file in the right place in the final jar.
// See https://docs.minecraftforge.net/en/latest/advanced/accesstransformers/ for more information. // See https://docs.minecraftforge.net/en/latest/advanced/accesstransformers/ for more information.
accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
// Default run configurations. // Default run configurations.
// These can be tweaked, removed, or duplicated as needed. // These can be tweaked, removed, or duplicated as needed.
@@ -133,9 +133,9 @@ repositories {
// If you have mod jar dependencies in ./libs, you can declare them as a repository like so. // If you have mod jar dependencies in ./libs, you can declare them as a repository like so.
// See https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:flat_dir_resolver // See https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:flat_dir_resolver
flatDir { // flatDir {
dir 'libs' // dir 'libs'
} // }
maven { maven {
url "https://cursemaven.com" url "https://cursemaven.com"
} }
@@ -165,19 +165,13 @@ dependencies {
// http://www.gradle.org/docs/current/userguide/dependency_management.html // http://www.gradle.org/docs/current/userguide/dependency_management.html
annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' annotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
compileOnly fg.deobf("curse.maven:touhou-little-maid-355044:6911704") compileOnly fg.deobf("curse.maven:touhou-little-maid-355044:6440955")
runtimeOnly fg.deobf("curse.maven:touhou-little-maid-355044:6911704")
// compileOnly fg.deobf("libs:touhoulittlemaid-${minecraft_version}-release:1.3.7")
// runtimeOnly fg.deobf("libs:touhoulittlemaid-${minecraft_version}-release:1.3.7")
compileOnly fg.deobf("curse.maven:playerrevive-266890:6048921") compileOnly fg.deobf("curse.maven:playerrevive-266890:6048921")
compileOnly fg.deobf("curse.maven:creativecore-257814:6383884") compileOnly fg.deobf("curse.maven:creativecore-257814:6383884")
compileOnly fg.deobf("curse.maven:natures-compass-252848:4712189") runtimeOnly fg.deobf("curse.maven:touhou-little-maid-355044:6440955")
compileOnly fg.deobf("curse.maven:explorers-compass-491794:4712194") runtimeOnly fg.deobf("curse.maven:maid-storage-manager-1210244:6455832")
runtimeOnly fg.deobf("curse.maven:playerrevive-266890:6048921") runtimeOnly fg.deobf("curse.maven:playerrevive-266890:6048921")
runtimeOnly fg.deobf("curse.maven:creativecore-257814:6383884") runtimeOnly fg.deobf("curse.maven:creativecore-257814:6383884")
// runtimeOnly fg.deobf("curse.maven:natures-compass-252848:4712189")
// runtimeOnly fg.deobf("curse.maven:explorers-compass-491794:4712194")
compileOnly(annotationProcessor("io.github.llamalad7:mixinextras-common:0.4.1")) compileOnly(annotationProcessor("io.github.llamalad7:mixinextras-common:0.4.1"))
implementation(jarJar("io.github.llamalad7:mixinextras-forge:0.4.1")) { implementation(jarJar("io.github.llamalad7:mixinextras-forge:0.4.1")) {
jarJar.ranged(it, "[0.4.1,)") jarJar.ranged(it, "[0.4.1,)")
@@ -190,19 +184,18 @@ dependencies {
// See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html // See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html
tasks.named('processResources', ProcessResources).configure { tasks.named('processResources', ProcessResources).configure {
var replaceProperties = [ var replaceProperties = [
minecraft_version : minecraft_version, minecraft_version_range: minecraft_version_range, minecraft_version: minecraft_version, minecraft_version_range: minecraft_version_range,
forge_version : forge_version, forge_version_range: forge_version_range, forge_version: forge_version, forge_version_range: forge_version_range,
loader_version_range: loader_version_range, loader_version_range: loader_version_range,
mod_id : mod_id, mod_name: mod_name, mod_license: mod_license, mod_version: mod_version, mod_id: mod_id, mod_name: mod_name, mod_license: mod_license, mod_version: mod_version,
mod_authors : mod_authors, mod_description: mod_description, mod_authors: mod_authors, mod_description: mod_description,
] ]
inputs.properties replaceProperties inputs.properties replaceProperties
filesMatching(['META-INF/mods.toml', 'pack.mcmeta']) { filesMatching(['META-INF/mods.toml', 'pack.mcmeta']) {
expand replaceProperties + [project: project] expand replaceProperties + [project: project]
} }}
}
// Example for how to get properties into the manifest for reading at runtime. // Example for how to get properties into the manifest for reading at runtime.
tasks.named('jar', Jar).configure { tasks.named('jar', Jar).configure {

View File

@@ -38,7 +38,7 @@ mod_name=maid useful task
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
mod_license=MIT mod_license=MIT
# The mod version. See https://semver.org/ # The mod version. See https://semver.org/
mod_version=1.3.7 mod_version=1.3.3_a_1
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
# This should match the base package used for the mod sources. # This should match the base package used for the mod sources.
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html # See https://maven.apache.org/guides/mini/guide-naming-conventions.html

View File

@@ -5,15 +5,14 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.config.ModConfigEvent; import net.minecraftforge.fml.event.config.ModConfigEvent;
import java.util.List;
// An example config class. This is not required, but it's a good idea to have one to keep your config organized. // An example config class. This is not required, but it's a good idea to have one to keep your config organized.
// Demonstrates how to use Forge's config APIs // Demonstrates how to use Forge's config APIs
@Mod.EventBusSubscriber(modid = MaidUsefulTask.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) @Mod.EventBusSubscriber(modid = MaidUsefulTask.MODID, bus = Mod.EventBusSubscriber.Bus.MOD)
public class Config { public class Config {
private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder(); private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();
private static final ForgeConfigSpec.BooleanValue SELF_RESCUE = BUILDER
.define("misc.self_rescue", true);
private static final ForgeConfigSpec.BooleanValue ENABLE_LOGGING = BUILDER private static final ForgeConfigSpec.BooleanValue ENABLE_LOGGING = BUILDER
.define("functions.logging", true); .define("functions.logging", true);
private static final ForgeConfigSpec.BooleanValue ENABLE_REVIVE = BUILDER private static final ForgeConfigSpec.BooleanValue ENABLE_REVIVE = BUILDER
@@ -26,9 +25,6 @@ public class Config {
private static final ForgeConfigSpec.BooleanValue ENABLE_REVIVE_TOTEM = BUILDER private static final ForgeConfigSpec.BooleanValue ENABLE_REVIVE_TOTEM = BUILDER
.define("revive.totem", true); .define("revive.totem", true);
private static final ForgeConfigSpec.BooleanValue LOGGING_DISABLE_BLOCKUP = BUILDER
.define("logging.disable_blockup", false);
private static final ForgeConfigSpec.BooleanValue ENABLE_VEHICLE_CONTROL_FULL = BUILDER private static final ForgeConfigSpec.BooleanValue ENABLE_VEHICLE_CONTROL_FULL = BUILDER
.define("vehicle_control.full", true); .define("vehicle_control.full", true);
private static final ForgeConfigSpec.BooleanValue ENABLE_VEHICLE_CONTROL_ROTATE = BUILDER private static final ForgeConfigSpec.BooleanValue ENABLE_VEHICLE_CONTROL_ROTATE = BUILDER
@@ -36,8 +32,6 @@ public class Config {
static final ForgeConfigSpec SPEC = BUILDER.build(); static final ForgeConfigSpec SPEC = BUILDER.build();
public static boolean enableSelfRescue = false;
public static boolean enableLoggingTask = false; public static boolean enableLoggingTask = false;
public static boolean enableReviveTask = false; public static boolean enableReviveTask = false;
public static boolean enableLocateTask = false; public static boolean enableLocateTask = false;
@@ -47,12 +41,8 @@ public class Config {
public static boolean enableVehicleControlFull = false; public static boolean enableVehicleControlFull = false;
public static boolean enableVehicleControlRotate = false; public static boolean enableVehicleControlRotate = false;
public static boolean disableLoggingBlockUp = false;
@SubscribeEvent @SubscribeEvent
static void onLoad(final ModConfigEvent event) { static void onLoad(final ModConfigEvent event) {
enableSelfRescue = SELF_RESCUE.get();
enableLoggingTask = ENABLE_LOGGING.get(); enableLoggingTask = ENABLE_LOGGING.get();
enableReviveTask = ENABLE_REVIVE.get(); enableReviveTask = ENABLE_REVIVE.get();
enableLocateTask = ENABLE_LOCATE.get(); enableLocateTask = ENABLE_LOCATE.get();
@@ -60,6 +50,5 @@ public class Config {
enableReviveTotem = ENABLE_REVIVE_TOTEM.get(); enableReviveTotem = ENABLE_REVIVE_TOTEM.get();
enableVehicleControlFull = ENABLE_VEHICLE_CONTROL_FULL.get(); enableVehicleControlFull = ENABLE_VEHICLE_CONTROL_FULL.get();
enableVehicleControlRotate = ENABLE_VEHICLE_CONTROL_ROTATE.get(); enableVehicleControlRotate = ENABLE_VEHICLE_CONTROL_ROTATE.get();
disableLoggingBlockUp = LOGGING_DISABLE_BLOCKUP.get();
} }
} }

View File

@@ -5,7 +5,6 @@ import com.github.tartaricacid.touhoulittlemaid.api.LittleMaidExtension;
import com.github.tartaricacid.touhoulittlemaid.api.entity.ai.IExtraMaidBrain; import com.github.tartaricacid.touhoulittlemaid.api.entity.ai.IExtraMaidBrain;
import com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.ExtraMaidBrainManager; import com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.ExtraMaidBrainManager;
import com.github.tartaricacid.touhoulittlemaid.entity.data.TaskDataRegister; import com.github.tartaricacid.touhoulittlemaid.entity.data.TaskDataRegister;
import com.github.tartaricacid.touhoulittlemaid.entity.item.control.BroomControlManager;
import com.github.tartaricacid.touhoulittlemaid.entity.task.TaskManager; import com.github.tartaricacid.touhoulittlemaid.entity.task.TaskManager;
import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import studio.fantasyit.maid_useful_task.compat.PlayerRevive; import studio.fantasyit.maid_useful_task.compat.PlayerRevive;
@@ -16,7 +15,6 @@ import studio.fantasyit.maid_useful_task.registry.MemoryModuleRegistry;
import studio.fantasyit.maid_useful_task.task.MaidLocateTask; import studio.fantasyit.maid_useful_task.task.MaidLocateTask;
import studio.fantasyit.maid_useful_task.task.MaidRevivePlayerTask; import studio.fantasyit.maid_useful_task.task.MaidRevivePlayerTask;
import studio.fantasyit.maid_useful_task.task.MaidTreeTask; import studio.fantasyit.maid_useful_task.task.MaidTreeTask;
import studio.fantasyit.maid_useful_task.vehicle.broom.BroomController;
import java.util.List; import java.util.List;
@@ -62,9 +60,4 @@ public class UsefulTaskExtension implements ILittleMaid {
MaidReviveConfig.KEY = register.register(new MaidReviveConfig()), MaidReviveConfig.KEY = register.register(new MaidReviveConfig()),
MaidReviveConfig.Data::getDefault); MaidReviveConfig.Data::getDefault);
} }
@Override
public void registerBroomControl(BroomControlManager register) {
register.register(BroomController::new);
}
} }

View File

@@ -1,29 +0,0 @@
package studio.fantasyit.maid_useful_task.api;
import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid;
import net.minecraft.core.BlockPos;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.eventbus.api.Cancelable;
import net.minecraftforge.eventbus.api.Event;
@Cancelable
public class ItemLocateEvent extends Event {
public final ItemStack itemStack;
public final EntityMaid maid;
public final BlockPos cache;
public BlockPos target = null;
public ItemLocateEvent(ItemStack itemStack, EntityMaid maid, BlockPos cache) {
this.itemStack = itemStack;
this.maid = maid;
this.cache = cache;
}
public BlockPos getTarget() {
return target;
}
public void setTarget(BlockPos target) {
this.target = target;
}
}

View File

@@ -176,6 +176,8 @@ public class PlayerReviveBehavior extends Behavior<EntityMaid> {
@Override @Override
protected void stop(ServerLevel p_22548_, EntityMaid maid, long p_22550_) { protected void stop(ServerLevel p_22548_, EntityMaid maid, long p_22550_) {
PlayerReviveServer.removePlayerAsHelper(WrappedMaidFakePlayer.get(maid)); PlayerReviveServer.removePlayerAsHelper(WrappedMaidFakePlayer.get(maid));
if (!bleeding.isBleeding())
targetPlayer.addEffect(new MobEffectInstance(MobEffects.REGENERATION, 200));
for (UUID uuid : aggroEntities) { for (UUID uuid : aggroEntities) {
Entity entity = p_22548_.getEntity(uuid); Entity entity = p_22548_.getEntity(uuid);
if (entity instanceof Monster monster && entity.isAlive()) if (entity instanceof Monster monster && entity.isAlive())

View File

@@ -0,0 +1,114 @@
package studio.fantasyit.maid_useful_task.behavior;
import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.stats.Stats;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.TamableAnimal;
import net.minecraft.world.entity.ai.behavior.Behavior;
import net.minecraft.world.entity.ai.behavior.BehaviorUtils;
import net.minecraft.world.entity.ai.goal.target.TargetGoal;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.ai.memory.MemoryStatus;
import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities;
import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.entity.EntityTypeTest;
import net.minecraft.world.phys.AABB;
import studio.fantasyit.maid_useful_task.Config;
import studio.fantasyit.maid_useful_task.data.MaidReviveConfig;
import studio.fantasyit.maid_useful_task.util.InvUtil;
import studio.fantasyit.maid_useful_task.util.WrappedMaidFakePlayer;
import team.creative.playerrevive.PlayerRevive;
import team.creative.playerrevive.api.IBleeding;
import team.creative.playerrevive.server.PlayerReviveServer;
import java.util.*;
public class SupportEffectBehavior extends Behavior<EntityMaid> {
public SupportEffectBehavior() {
super(Map.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.VALUE_PRESENT));
}
@Override
protected boolean checkExtraStartConditions(ServerLevel p_22538_, EntityMaid maid) {
if (maid.getExperience() <= 0) return false;
LivingEntity player = maid.getOwner();
if (player == null) return false;
Optional<NearestVisibleLivingEntities> memory = maid.getBrain().getMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES);
return memory.map(list -> list
.find(entity -> entity instanceof Monster)
.map(monster -> (Monster) monster)
.map(Mob::getTarget)
.anyMatch(target -> {
if (target == null)
return false;
if (target.equals(player)) {
return true;
}
if (target instanceof TamableAnimal tamed) {
if (tamed.getOwner() != null && tamed.getOwner().equals(player))
return true;
}
return false;
})
).orElse(false);
}
@Override
protected void start(ServerLevel level, EntityMaid maid, long p_22542_) {
super.start(level, maid, p_22542_);
}
@Override
protected boolean canStillUse(ServerLevel p_22545_, EntityMaid maid, long p_22547_) {
return this.checkExtraStartConditions(p_22545_, maid);
}
@Override
protected void tick(ServerLevel level, EntityMaid maid, long p_22553_) {
super.tick(level, maid, p_22553_);
if (p_22553_ % 20 == 0) {
//1 experience per second.
maid.setExperience(maid.getExperience() - 1);
reApplyEffects(level, maid);
}
}
private void reApplyEffects(ServerLevel level, EntityMaid maid) {
LivingEntity player = maid.getOwner();
if (player == null) return;
List<Entity> entities = level.getEntities(maid, AABB.ofSize(maid.position(), 16, 16, 16));
for (Entity entity : entities) {
if (entity instanceof Monster monster && entity.isAlive()) {
monster.addEffect(new MobEffectInstance(MobEffects.WEAKNESS, 30, 0, false, false));
} else if (entity instanceof TamableAnimal animal && animal.isAlive()) {
if (animal.getOwner() != null && animal.getOwner().equals(player)) {
animal.addEffect(new MobEffectInstance(MobEffects.DAMAGE_RESISTANCE, 30, 0, false, false));
animal.addEffect(new MobEffectInstance(MobEffects.DAMAGE_BOOST, 30, 1, false, false));
}
} else if (entity.is(player)) {
player.addEffect(new MobEffectInstance(MobEffects.DAMAGE_RESISTANCE, 30, 0, false, false));
player.addEffect(new MobEffectInstance(MobEffects.DAMAGE_BOOST, 30, 1, false, false));
}
}
}
@Override
protected void stop(ServerLevel p_22548_, EntityMaid maid, long p_22550_) {
}
@Override
protected boolean timedOut(long p_22537_) {
return false;
}
}

View File

@@ -7,6 +7,7 @@ import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.ai.behavior.Behavior; import net.minecraft.world.entity.ai.behavior.Behavior;
import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.ai.memory.MemoryStatus;
import net.minecraft.world.level.block.state.BlockState;
import studio.fantasyit.maid_useful_task.memory.BlockUpContext; import studio.fantasyit.maid_useful_task.memory.BlockUpContext;
import studio.fantasyit.maid_useful_task.memory.CurrentWork; import studio.fantasyit.maid_useful_task.memory.CurrentWork;
import studio.fantasyit.maid_useful_task.task.IMaidBlockUpTask; import studio.fantasyit.maid_useful_task.task.IMaidBlockUpTask;
@@ -28,15 +29,15 @@ public class BlockUpDestroyBehavior extends Behavior<EntityMaid> {
} }
public BlockUpDestroyBehavior() { public BlockUpDestroyBehavior() {
super(Map.of(), 500); super(Map.of(),500);
} }
@Override @Override
protected boolean checkExtraStartConditions(ServerLevel p_22538_, EntityMaid p_22539_) { protected boolean checkExtraStartConditions(ServerLevel p_22538_, EntityMaid p_22539_) {
if (!Conditions.isCurrent(p_22539_, CurrentWork.BLOCKUP_DOWN)) return false; if(!Conditions.isCurrent(p_22539_, CurrentWork.BLOCKUP_DOWN)) return false;
if (!MemoryUtil.getBlockUpContext(p_22539_).hasTarget()) return false; if (!MemoryUtil.getBlockUpContext(p_22539_).hasTarget()) return false;
if (MemoryUtil.getBlockUpContext(p_22539_).getStatus() != BlockUpContext.STATUS.DOWN) return false; if (MemoryUtil.getBlockUpContext(p_22539_).getStatus() != BlockUpContext.STATUS.DOWN) return false;
return true; return Conditions.hasReachedValidTargetOrReset(p_22539_, 0.8f);
} }
@Override @Override
@@ -72,7 +73,6 @@ public class BlockUpDestroyBehavior extends Behavior<EntityMaid> {
} }
} }
} }
@Override @Override
protected void stop(ServerLevel p_22548_, EntityMaid maid, long p_22550_) { protected void stop(ServerLevel p_22548_, EntityMaid maid, long p_22550_) {
super.stop(p_22548_, maid, p_22550_); super.stop(p_22548_, maid, p_22550_);

View File

@@ -7,6 +7,7 @@ import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.ai.behavior.Behavior; import net.minecraft.world.entity.ai.behavior.Behavior;
import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.ai.memory.MemoryStatus;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import studio.fantasyit.maid_useful_task.memory.BlockUpContext; import studio.fantasyit.maid_useful_task.memory.BlockUpContext;
@@ -44,7 +45,6 @@ public class BlockUpPlaceBehavior extends Behavior<EntityMaid> {
protected boolean canStillUse(ServerLevel p_22545_, EntityMaid maid, long p_22547_) { protected boolean canStillUse(ServerLevel p_22545_, EntityMaid maid, long p_22547_) {
if (MemoryUtil.getBlockUpContext(maid).getStatus() != BlockUpContext.STATUS.UP) return false; if (MemoryUtil.getBlockUpContext(maid).getStatus() != BlockUpContext.STATUS.UP) return false;
if (maid.onGround() && !p_22545_.getBlockState(maid.blockPosition().above().above()).isAir()) return false; if (maid.onGround() && !p_22545_.getBlockState(maid.blockPosition().above().above()).isAir()) return false;
if (maid.getY() > context.getTargetPos().getY() + 2) return false;
return !(maid.blockPosition().equals(context.getTargetPos()) && maid.onGround()); return !(maid.blockPosition().equals(context.getTargetPos()) && maid.onGround());
} }
@@ -60,7 +60,9 @@ public class BlockUpPlaceBehavior extends Behavior<EntityMaid> {
AABB boundingBox = maid.getBoundingBox(); AABB boundingBox = maid.getBoundingBox();
BlockPos startPos = context.getStartPos(); BlockPos startPos = context.getStartPos();
Vec3 move = maid.getDeltaMovement(); Vec3 move = maid.getDeltaMovement();
if (boundingBox.maxX <= startPos.getX() + 1 && boundingBox.maxZ <= startPos.getZ() + 1 && boundingBox.minX >= startPos.getX() && boundingBox.minZ >= startPos.getZ()) { if (boundingBox.maxX <= startPos.getX() + 1 && boundingBox.maxZ <= startPos.getZ() + 1
&& boundingBox.minX >= startPos.getX() && boundingBox.minZ >= startPos.getZ()
) {
maid.setDeltaMovement(0, move.y, 0); maid.setDeltaMovement(0, move.y, 0);
return true; return true;
} }
@@ -78,7 +80,9 @@ public class BlockUpPlaceBehavior extends Behavior<EntityMaid> {
task.swapValidItemToHand(maid); task.swapValidItemToHand(maid);
BlockPos pos = maid.blockPosition(); BlockPos pos = maid.blockPosition();
BlockPos below = pos.below(); BlockPos below = pos.below();
if (context.isOnLine(pos)) if (below.equals(context.getTargetPos())) return; if (context.isOnLine(pos))
if (below.equals(context.getTargetPos()))
return;
if (level.getBlockState(below).canBeReplaced() && level.getBlockState(pos).canBeReplaced()) { if (level.getBlockState(below).canBeReplaced() && level.getBlockState(pos).canBeReplaced()) {
maid.swing(InteractionHand.MAIN_HAND); maid.swing(InteractionHand.MAIN_HAND);
MaidUtils.placeBlock(maid, below); MaidUtils.placeBlock(maid, below);

View File

@@ -45,11 +45,9 @@ public class BlockUpScheduleBehavior extends Behavior<EntityMaid> {
if (context.getStatus() == BlockUpContext.STATUS.DOWN) { if (context.getStatus() == BlockUpContext.STATUS.DOWN) {
MemoryUtil.setTarget(maid, context.getTargetPos(), 0.5f); MemoryUtil.setTarget(maid, context.getTargetPos(), 0.5f);
MemoryUtil.setCurrent(maid, CurrentWork.BLOCKUP_DOWN); MemoryUtil.setCurrent(maid, CurrentWork.BLOCKUP_DOWN);
} else if (maid.canPathReach(context.getStartPos())) { } else {
MemoryUtil.setTarget(maid, context.getStartPos(), 0.5f); MemoryUtil.setTarget(maid, context.getStartPos(), 0.5f);
MemoryUtil.setCurrent(maid, CurrentWork.BLOCKUP_UP); MemoryUtil.setCurrent(maid, CurrentWork.BLOCKUP_UP);
} else {
context.clearStartTarget();
} }
} else if (!context.isOnLine(maid.blockPosition()) || context.getStartPos().equals(context.getTargetPos())) { } else if (!context.isOnLine(maid.blockPosition()) || context.getStartPos().equals(context.getTargetPos())) {
context.clearStartTarget(); context.clearStartTarget();

View File

@@ -53,7 +53,7 @@ public class DestoryBlockBehavior extends Behavior<EntityMaid> {
BlockTargetMemory blockTargetMemory = MemoryUtil.getDestroyTargetMemory(maid); BlockTargetMemory blockTargetMemory = MemoryUtil.getDestroyTargetMemory(maid);
if (blockTargetMemory != null) { if (blockTargetMemory != null) {
blockPosSet = new ArrayList<>(blockTargetMemory.getBlockPosSet()); blockPosSet = new ArrayList<>(blockTargetMemory.getBlockPosSet());
blockPosSet.sort((o1, o2) -> (int) (o1.distSqr(maid.blockPosition().above()) - o2.distSqr(maid.blockPosition().above()))); blockPosSet.sort((o1, o2) -> (int) (o1.distSqr(maid.blockPosition()) - o2.distSqr(maid.blockPosition())));
} }
index = 0; index = 0;
task = (IMaidBlockDestroyTask) maid.getTask(); task = (IMaidBlockDestroyTask) maid.getTask();
@@ -65,8 +65,6 @@ public class DestoryBlockBehavior extends Behavior<EntityMaid> {
@Override @Override
protected boolean canStillUse(ServerLevel p_22545_, EntityMaid p_22546_, long p_22547_) { protected boolean canStillUse(ServerLevel p_22545_, EntityMaid p_22546_, long p_22547_) {
if (MemoryUtil.getCurrent(p_22546_) != CurrentWork.DESTROY && MemoryUtil.getCurrent(p_22546_) != CurrentWork.BLOCKUP_DESTROY)
return false;
return (blockPosSet != null && index < blockPosSet.size()) || targetPos != null; return (blockPosSet != null && index < blockPosSet.size()) || targetPos != null;
} }

View File

@@ -10,7 +10,6 @@ import studio.fantasyit.maid_useful_task.memory.CurrentWork;
import studio.fantasyit.maid_useful_task.task.IMaidBlockDestroyTask; import studio.fantasyit.maid_useful_task.task.IMaidBlockDestroyTask;
import studio.fantasyit.maid_useful_task.util.Conditions; import studio.fantasyit.maid_useful_task.util.Conditions;
import studio.fantasyit.maid_useful_task.util.MemoryUtil; import studio.fantasyit.maid_useful_task.util.MemoryUtil;
import studio.fantasyit.maid_useful_task.util.PosUtils;
import java.util.List; import java.util.List;
@@ -53,19 +52,14 @@ public class DestoryBlockMoveBehavior extends MaidCenterMoveToBlockTask {
protected boolean shouldMoveTo(@NotNull ServerLevel serverLevel, @NotNull EntityMaid entityMaid, @NotNull BlockPos blockPos) { protected boolean shouldMoveTo(@NotNull ServerLevel serverLevel, @NotNull EntityMaid entityMaid, @NotNull BlockPos blockPos) {
if (!task.shouldDestroyBlock(entityMaid, blockPos.immutable())) return false; if (!task.shouldDestroyBlock(entityMaid, blockPos.immutable())) return false;
targetPos = blockPos.immutable(); targetPos = blockPos.immutable();
BlockPos startPos = entityMaid.blockPosition();
if (blockPos instanceof BlockPos.MutableBlockPos mb) { if (blockPos instanceof BlockPos.MutableBlockPos mb) {
for (int dx = 0; dx < task.reachDistance(); dx = dx <= 0 ? 1 - dx : -dx) { for (int dx = 0; dx < task.reachDistance(); dx = dx <= 0 ? 1 - dx : -dx) {
for (int dy = 0; dy < task.reachDistance(); dy = dy <= 0 ? 1 - dy : -dy) { for (int dy = 0; dy < task.reachDistance(); dy = dy <= 0 ? 1 - dy : -dy) {
for (int dz = 0; dz < task.reachDistance(); dz = dz <= 0 ? 1 - dz : -dz) { for (int dz = 0; dz < task.reachDistance(); dz = dz <= 0 ? 1 - dz : -dz) {
BlockPos pos = mb.offset(dx, dy, dz); BlockPos pos = mb.offset(dx, dy, dz);
if (!PosUtils.isSafePos(serverLevel, pos)) continue;
if (!Conditions.isGlobalValidTarget(entityMaid, pos, targetPos)) continue; if (!Conditions.isGlobalValidTarget(entityMaid, pos, targetPos)) continue;
if (pos.distSqr(targetPos) > task.reachDistance() * task.reachDistance()) continue; if (pos.distSqr(targetPos) > task.reachDistance() * task.reachDistance()) continue;
if (Math.abs(startPos.getY() - pos.getY()) >= task.reachDistance()) continue; if (entityMaid.isWithinRestriction(pos) && pathfindingBFS.canPathReach(pos)) {
if (Math.abs(startPos.getX() - pos.getX()) >= task.reachDistance()) continue;
if (Math.abs(startPos.getZ() - pos.getZ()) >= task.reachDistance()) continue;
if (pos.equals(entityMaid.blockPosition()) || (entityMaid.isWithinRestriction(pos) && pathfindingBFS.canPathReach(pos))) {
blockPosSet = task.toDestroyFromStanding(entityMaid, targetPos, pos); blockPosSet = task.toDestroyFromStanding(entityMaid, targetPos, pos);
if (blockPosSet != null) { if (blockPosSet != null) {
mb.set(pos); mb.set(pos);
@@ -84,10 +78,10 @@ public class DestoryBlockMoveBehavior extends MaidCenterMoveToBlockTask {
@Override @Override
protected @NotNull MaidPathFindingBFS getOrCreateArrivalMap(@NotNull ServerLevel worldIn, @NotNull EntityMaid maid) { protected @NotNull MaidPathFindingBFS getOrCreateArrivalMap(@NotNull ServerLevel worldIn, @NotNull EntityMaid maid) {
if (this.pathfindingBFS == null) if (this.pathfindingBFS == null)
if (maid.hasRestriction()) if(maid.hasRestriction())
this.pathfindingBFS = new MaidPathFindingBFS(maid.getNavigation().getNodeEvaluator(), worldIn, maid, (int) maid.getRestrictRadius() + 1, task.reachDistance() + 2); this.pathfindingBFS = new MaidPathFindingBFS(maid.getNavigation().getNodeEvaluator(), worldIn, maid, 14, (int) maid.getRestrictRadius());
else else
this.pathfindingBFS = new MaidPathFindingBFS(maid.getNavigation().getNodeEvaluator(), worldIn, maid, task.reachDistance() + 1, task.reachDistance() + 2); this.pathfindingBFS = new MaidPathFindingBFS(maid.getNavigation().getNodeEvaluator(), worldIn, maid, 14);
return this.pathfindingBFS; return this.pathfindingBFS;
} }

View File

@@ -1,6 +1,7 @@
package studio.fantasyit.maid_useful_task.behavior.common; package studio.fantasyit.maid_useful_task.behavior.common;
import com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.task.MaidCheckRateTask;
import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid;
import com.github.tartaricacid.touhoulittlemaid.entity.passive.MaidPathFindingBFS; import com.github.tartaricacid.touhoulittlemaid.entity.passive.MaidPathFindingBFS;
import com.github.tartaricacid.touhoulittlemaid.init.InitEntities; import com.github.tartaricacid.touhoulittlemaid.init.InitEntities;
@@ -40,11 +41,9 @@ abstract public class MaidCenterMoveToBlockTask extends Behavior<EntityMaid> {
this.verticalSearchRange = verticalSearchRange; this.verticalSearchRange = verticalSearchRange;
this.searchRange = defaultSearchRange; this.searchRange = defaultSearchRange;
} }
public void setSearchRange(int searchRange) { public void setSearchRange(int searchRange) {
this.searchRange = searchRange; this.searchRange = searchRange;
} }
protected final void searchForDestination(ServerLevel worldIn, EntityMaid maid) { protected final void searchForDestination(ServerLevel worldIn, EntityMaid maid) {
MaidPathFindingBFS pathFinding = this.getOrCreateArrivalMap(worldIn, maid); MaidPathFindingBFS pathFinding = this.getOrCreateArrivalMap(worldIn, maid);
BlockPos centrePos = this.getWorkSearchPos(maid); BlockPos centrePos = this.getWorkSearchPos(maid);
@@ -74,7 +73,7 @@ abstract public class MaidCenterMoveToBlockTask extends Behavior<EntityMaid> {
} }
protected MaidPathFindingBFS getOrCreateArrivalMap(ServerLevel worldIn, EntityMaid maid) { protected MaidPathFindingBFS getOrCreateArrivalMap(ServerLevel worldIn, EntityMaid maid) {
return new MaidPathFindingBFS(maid.getNavigation().getNodeEvaluator(), worldIn, maid, maid.searchRadius(), 9); return new MaidPathFindingBFS(maid.getNavigation().getNodeEvaluator(), worldIn, maid);
} }
private BlockPos getWorkSearchPos(EntityMaid maid) { private BlockPos getWorkSearchPos(EntityMaid maid) {

View File

@@ -1,80 +0,0 @@
package studio.fantasyit.maid_useful_task.behavior.common;
import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.ai.behavior.Behavior;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.VoxelShape;
import studio.fantasyit.maid_useful_task.Config;
import studio.fantasyit.maid_useful_task.memory.CurrentWork;
import studio.fantasyit.maid_useful_task.task.IMaidBlockDestroyTask;
import studio.fantasyit.maid_useful_task.util.MemoryUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class MaidSelfRescueBehavior extends Behavior<EntityMaid> {
public MaidSelfRescueBehavior() {
super(Map.of(), 600);
}
boolean started = false;
private static boolean isNotSafeAndCanTryToDestroy(ServerLevel level, EntityMaid maid, BlockPos pos, IMaidBlockDestroyTask task) {
BlockState bs = level.getBlockState(pos);
if (bs.isAir()) return false;
VoxelShape collision = bs.getCollisionShape(level, pos);
if (collision.isEmpty()) return false;
return maid.getBoundingBox().intersects(collision.bounds().move(pos)) && bs.isSuffocating(level, pos) && task.mayDestroy(maid, pos);
}
@Override
protected boolean checkExtraStartConditions(ServerLevel level, EntityMaid maid) {
if (!Config.enableSelfRescue) return false;
if (!(maid.getTask() instanceof IMaidBlockDestroyTask ibdt)) return false;
if (isNotSafeAndCanTryToDestroy(level, maid, maid.blockPosition(), ibdt) || isNotSafeAndCanTryToDestroy(level, maid, maid.blockPosition().above(), ibdt))
return true;
return false;
}
@Override
protected boolean canStillUse(ServerLevel p_22545_, EntityMaid p_22546_, long p_22547_) {
return started && checkExtraStartConditions(p_22545_, p_22546_);
}
@Override
protected void start(ServerLevel p_22540_, EntityMaid maid, long p_22542_) {
started = false;
if (MemoryUtil.getCurrent(maid) == CurrentWork.DESTROY) {
//如果执行中破坏任务,则立刻停止。用以清空相关状态
MemoryUtil.setCurrent(maid, CurrentWork.IDLE);
return;
}
//等待上一个任务结束
if (MemoryUtil.getDestroyTargetMemory(maid) != null)
return;
if (!(maid.getTask() instanceof IMaidBlockDestroyTask task))
return;
started = true;
List<BlockPos> list = new ArrayList<>();
if (isNotSafeAndCanTryToDestroy(p_22540_, maid, maid.blockPosition(), task)) {
list.add(maid.blockPosition());
}
if (isNotSafeAndCanTryToDestroy(p_22540_, maid, maid.blockPosition().above(), task)) {
list.add(maid.blockPosition().above());
}
MemoryUtil.setDestroyTargetMemory(maid, list);
MemoryUtil.setTarget(maid, maid.blockPosition(), 0.5f);
MemoryUtil.setCurrent(maid, CurrentWork.DESTROY);
}
@Override
protected void stop(ServerLevel p_22548_, EntityMaid p_22549_, long p_22550_) {
MemoryUtil.clearTarget(p_22549_);
MemoryUtil.setCurrent(p_22549_, CurrentWork.IDLE);
}
}

View File

@@ -89,9 +89,9 @@ public class PlaceBlockMoveBehavior extends MaidCenterMoveToBlockTask {
protected @NotNull MaidPathFindingBFS getOrCreateArrivalMap(@NotNull ServerLevel worldIn, @NotNull EntityMaid maid) { protected @NotNull MaidPathFindingBFS getOrCreateArrivalMap(@NotNull ServerLevel worldIn, @NotNull EntityMaid maid) {
if (this.pathfindingBFS == null) if (this.pathfindingBFS == null)
if (maid.hasRestriction()) if (maid.hasRestriction())
this.pathfindingBFS = new MaidPathFindingBFS(maid.getNavigation().getNodeEvaluator(), worldIn, maid, (int) maid.getRestrictRadius(), 9); this.pathfindingBFS = new MaidPathFindingBFS(maid.getNavigation().getNodeEvaluator(), worldIn, maid, 14, (int) maid.getRestrictRadius());
else else
this.pathfindingBFS = new MaidPathFindingBFS(maid.getNavigation().getNodeEvaluator(), worldIn, maid, 7, 9); this.pathfindingBFS = new MaidPathFindingBFS(maid.getNavigation().getNodeEvaluator(), worldIn, maid, 14);
return this.pathfindingBFS; return this.pathfindingBFS;
} }

View File

@@ -1,20 +0,0 @@
package studio.fantasyit.maid_useful_task.compat;
import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid;
import net.minecraft.core.BlockPos;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.fml.ModList;
public class CompatEntry {
public static BlockPos getLocateTarget(EntityMaid maid, ItemStack itemStack) {
BlockPos tmp = null;
if (tmp == null && ModList.get().isLoaded("naturescompass")) {
tmp = NatureCompass.getCompassTarget(maid, itemStack);
}
if (tmp == null && ModList.get().isLoaded("explorerscompass")) {
tmp = ExplorerCompass.getCompassTarget(maid, itemStack);
}
return tmp;
}
}

View File

@@ -1,20 +0,0 @@
package studio.fantasyit.maid_useful_task.compat;
import com.chaosthedude.explorerscompass.ExplorersCompass;
import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid;
import net.minecraft.core.BlockPos;
import net.minecraft.world.item.ItemStack;
public class ExplorerCompass {
public static BlockPos getCompassTarget(EntityMaid maid, ItemStack itemStack) {
if (itemStack.is(ExplorersCompass.explorersCompass)) {
return new BlockPos(
ExplorersCompass.explorersCompass.getFoundStructureX(itemStack),
maid.level().getSeaLevel(),
ExplorersCompass.explorersCompass.getFoundStructureZ(itemStack)
);
}
return null;
}
}

View File

@@ -1,21 +0,0 @@
package studio.fantasyit.maid_useful_task.compat;
import com.chaosthedude.naturescompass.NaturesCompass;
import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid;
import net.minecraft.core.BlockPos;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.fml.ModList;
public class NatureCompass {
public static BlockPos getCompassTarget(EntityMaid maid, ItemStack itemStack) {
if (itemStack.is(NaturesCompass.naturesCompass)) {
return new BlockPos(
NaturesCompass.naturesCompass.getFoundBiomeX(itemStack),
maid.level().getSeaLevel(),
NaturesCompass.naturesCompass.getFoundBiomeZ(itemStack)
);
}
return null;
}
}

View File

@@ -1,7 +1,6 @@
package studio.fantasyit.maid_useful_task.data; package studio.fantasyit.maid_useful_task.data;
import com.github.tartaricacid.touhoulittlemaid.api.entity.data.TaskDataKey; import com.github.tartaricacid.touhoulittlemaid.api.entity.data.TaskDataKey;
import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import studio.fantasyit.maid_useful_task.MaidUsefulTask; import studio.fantasyit.maid_useful_task.MaidUsefulTask;
@@ -9,23 +8,15 @@ import studio.fantasyit.maid_useful_task.MaidUsefulTask;
public class MaidLoggingConfig implements TaskDataKey<MaidLoggingConfig.Data> { public class MaidLoggingConfig implements TaskDataKey<MaidLoggingConfig.Data> {
public static Data get(EntityMaid maid) {
return maid.getOrCreateData(KEY, Data.getDefault());
}
public static final class Data implements IConfigSetter { public static final class Data implements IConfigSetter {
private boolean plant; private boolean plant;
private boolean blockUp;
private boolean skipNonNature;
public Data(boolean plant, boolean blockUp, boolean skipNonNature) { public Data(boolean plant) {
this.plant = plant; this.plant = plant;
this.blockUp = blockUp;
this.skipNonNature = skipNonNature;
} }
public static Data getDefault() { public static Data getDefault() {
return new Data(true, true, true); return new Data(true);
} }
public boolean plant() { public boolean plant() {
@@ -36,34 +27,12 @@ public class MaidLoggingConfig implements TaskDataKey<MaidLoggingConfig.Data> {
this.plant = plant; this.plant = plant;
} }
public boolean blockUp() {
return blockUp;
}
public void blockUp(boolean blockUp) {
this.blockUp = blockUp;
}
public boolean skipNonNature() {
return skipNonNature;
}
public void skipNonNature(boolean skipNonNature) {
this.skipNonNature = skipNonNature;
}
@Override @Override
public void setConfigValue(String name, String value) { public void setConfigValue(String name, String value) {
switch (name) { switch (name) {
case "plant": case "plant":
plant = Boolean.parseBoolean(value); plant = Boolean.parseBoolean(value);
break; break;
case "blockUp":
blockUp = Boolean.parseBoolean(value);
break;
case "skipNonNature":
skipNonNature = Boolean.parseBoolean(value);
break;
} }
} }
} }
@@ -80,16 +49,12 @@ public class MaidLoggingConfig implements TaskDataKey<MaidLoggingConfig.Data> {
public CompoundTag writeSaveData(Data data) { public CompoundTag writeSaveData(Data data) {
CompoundTag tag = new CompoundTag(); CompoundTag tag = new CompoundTag();
tag.putBoolean("plant", data.plant); tag.putBoolean("plant", data.plant);
tag.putBoolean("blockUp", data.blockUp);
tag.putBoolean("skipNonNature", data.skipNonNature);
return tag; return tag;
} }
@Override @Override
public Data readSaveData(CompoundTag compound) { public Data readSaveData(CompoundTag compound) {
boolean plant = compound.getBoolean("plant"); boolean plant = compound.getBoolean("plant");
boolean blockUp = compound.getBoolean("blockUp"); return new Data(plant);
boolean skipNonNature = compound.getBoolean("skipNonNature");
return new Data(plant, blockUp, skipNonNature);
} }
} }

View File

@@ -15,8 +15,6 @@ public class MaidTickEvent {
if (event.getMaid().getTask() instanceof IMaidVehicleControlTask imvc && event.getMaid().getVehicle() != null) { if (event.getMaid().getTask() instanceof IMaidVehicleControlTask imvc && event.getMaid().getVehicle() != null) {
imvc.tick(sl, event.getMaid()); imvc.tick(sl, event.getMaid());
MaidVehicleManager.syncVehicleParameter(event.getMaid()); MaidVehicleManager.syncVehicleParameter(event.getMaid());
}else if(event.getMaid().getVehicle() != null){
MaidVehicleManager.stopControlling(event.getMaid());
} }
} }
} }

View File

@@ -5,9 +5,9 @@ import com.github.tartaricacid.touhoulittlemaid.client.gui.widget.button.MaidCon
import com.github.tartaricacid.touhoulittlemaid.inventory.container.task.TaskConfigContainer; import com.github.tartaricacid.touhoulittlemaid.inventory.container.task.TaskConfigContainer;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import studio.fantasyit.maid_useful_task.Config;
import studio.fantasyit.maid_useful_task.data.MaidLoggingConfig; import studio.fantasyit.maid_useful_task.data.MaidLoggingConfig;
import studio.fantasyit.maid_useful_task.network.MaidConfigurePacket; import studio.fantasyit.maid_useful_task.network.MaidConfigurePacket;
import studio.fantasyit.maid_useful_task.network.Network;
import studio.fantasyit.maid_useful_task.registry.GuiRegistry; import studio.fantasyit.maid_useful_task.registry.GuiRegistry;
import studio.fantasyit.maid_useful_task.util.TranslateUtil; import studio.fantasyit.maid_useful_task.util.TranslateUtil;
@@ -35,7 +35,7 @@ public class MaidLoggingConfigGui extends MaidTaskConfigGui<MaidLoggingConfigGui
int startLeft = leftPos + 87; int startLeft = leftPos + 87;
int startTop = topPos + 36; int startTop = topPos + 36;
this.addRenderableWidget(new MaidConfigButton(startLeft, startTop, this.addRenderableWidget(new MaidConfigButton(startLeft, startTop + 0,
Component.translatable("gui.maid_useful_task.logging.plant"), Component.translatable("gui.maid_useful_task.logging.plant"),
TranslateUtil.getBooleanTranslate(this.currentData.plant()), TranslateUtil.getBooleanTranslate(this.currentData.plant()),
button -> { button -> {
@@ -49,37 +49,5 @@ public class MaidLoggingConfigGui extends MaidTaskConfigGui<MaidLoggingConfigGui
MaidConfigurePacket.send(this.maid, MaidLoggingConfig.LOCATION, "plant", "true"); MaidConfigurePacket.send(this.maid, MaidLoggingConfig.LOCATION, "plant", "true");
} }
)); ));
if (!Config.disableLoggingBlockUp) {
startTop += 13;
this.addRenderableWidget(new MaidConfigButton(startLeft, startTop,
Component.translatable("gui.maid_useful_task.logging.block_up"),
TranslateUtil.getBooleanTranslate(this.currentData.blockUp()),
button -> {
this.currentData.blockUp(false);
button.setValue(TranslateUtil.getBooleanTranslate(false));
MaidConfigurePacket.send(this.maid, MaidLoggingConfig.LOCATION, "blockUp", "false");
},
button -> {
this.currentData.blockUp(true);
button.setValue(TranslateUtil.getBooleanTranslate(true));
MaidConfigurePacket.send(this.maid, MaidLoggingConfig.LOCATION, "blockUp", "true");
}
));
}
startTop += 13;
this.addRenderableWidget(new MaidConfigButton(startLeft, startTop,
Component.translatable("gui.maid_useful_task.logging.skip_non_nature"),
TranslateUtil.getBooleanTranslate(this.currentData.skipNonNature()),
button -> {
this.currentData.skipNonNature(false);
button.setValue(TranslateUtil.getBooleanTranslate(false));
MaidConfigurePacket.send(this.maid, MaidLoggingConfig.LOCATION, "skipNonNature", "false");
},
button -> {
this.currentData.skipNonNature(true);
button.setValue(TranslateUtil.getBooleanTranslate(true));
MaidConfigurePacket.send(this.maid, MaidLoggingConfig.LOCATION, "skipNonNature", "true");
}
));
} }
} }

View File

@@ -8,8 +8,6 @@ import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import studio.fantasyit.maid_useful_task.task.MaidLocateTask;
import studio.fantasyit.maid_useful_task.task.MaidTreeTask;
import studio.fantasyit.maid_useful_task.util.MemoryUtil; import studio.fantasyit.maid_useful_task.util.MemoryUtil;
@Mixin(MaidMoveControl.class) @Mixin(MaidMoveControl.class)
@@ -20,12 +18,11 @@ abstract public class MaidMoveControlMixin {
@Inject(method = "tick", at = @At("HEAD"), cancellable = true) @Inject(method = "tick", at = @At("HEAD"), cancellable = true)
public void tick(CallbackInfo ci) { public void tick(CallbackInfo ci) {
if (maid.getTask().getUid().equals(MaidTreeTask.UID)) if (switch (MemoryUtil.getCurrent(maid)) {
if (switch (MemoryUtil.getCurrent(maid)) { case BLOCKUP_DESTROY, BLOCKUP_DOWN -> true;
case BLOCKUP_DESTROY, BLOCKUP_DOWN -> true; default -> false;
default -> false; }) {
}) { ci.cancel();
ci.cancel(); }
}
} }
} }

View File

@@ -8,7 +8,6 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import studio.fantasyit.maid_useful_task.memory.CurrentWork; import studio.fantasyit.maid_useful_task.memory.CurrentWork;
import studio.fantasyit.maid_useful_task.task.MaidTreeTask;
import studio.fantasyit.maid_useful_task.util.Conditions; import studio.fantasyit.maid_useful_task.util.Conditions;
import studio.fantasyit.maid_useful_task.util.MemoryUtil; import studio.fantasyit.maid_useful_task.util.MemoryUtil;
@@ -16,9 +15,8 @@ import studio.fantasyit.maid_useful_task.util.MemoryUtil;
abstract public class MaidRunOneMixin { abstract public class MaidRunOneMixin {
@Inject(method = "tryStart(Lnet/minecraft/server/level/ServerLevel;Lcom/github/tartaricacid/touhoulittlemaid/entity/passive/EntityMaid;J)Z", at = @At("HEAD"), cancellable = true, remap = false) @Inject(method = "tryStart(Lnet/minecraft/server/level/ServerLevel;Lcom/github/tartaricacid/touhoulittlemaid/entity/passive/EntityMaid;J)Z", at = @At("HEAD"), cancellable = true, remap = false)
public void runOne(ServerLevel pLevel, EntityMaid maid, long pGameTime, CallbackInfoReturnable<Boolean> cir) { public void runOne(ServerLevel pLevel, EntityMaid maid, long pGameTime, CallbackInfoReturnable<Boolean> cir) {
if (maid.getTask().getUid().equals(MaidTreeTask.UID)) if (!Conditions.isCurrent(maid, CurrentWork.IDLE)) {
if (!Conditions.isCurrent(maid, CurrentWork.IDLE)) { cir.setReturnValue(false);
cir.setReturnValue(false); }
}
} }
} }

View File

@@ -0,0 +1,103 @@
package studio.fantasyit.maid_useful_task.mixin;
import com.github.tartaricacid.touhoulittlemaid.entity.item.AbstractEntityFromItem;
import com.github.tartaricacid.touhoulittlemaid.entity.item.EntityBroom;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import studio.fantasyit.maid_useful_task.vehicle.IVirtualControl;
import studio.fantasyit.maid_useful_task.vehicle.MaidVehicleControlType;
@Mixin(EntityBroom.class)
abstract public class VehicleBroomMixin extends AbstractEntityFromItem implements IVirtualControl {
public VehicleBroomMixin(EntityType<? extends LivingEntity> type, Level worldIn) {
super(type, worldIn);
}
@Unique
public MaidVehicleControlType maid_useful_tasks$vc_type = MaidVehicleControlType.NONE;
@Unique
public float maid_useful_tasks$vc_xRot;
@Unique
public float maid_useful_tasks$vc_yRot;
@Unique
public float maid_useful_tasks$vc_speed;
@Override
public void maid_useful_tasks$setControlParam(float xRot, float yRot, float speed, MaidVehicleControlType type) {
this.maid_useful_tasks$vc_xRot = xRot;
this.maid_useful_tasks$vc_yRot = yRot;
this.maid_useful_tasks$vc_speed = speed;
this.maid_useful_tasks$vc_type = type;
}
@Override
public CompoundTag maid_useful_tasks$getControlParam() {
CompoundTag result = new CompoundTag();
result.putFloat("xRot", maid_useful_tasks$vc_xRot);
result.putFloat("yRot", maid_useful_tasks$vc_yRot);
result.putFloat("speed", maid_useful_tasks$vc_speed);
result.putString("type", maid_useful_tasks$vc_type.name());
return result;
}
@Override
public void maid_useful_tasks$setControlParam(CompoundTag target) {
if (target.contains("type")) {
this.maid_useful_tasks$vc_type = MaidVehicleControlType.valueOf(target.getString("type"));
}
if (target.contains("xRot")) {
this.maid_useful_tasks$vc_xRot = target.getFloat("xRot");
}
if (target.contains("yRot")) {
this.maid_useful_tasks$vc_yRot = target.getFloat("yRot");
}
if (target.contains("speed")) {
this.maid_useful_tasks$vc_speed = target.getFloat("speed");
}
}
@Override
public void maid_useful_tasks$stopControl() {
this.maid_useful_tasks$vc_type = MaidVehicleControlType.NONE;
}
@Inject(method = "tickRidden", at = @At(value = "TAIL"))
public void maid_useful_tasks$tickRidden(CallbackInfo ci) {
if (maid_useful_tasks$vc_type == MaidVehicleControlType.NONE) {
return;
}
this.setRot(maid_useful_tasks$vc_yRot, maid_useful_tasks$vc_xRot);
}
@ModifyVariable(method = "travel", at = @At(value = "STORE"), name = "strafe")
float maid_useful_tasks$travel_s(float strafe) {
if (maid_useful_tasks$vc_type != MaidVehicleControlType.FULL) {
return strafe;
}
return 0;
}
@ModifyVariable(method = "travel", at = @At(value = "STORE"), name = "vertical")
float maid_useful_tasks$travel_v(float vertical) {
if (maid_useful_tasks$vc_type != MaidVehicleControlType.FULL) {
return vertical;
}
return -(maid_useful_tasks$vc_xRot - 10.0F) / 22.5F;
}
@ModifyVariable(method = "travel", at = @At(value = "STORE"), name = "forward")
float maid_useful_tasks$travel_f(float forward) {
if (maid_useful_tasks$vc_type != MaidVehicleControlType.FULL) {
return forward;
}
return maid_useful_tasks$vc_speed;
}
}

View File

@@ -62,9 +62,8 @@ public interface IMaidBlockDestroyTask {
for (int dz : dv) { for (int dz : dv) {
if (dx == 0 && dy == 0 && dz == 0) continue; if (dx == 0 && dy == 0 && dz == 0) continue;
BlockPos target = pos.offset(dx, dy, dz); BlockPos target = pos.offset(dx, dy, dz);
// if (Math.abs(target.getX() - standPos.getX()) > maxDXZ || Math.abs(target.getZ() - standPos.getZ()) > maxDXZ) if (Math.abs(target.getX() - standPos.getX()) > maxDXZ || Math.abs(target.getZ() - standPos.getZ()) > maxDXZ)
// continue; continue;
//上代码不明所以,删除待查
if (target.distSqr(standPos) > reachDistance() * reachDistance()) continue; if (target.distSqr(standPos) > reachDistance() * reachDistance()) continue;
if (marked.contains(target)) continue; if (marked.contains(target)) continue;
if (!shouldDestroyBlock(maid, target)) continue; if (!shouldDestroyBlock(maid, target)) continue;

View File

@@ -13,8 +13,6 @@ import oshi.util.tuples.Pair;
import studio.fantasyit.maid_useful_task.util.MaidUtils; import studio.fantasyit.maid_useful_task.util.MaidUtils;
import studio.fantasyit.maid_useful_task.util.PosUtils; import studio.fantasyit.maid_useful_task.util.PosUtils;
import java.util.function.Function;
public interface IMaidBlockUpTask { public interface IMaidBlockUpTask {
default boolean isFindingBlock(EntityMaid maid, BlockPos target, BlockPos standPos) { default boolean isFindingBlock(EntityMaid maid, BlockPos target, BlockPos standPos) {
if (target.distSqr(standPos) > touchLimit() * touchLimit()) if (target.distSqr(standPos) > touchLimit() * touchLimit())
@@ -43,28 +41,16 @@ public interface IMaidBlockUpTask {
default Pair<BlockPos, BlockPos> findTargetPosBlockUp(EntityMaid maid, BlockPos center, int maxUp) { default Pair<BlockPos, BlockPos> findTargetPosBlockUp(EntityMaid maid, BlockPos center, int maxUp) {
ServerLevel level = (ServerLevel) maid.level(); ServerLevel level = (ServerLevel) maid.level();
int maxHeight = verticalOffset() + verticalDistance(); int maxHeight = verticalOffset() + verticalDistance();
boolean hasRestriction = maid.hasRestriction(); CenterOffsetBlockPosSet notAvailable = new CenterOffsetBlockPosSet(scanRange(maid), scanRange(maid) + maxHeight / 2 + 1, scanRange(maid), center.getX(), center.getY() + maxHeight / 2, center.getZ());
BlockPos restrictCenter = maid.getRestrictCenter(); MaidPathFindingBFS pathFindingBFS = new MaidPathFindingBFS(maid.getNavigation().getNodeEvaluator(), level, maid, 7, scanRange(maid));
float restrictRadius = maid.getRestrictRadius(); for (int dx = 0; dx < scanRange(maid); dx = dx <= 0 ? 1 - dx : -dx) {
int scanRange = scanRange(maid); for (int dz = 0; dz < scanRange(maid); dz = dz <= 0 ? 1 - dz : -dz) {
Function<BlockPos, Boolean> withinRestriction = (BlockPos pos) -> {
if (hasRestriction) {
return restrictCenter.distSqr(pos) < (double) (restrictRadius * restrictRadius);
} else {
return true;
}
};
CenterOffsetBlockPosSet notAvailable = new CenterOffsetBlockPosSet(scanRange, scanRange + maxHeight / 2 + 1, scanRange, center.getX(), center.getY() + maxHeight / 2, center.getZ());
MaidPathFindingBFS pathFindingBFS = new MaidPathFindingBFS(maid.getNavigation().getNodeEvaluator(), level, maid, 7, scanRange+2);
for (int dx = 0; dx < scanRange; dx = dx <= 0 ? 1 - dx : -dx) {
for (int dz = 0; dz < scanRange; dz = dz <= 0 ? 1 - dz : -dz) {
//计算地面的位置 //计算地面的位置
BlockPos.MutableBlockPos ground = center.offset(dx, 0, dz).mutable(); BlockPos.MutableBlockPos ground = center.offset(dx, 0, dz).mutable();
while (level.getBlockState(ground).canBeReplaced()) ground.move(0, -1, 0); while (level.getBlockState(ground).canBeReplaced()) ground.move(0, -1, 0);
while (!level.getBlockState(ground).canBeReplaced()) ground.move(0, 1, 0); while (!level.getBlockState(ground).canBeReplaced()) ground.move(0, 1, 0);
if (notAvailable.isVis(ground)) continue; if (notAvailable.isVis(ground)) continue;
//地面基本判断 //地面基本判断
if (!PosUtils.isSafePos(level, ground)) continue;
if (!PosUtils.isFourSideAir(level, ground.immutable())) continue; if (!PosUtils.isFourSideAir(level, ground.immutable())) continue;
if (!pathFindingBFS.canPathReach(ground)) continue; if (!pathFindingBFS.canPathReach(ground)) continue;
boolean valid = true; boolean valid = true;
@@ -97,7 +83,7 @@ public interface IMaidBlockUpTask {
for (int dy = verticalOffset(); dy < verticalDistance() + verticalOffset(); dy++) { for (int dy = verticalOffset(); dy < verticalDistance() + verticalOffset(); dy++) {
BlockPos targetPos = ground.offset(sdx, dy, sdz); BlockPos targetPos = ground.offset(sdx, dy, sdz);
if (targetPos.distSqr(standPos) > touchLimit * touchLimit) break; if (targetPos.distSqr(standPos) > touchLimit * touchLimit) break;
if (hasRestriction && !withinRestriction.apply(standPos)) break; if (maid.hasRestriction() && !maid.isWithinRestriction(standPos)) break;
if (isFindingBlock(maid, targetPos, standPos)) { if (isFindingBlock(maid, targetPos, standPos)) {
return new Pair<>(ground.immutable(), standPos); return new Pair<>(ground.immutable(), standPos);
} }
@@ -105,7 +91,7 @@ public interface IMaidBlockUpTask {
if (continuous) { if (continuous) {
if (!level.getBlockState(standPos.above().above()).isAir()) { if (!level.getBlockState(standPos.above().above()).isAir()) {
continuous = false; continuous = false;
} else if (hasRestriction && !withinRestriction.apply((standPos.above().above()))) { } else if (maid.hasRestriction() && !maid.isWithinRestriction(standPos.above())) {
continuous = false; continuous = false;
} }
} }

View File

@@ -4,30 +4,24 @@ import com.github.tartaricacid.touhoulittlemaid.api.task.IMaidTask;
import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid;
import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Pair;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.GlobalPos;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvent;
import net.minecraft.tags.ItemTags;
import net.minecraft.tags.StructureTags; import net.minecraft.tags.StructureTags;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.behavior.BehaviorControl; import net.minecraft.world.entity.ai.behavior.BehaviorControl;
import net.minecraft.world.item.CompassItem;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items; import net.minecraft.world.item.Items;
import net.minecraft.world.item.MapItem; import net.minecraft.world.item.MapItem;
import net.minecraft.world.level.saveddata.maps.MapDecoration;
import net.minecraft.world.level.saveddata.maps.MapItemSavedData; import net.minecraft.world.level.saveddata.maps.MapItemSavedData;
import net.minecraftforge.common.MinecraftForge;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import studio.fantasyit.maid_useful_task.Config; import studio.fantasyit.maid_useful_task.Config;
import studio.fantasyit.maid_useful_task.MaidUsefulTask; import studio.fantasyit.maid_useful_task.MaidUsefulTask;
import studio.fantasyit.maid_useful_task.api.ItemLocateEvent;
import studio.fantasyit.maid_useful_task.behavior.common.FindTargetMoveBehavior; import studio.fantasyit.maid_useful_task.behavior.common.FindTargetMoveBehavior;
import studio.fantasyit.maid_useful_task.behavior.common.FindTargetWaitBehavior; import studio.fantasyit.maid_useful_task.behavior.common.FindTargetWaitBehavior;
import studio.fantasyit.maid_useful_task.compat.CompatEntry;
import studio.fantasyit.maid_useful_task.util.MemoryUtil; import studio.fantasyit.maid_useful_task.util.MemoryUtil;
import java.util.ArrayList; import java.util.ArrayList;
@@ -75,14 +69,11 @@ public class MaidLocateTask implements IMaidTask, IMaidFindTargetTask {
BlockPos target = null; BlockPos target = null;
ItemStack itemStack = maid.getMainHandItem(); ItemStack itemStack = maid.getMainHandItem();
ItemStack last = MemoryUtil.getLocateItem(maid); ItemStack last = MemoryUtil.getLocateItem(maid);
if (!last.isEmpty() && !itemStack.isEmpty() && ItemStack.isSameItemSameTags(last, itemStack)) { if (!last.isEmpty() && !itemStack.isEmpty() && ItemStack.isSameItem(last, itemStack)) {
MemoryUtil.setLocateItem(maid, itemStack); MemoryUtil.setLocateItem(maid, itemStack);
MemoryUtil.clearCommonBlockCache(maid); MemoryUtil.clearCommonBlockCache(maid);
} }
ItemLocateEvent event = new ItemLocateEvent(itemStack, maid, MemoryUtil.getCommonBlockCache(maid)); if (maid.getMainHandItem().is(Items.ENDER_EYE)) {
if (MinecraftForge.EVENT_BUS.post(event)) {
target = event.getTarget();
} else if (maid.getMainHandItem().is(Items.ENDER_EYE)) {
target = MemoryUtil.getCommonBlockCache(maid); target = MemoryUtil.getCommonBlockCache(maid);
if (target == null) { if (target == null) {
BlockPos blockpos = level.findNearestMapStructure(StructureTags.EYE_OF_ENDER_LOCATED, maid.blockPosition(), 100, false); BlockPos blockpos = level.findNearestMapStructure(StructureTags.EYE_OF_ENDER_LOCATED, maid.blockPosition(), 100, false);
@@ -92,36 +83,11 @@ public class MaidLocateTask implements IMaidTask, IMaidFindTargetTask {
} }
} }
} else if (maid.getMainHandItem().is(Items.COMPASS)) { } else if (maid.getMainHandItem().is(Items.COMPASS)) {
target = MemoryUtil.getCommonBlockCache(maid);
if (target == null) {
GlobalPos globalPos;
if (CompassItem.isLodestoneCompass(itemStack)) {
globalPos = CompassItem.getLodestonePosition(itemStack.getOrCreateTag());
} else {
globalPos = CompassItem.getSpawnPosition(level);
}
if (globalPos != null && level.dimension().equals(globalPos.dimension())) {
MemoryUtil.setCommonBlockCache(maid, globalPos.pos());
target = globalPos.pos();
}
}
} else if (maid.getMainHandItem().is(ItemTags.BEDS)) {
target = MemoryUtil.getCommonBlockCache(maid); target = MemoryUtil.getCommonBlockCache(maid);
if (target == null) { if (target == null) {
LivingEntity owner = maid.getOwner(); LivingEntity owner = maid.getOwner();
if (owner instanceof ServerPlayer player) { if (owner != null) {
if (player.getRespawnDimension().equals(level.dimension())) { target = owner.getSleepingPos().orElse(maid.level().getSharedSpawnPos());
target = player.getRespawnPosition();
if (target == null) {
GlobalPos globalRespawn = CompassItem.getSpawnPosition(level);
if (globalRespawn != null && level.dimension().equals(globalRespawn.dimension())) {
target = globalRespawn.pos();
}
}
}
if (target == null) {
MemoryUtil.setCommonBlockCache(maid, target);
}
} }
} }
} else if (maid.getMainHandItem().is(Items.FILLED_MAP)) { } else if (maid.getMainHandItem().is(Items.FILLED_MAP)) {
@@ -154,11 +120,6 @@ public class MaidLocateTask implements IMaidTask, IMaidFindTargetTask {
} }
} }
} else { } else {
target = CompatEntry.getLocateTarget(maid, maid.getMainHandItem());
if (target != null) {
MemoryUtil.setCommonBlockCache(maid, target);
return target;
}
MemoryUtil.clearCommonBlockCache(maid); MemoryUtil.clearCommonBlockCache(maid);
} }
return target; return target;
@@ -169,4 +130,3 @@ public class MaidLocateTask implements IMaidTask, IMaidFindTargetTask {
MemoryUtil.clearCommonBlockCache(maid); MemoryUtil.clearCommonBlockCache(maid);
} }
} }

View File

@@ -17,6 +17,7 @@ import org.jetbrains.annotations.Nullable;
import studio.fantasyit.maid_useful_task.Config; import studio.fantasyit.maid_useful_task.Config;
import studio.fantasyit.maid_useful_task.MaidUsefulTask; import studio.fantasyit.maid_useful_task.MaidUsefulTask;
import studio.fantasyit.maid_useful_task.behavior.PlayerReviveBehavior; import studio.fantasyit.maid_useful_task.behavior.PlayerReviveBehavior;
import studio.fantasyit.maid_useful_task.behavior.SupportEffectBehavior;
import studio.fantasyit.maid_useful_task.compat.PlayerRevive; import studio.fantasyit.maid_useful_task.compat.PlayerRevive;
import studio.fantasyit.maid_useful_task.menu.MaidLoggingConfigGui; import studio.fantasyit.maid_useful_task.menu.MaidLoggingConfigGui;
import studio.fantasyit.maid_useful_task.menu.MaidReviveConfigGui; import studio.fantasyit.maid_useful_task.menu.MaidReviveConfigGui;
@@ -62,6 +63,7 @@ public class MaidRevivePlayerTask implements IMaidTask {
public List<Pair<Integer, BehaviorControl<? super EntityMaid>>> createBrainTasks(EntityMaid entityMaid) { public List<Pair<Integer, BehaviorControl<? super EntityMaid>>> createBrainTasks(EntityMaid entityMaid) {
ArrayList<Pair<Integer, BehaviorControl<? super EntityMaid>>> ret = new ArrayList<>(); ArrayList<Pair<Integer, BehaviorControl<? super EntityMaid>>> ret = new ArrayList<>();
ret.add(Pair.of(1, new PlayerReviveBehavior())); ret.add(Pair.of(1, new PlayerReviveBehavior()));
ret.add(Pair.of(1, new SupportEffectBehavior()));
return ret; return ret;
} }

View File

@@ -29,6 +29,7 @@ import studio.fantasyit.maid_useful_task.behavior.common.*;
import studio.fantasyit.maid_useful_task.data.MaidLoggingConfig; import studio.fantasyit.maid_useful_task.data.MaidLoggingConfig;
import studio.fantasyit.maid_useful_task.memory.BlockValidationMemory; import studio.fantasyit.maid_useful_task.memory.BlockValidationMemory;
import studio.fantasyit.maid_useful_task.menu.MaidLoggingConfigGui; import studio.fantasyit.maid_useful_task.menu.MaidLoggingConfigGui;
import studio.fantasyit.maid_useful_task.registry.GuiRegistry;
import studio.fantasyit.maid_useful_task.util.MaidUtils; import studio.fantasyit.maid_useful_task.util.MaidUtils;
import studio.fantasyit.maid_useful_task.util.MemoryUtil; import studio.fantasyit.maid_useful_task.util.MemoryUtil;
import studio.fantasyit.maid_useful_task.util.WrappedMaidFakePlayer; import studio.fantasyit.maid_useful_task.util.WrappedMaidFakePlayer;
@@ -39,11 +40,9 @@ import java.util.List;
import java.util.Set; import java.util.Set;
public class MaidTreeTask implements IMaidTask, IMaidBlockPlaceTask, IMaidBlockDestroyTask, IMaidBlockUpTask { public class MaidTreeTask implements IMaidTask, IMaidBlockPlaceTask, IMaidBlockDestroyTask, IMaidBlockUpTask {
public static final ResourceLocation UID = new ResourceLocation(MaidUsefulTask.MODID, "maid_tree");
@Override @Override
public ResourceLocation getUid() { public ResourceLocation getUid() {
return UID; return new ResourceLocation(MaidUsefulTask.MODID, "maid_tree");
} }
@Override @Override
@@ -90,10 +89,7 @@ public class MaidTreeTask implements IMaidTask, IMaidBlockPlaceTask, IMaidBlockD
} }
} }
BlockState blockState = maid.level().getBlockState(pos); BlockState blockState = maid.level().getBlockState(pos);
if (blockState.is(BlockTags.LOGS)) { return blockState.is(BlockTags.LOGS) && isValidNatureTree(maid, pos);
return !MaidLoggingConfig.get(maid).skipNonNature() || isValidNatureTree(maid, pos);
}
return false;
} }
@Override @Override
@@ -184,22 +180,11 @@ public class MaidTreeTask implements IMaidTask, IMaidBlockPlaceTask, IMaidBlockD
protected boolean isValidNatureTree(EntityMaid maid, BlockPos startPos) { protected boolean isValidNatureTree(EntityMaid maid, BlockPos startPos) {
HashSet<BlockPos> vis = new HashSet<>(); return isValidNatureTree(maid, startPos, new HashSet<>(), 0);
BlockValidationMemory validationMemory = MemoryUtil.getBlockValidationMemory(maid);
boolean validNatureTree = isValidNatureTree(maid, startPos, vis, 0, validationMemory);
for (BlockPos pos : vis) {
BlockState blockState = maid.level().getBlockState(pos);
if (!blockState.is(BlockTags.LEAVES) && !blockState.is(BlockTags.LOGS))
continue;
if (validNatureTree)
validationMemory.setValid(pos);
else
validationMemory.setInvalid(pos);
}
return validNatureTree;
} }
protected boolean isValidNatureTree(EntityMaid maid, BlockPos startPos, Set<BlockPos> visited, int depth, BlockValidationMemory validationMemory) { protected boolean isValidNatureTree(EntityMaid maid, BlockPos startPos, Set<BlockPos> visited, int depth) {
BlockValidationMemory validationMemory = MemoryUtil.getBlockValidationMemory(maid);
if (validationMemory.hasRecord(startPos)) if (validationMemory.hasRecord(startPos))
return validationMemory.isValid(startPos, false); return validationMemory.isValid(startPos, false);
if (visited.contains(startPos)) if (visited.contains(startPos))
@@ -216,7 +201,7 @@ public class MaidTreeTask implements IMaidTask, IMaidBlockPlaceTask, IMaidBlockD
if (blockState.is(BlockTags.LEAVES) && blockState.hasProperty(LeavesBlock.PERSISTENT) && !blockState.getValue(LeavesBlock.PERSISTENT)) { if (blockState.is(BlockTags.LEAVES) && blockState.hasProperty(LeavesBlock.PERSISTENT) && !blockState.getValue(LeavesBlock.PERSISTENT)) {
valid = true; valid = true;
} }
if (blockState.is(BlockTags.LOGS) && isValidNatureTree(maid, offset, visited, depth + 1, validationMemory)) { if (blockState.is(BlockTags.LOGS) && isValidNatureTree(maid, offset, visited, depth + 1)) {
valid = true; valid = true;
} }
} }
@@ -232,7 +217,6 @@ public class MaidTreeTask implements IMaidTask, IMaidBlockPlaceTask, IMaidBlockD
@Override @Override
public List<Pair<Integer, BehaviorControl<? super EntityMaid>>> createBrainTasks(EntityMaid entityMaid) { public List<Pair<Integer, BehaviorControl<? super EntityMaid>>> createBrainTasks(EntityMaid entityMaid) {
ArrayList<Pair<Integer, BehaviorControl<? super EntityMaid>>> list = new ArrayList<>(); ArrayList<Pair<Integer, BehaviorControl<? super EntityMaid>>> list = new ArrayList<>();
list.add(Pair.of(0, new MaidSelfRescueBehavior()));
list.add(Pair.of(1, new DestoryBlockBehavior())); list.add(Pair.of(1, new DestoryBlockBehavior()));
list.add(Pair.of(1, new DestoryBlockMoveBehavior())); list.add(Pair.of(1, new DestoryBlockMoveBehavior()));
@@ -263,10 +247,7 @@ public class MaidTreeTask implements IMaidTask, IMaidBlockPlaceTask, IMaidBlockD
public boolean isFindingBlock(EntityMaid maid, BlockPos target, BlockPos standPos) { public boolean isFindingBlock(EntityMaid maid, BlockPos target, BlockPos standPos) {
if (target.distSqr(standPos) > touchLimit() * touchLimit()) if (target.distSqr(standPos) > touchLimit() * touchLimit())
return false; return false;
if (maid.level().getBlockState(target).is(BlockTags.LOGS)) { return maid.level().getBlockState(target).is(BlockTags.LOGS) && isValidNatureTree(maid, target);
return !MaidLoggingConfig.get(maid).skipNonNature() || isValidNatureTree(maid, target);
}
return false;
} }
@Override @Override
@@ -294,7 +275,6 @@ public class MaidTreeTask implements IMaidTask, IMaidBlockPlaceTask, IMaidBlockD
/** /**
* 此处判断当home模式未开启时不允许上搭。 * 此处判断当home模式未开启时不允许上搭。
*
* @param maid * @param maid
* @param center * @param center
* @param maxUp * @param maxUp
@@ -302,8 +282,8 @@ public class MaidTreeTask implements IMaidTask, IMaidBlockPlaceTask, IMaidBlockD
*/ */
@Override @Override
public oshi.util.tuples.Pair<BlockPos, BlockPos> findTargetPosBlockUp(EntityMaid maid, BlockPos center, int maxUp) { public oshi.util.tuples.Pair<BlockPos, BlockPos> findTargetPosBlockUp(EntityMaid maid, BlockPos center, int maxUp) {
if (maid.isHomeModeEnable() && MaidLoggingConfig.get(maid).blockUp() && !Config.disableLoggingBlockUp) if (maid.isHomeModeEnable())
return IMaidBlockUpTask.super.findTargetPosBlockUp(maid, center, maxUp); return IMaidBlockUpTask.super.findTargetPosBlockUp(maid, center, maxUp);
return null; return null;
} }
} }

View File

@@ -8,12 +8,13 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.ai.memory.WalkTarget; import net.minecraft.world.entity.ai.memory.WalkTarget;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import studio.fantasyit.maid_useful_task.memory.CurrentWork; import studio.fantasyit.maid_useful_task.memory.CurrentWork;
import studio.fantasyit.maid_useful_task.registry.MemoryModuleRegistry;
import java.util.Optional; import java.util.Optional;
public class Conditions { public class Conditions {
public static boolean hasReachedValidTargetOrReset(EntityMaid maid) { public static boolean hasReachedValidTargetOrReset(EntityMaid maid) {
return hasReachedValidTargetOrReset(maid, 2.5f); return hasReachedValidTargetOrReset(maid, 2);
} }
public static boolean hasReachedValidTargetOrReset(EntityMaid maid, float closeEnough) { public static boolean hasReachedValidTargetOrReset(EntityMaid maid, float closeEnough) {
@@ -42,7 +43,7 @@ public class Conditions {
public static boolean isGlobalValidTarget(EntityMaid maid, BlockPos pos, BlockPos targetPos) { public static boolean isGlobalValidTarget(EntityMaid maid, BlockPos pos, BlockPos targetPos) {
if (MemoryUtil.getBlockUpContext(maid).hasTarget()) { if (MemoryUtil.getBlockUpContext(maid).hasTarget()) {
return pos.equals(maid.blockPosition()); return MemoryUtil.getBlockUpContext(maid).isTarget(pos);
} }
return true; return true;
} }

View File

@@ -2,8 +2,6 @@ package studio.fantasyit.maid_useful_task.util;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.shapes.CollisionContext;
public class PosUtils { public class PosUtils {
public static boolean isFourSideAir(BlockGetter level, BlockPos pos) { public static boolean isFourSideAir(BlockGetter level, BlockPos pos) {
@@ -13,17 +11,4 @@ public class PosUtils {
level.getBlockState(pos.east()).isAir() && level.getBlockState(pos.east()).isAir() &&
level.getBlockState(pos.west()).isAir(); level.getBlockState(pos.west()).isAir();
} }
static protected boolean isEmptyBlockPos(Level level, BlockPos pos) {
return level.getBlockState(pos).isAir() || level.getBlockState(pos).getCollisionShape(
level,
pos,
CollisionContext.empty()
).isEmpty();
}
static public boolean isSafePos(Level level, BlockPos pos) {
return isEmptyBlockPos(level, pos)
&& isEmptyBlockPos(level, pos.above())
&& !isEmptyBlockPos(level, pos.below());
}
} }

View File

@@ -3,11 +3,8 @@ package studio.fantasyit.maid_useful_task.vehicle;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
public interface IVirtualControl { public interface IVirtualControl {
void maid_useful_tasks$setControlParam(float xRot, float yRot, float speed, MaidVehicleControlType type); void maid_useful_tasks$setControlParam(float xRot, float yRot, float speed,MaidVehicleControlType type);
void maid_useful_tasks$stopControl(); void maid_useful_tasks$stopControl();
CompoundTag maid_useful_tasks$getControlParam(); CompoundTag maid_useful_tasks$getControlParam();
void maid_useful_tasks$setControlParam(CompoundTag target); void maid_useful_tasks$setControlParam(CompoundTag target);
} }

View File

@@ -1,11 +1,12 @@
package studio.fantasyit.maid_useful_task.vehicle; package studio.fantasyit.maid_useful_task.vehicle;
import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraftforge.network.PacketDistributor; import net.minecraftforge.network.PacketDistributor;
import studio.fantasyit.maid_useful_task.network.MaidSyncVehiclePacket; import studio.fantasyit.maid_useful_task.network.MaidSyncVehiclePacket;
import studio.fantasyit.maid_useful_task.network.Network; import studio.fantasyit.maid_useful_task.network.Network;
import studio.fantasyit.maid_useful_task.vehicle.broom.VehicleBroom; import studio.fantasyit.maid_useful_task.util.MemoryUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -40,8 +41,4 @@ public class MaidVehicleManager {
} }
}); });
} }
public static void stopControlling(EntityMaid maid) {
MaidVehicleManager.getControllableVehicle(maid).ifPresent(vehicle -> vehicle.maidStopControlVehicle(maid));
}
} }

View File

@@ -0,0 +1,60 @@
package studio.fantasyit.maid_useful_task.vehicle;
import com.github.tartaricacid.touhoulittlemaid.entity.item.EntityBroom;
import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Rotations;
import net.minecraft.nbt.CompoundTag;
import org.jetbrains.annotations.Nullable;
import studio.fantasyit.maid_useful_task.util.RotUtil;
public class VehicleBroom extends AbstractMaidControllableVehicle {
@Override
public boolean isMaidOnThisVehicle(EntityMaid maid) {
return maid.getVehicle() instanceof EntityBroom;
}
@Override
public void maidControlVehicle(EntityMaid maid, MaidVehicleControlType type, BlockPos target) {
if (maid.level().isClientSide) return;
if (maid.getVehicle() instanceof EntityBroom vehicle) {
if (type == MaidVehicleControlType.NONE) {
((IVirtualControl) vehicle).maid_useful_tasks$setControlParam(0, 0, 0, type);
return;
}
double xzDistance = maid.distanceToSqr(target.getX(), maid.getY(), target.getZ());
double finalXRot = vehicle.getXRot();
double finalYRot = vehicle.getYRot();
double finalSpeed = 0;
if (vehicle.isInWater()) {
finalXRot = -10;
} else if (xzDistance < Math.pow(maid.getY() - maid.level().getSeaLevel(), 2)) {
if (maid.getY() - maid.level().getSeaLevel() < 50 || vehicle.onGround())
finalXRot = 15;
else
finalXRot = 60;
} else if (maid.getY() < 100) {
finalXRot = -50;
} else if (maid.getY() > 160) {
finalXRot = 15;
} else {
finalXRot = 0;
}
finalYRot = RotUtil.getYRot(maid.position(), target.getCenter());
finalSpeed = type == MaidVehicleControlType.FULL ? 3.0 : 0;
if (xzDistance < 5 * 5 && (vehicle.onGround() || vehicle.isInWater()))
finalSpeed = 0;
((IVirtualControl) vehicle).maid_useful_tasks$setControlParam((float) finalXRot, (float) finalYRot, (float) finalSpeed, type);
}
}
@Override
public void maidStopControlVehicle(EntityMaid maid) {
EntityBroom vehicle = (EntityBroom) maid.getVehicle();
if (vehicle instanceof IVirtualControl ivc)
ivc.maid_useful_tasks$stopControl();
}
}

View File

@@ -1,52 +0,0 @@
package studio.fantasyit.maid_useful_task.vehicle.broom;
import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid;
import net.minecraft.nbt.CompoundTag;
import studio.fantasyit.maid_useful_task.vehicle.MaidVehicleControlType;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class BroomControlParamStore {
public record BroomControlParam(float xRot, float yRot, float vertical, float forward,
MaidVehicleControlType type) {
public static BroomControlParam fromNbt(CompoundTag tag) {
return new BroomControlParam(
tag.getFloat("xRot"),
tag.getFloat("yRot"),
tag.getFloat("vertical"),
tag.getFloat("forward"),
MaidVehicleControlType.valueOf(tag.getString("type"))
);
}
public CompoundTag toNbt() {
CompoundTag tag = new CompoundTag();
tag.putFloat("xRot", xRot);
tag.putFloat("yRot", yRot);
tag.putFloat("vertical", vertical);
tag.putFloat("forward", forward);
tag.putString("type", type.name());
return tag;
}
}
private static final BroomControlParam NONE = new BroomControlParam(0, 0, 0, 0, MaidVehicleControlType.NONE);
private static final Map<UUID, BroomControlParam> store = new HashMap<>();
public static void setControlParam(EntityMaid maid, BroomControlParam param) {
store.put(maid.getUUID(), param);
}
public static BroomControlParam getControlParam(EntityMaid maid) {
if (!store.containsKey(maid.getUUID()))
return NONE;
return store.get(maid.getUUID());
}
public static void removeControlParam(EntityMaid maid) {
store.remove(maid.getUUID());
}
}

View File

@@ -1,70 +0,0 @@
package studio.fantasyit.maid_useful_task.vehicle.broom;
import com.github.tartaricacid.touhoulittlemaid.api.entity.IBroomControl;
import com.github.tartaricacid.touhoulittlemaid.entity.item.EntityBroom;
import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.Vec3;
import studio.fantasyit.maid_useful_task.vehicle.MaidVehicleControlType;
public class BroomController implements IBroomControl {
private final EntityBroom broom;
public BroomController(EntityBroom broom) {
this.broom = broom;
}
@Override
public int getPriority() {
return 10;
}
@Override
public boolean inControl(Player player, EntityMaid entityMaid) {
return BroomControlParamStore.getControlParam(entityMaid).type() != MaidVehicleControlType.NONE;
}
@Override
public void travel(Player player, EntityMaid entityMaid) {
BroomControlParamStore.BroomControlParam param = BroomControlParamStore.getControlParam(entityMaid);
float forward = 0;
float strafe = 0;
float vertical = param.vertical();
if (param.type() == MaidVehicleControlType.FULL) {
forward = param.forward() / 15.0f;
} else {
boolean keyForward = player.zza > 0;
boolean keyBack = player.zza < 0;
boolean keyLeft = player.xxa > 0;
boolean keyRight = player.xxa < 0;
if (keyForward || keyBack || keyLeft || keyRight) {
strafe = keyLeft ? 0.2f : (keyRight ? -0.2f : 0);
forward = keyForward ? 0.375f : (keyBack ? -0.2f : 0);
} else {
vertical = 0;
}
}
//来自PlayerBroomControl
double playerSpeed = player.getAttributeValue(Attributes.MOVEMENT_SPEED);
double speed = Math.max(playerSpeed - 0.1, 0) * 2.5 + 0.1;
Vec3 targetMotion = new Vec3(strafe, vertical, forward).scale(speed * 20);
targetMotion = targetMotion.yRot((float) (-broom.getYRot() * Math.PI / 180.0));
// 插值到目标速度,而不是直接累加
Vec3 currentMotion = broom.getDeltaMovement();
Vec3 newMotion = currentMotion.lerp(targetMotion, 0.25f);
broom.setDeltaMovement(newMotion);
}
@Override
public void tickRot(Player player, EntityMaid entityMaid) {
BroomControlParamStore.BroomControlParam param = BroomControlParamStore.getControlParam(entityMaid);
broom.yRotO = broom.yBodyRot = broom.yHeadRot = broom.getYRot();
broom.setRot(param.yRot(), param.xRot());
}
}

View File

@@ -1,79 +0,0 @@
package studio.fantasyit.maid_useful_task.vehicle.broom;
import com.github.tartaricacid.touhoulittlemaid.entity.item.EntityBroom;
import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import org.jetbrains.annotations.Nullable;
import studio.fantasyit.maid_useful_task.util.RotUtil;
import studio.fantasyit.maid_useful_task.vehicle.AbstractMaidControllableVehicle;
import studio.fantasyit.maid_useful_task.vehicle.MaidVehicleControlType;
public class VehicleBroom extends AbstractMaidControllableVehicle {
@Override
public boolean isMaidOnThisVehicle(EntityMaid maid) {
return maid.getVehicle() instanceof EntityBroom;
}
@Override
public void maidControlVehicle(EntityMaid maid, MaidVehicleControlType type, BlockPos target) {
if (maid.level().isClientSide) return;
if (maid.getVehicle() instanceof EntityBroom vehicle) {
if (type == MaidVehicleControlType.NONE) {
BroomControlParamStore.removeControlParam(maid);
return;
}
double xzDistance = maid.distanceToSqr(target.getX(), maid.getY(), target.getZ());
double finalXRot = vehicle.getXRot();
double finalYRot = vehicle.getYRot();
double finalVertical = 0;
double finalForward;
if (vehicle.isInWater()) {
finalXRot = 0;
finalVertical = 0.1;
} else if (xzDistance < Math.pow(maid.getY() - maid.level().getSeaLevel(), 2)) {
finalXRot = 0;
if (maid.getY() - maid.level().getSeaLevel() < 50 || vehicle.onGround()) {
finalXRot = 5;
finalVertical = -0.2;
} else {
finalXRot = 50;
finalVertical = -0.35;
}
} else if (maid.getY() < 100) {
finalXRot = -50;
finalVertical = 0.2;
} else if (maid.getY() > 160) {
finalXRot = 0;
finalVertical = -0.1;
} else {
finalXRot = 0;
finalVertical = 0.05;
}
finalYRot = RotUtil.getYRot(maid.position(), target.getCenter());
finalForward = type == MaidVehicleControlType.FULL ? 3.0 : 0;
if (xzDistance < 5 * 5)
finalForward = 0;
BroomControlParamStore.setControlParam(maid, new BroomControlParamStore.BroomControlParam((float) finalXRot, (float) finalYRot, (float) finalVertical, (float) finalForward, type));
}
}
@Override
public void maidStopControlVehicle(EntityMaid maid) {
BroomControlParamStore.removeControlParam(maid);
}
@Override
public void syncVehicleParameter(EntityMaid maid, CompoundTag tag) {
BroomControlParamStore.BroomControlParam broomControlParam = BroomControlParamStore.BroomControlParam.fromNbt(tag);
BroomControlParamStore.setControlParam(maid, broomControlParam);
}
@Override
public @Nullable CompoundTag getSyncVehicleParameter(EntityMaid maid) {
return BroomControlParamStore.getControlParam(maid).toNbt();
}
}

View File

@@ -67,7 +67,7 @@ description='''${mod_description}'''
[[dependencies."${mod_id}"]] [[dependencies."${mod_id}"]]
modId="touhou_little_maid" modId="touhou_little_maid"
mandatory=true mandatory=true
versionRange="[1.3.7,)" versionRange="[1.2.2,)"
ordering="AFTER" ordering="AFTER"
side="BOTH" side="BOTH"
[[dependencies."${mod_id}"]] [[dependencies."${mod_id}"]]

View File

@@ -13,7 +13,5 @@
"gui.maid_useful_task.logging.plant": "Plant Saplings", "gui.maid_useful_task.logging.plant": "Plant Saplings",
"gui.maid_useful_task.no": "No", "gui.maid_useful_task.no": "No",
"gui.maid_useful_task.yes": "Yes", "gui.maid_useful_task.yes": "Yes",
"gui.maid_useful_task.revive.ownerOnly": "Only revive owner", "gui.maid_useful_task.revive.ownerOnly": "Only revive owner"
"gui.maid_useful_task.logging.block_up": "Block Up",
"gui.maid_useful_task.logging.skip_non_nature": "Skip Non-nature Logs"
} }

View File

@@ -1,19 +1,17 @@
{ {
"task.maid_useful_task.maid_tree": "伐木",
"task.maid_useful_task.maid_tree.desc": "女仆会砍伐身边的原木并种下树苗",
"task.maid_useful_task.locate": "定位",
"task.maid_useful_task.locate.desc": "女仆会根据手持物品定位指定的结构或你的出生点",
"task.maid_useful_task.revive_player": "救援玩家",
"task.maid_useful_task.revive_player.desc": "女仆会救援附近倒地的玩家",
"key.maid_useful_tasks.switch_vehicle_control": "切换载具控制模式",
"maid_useful_task.allow_handle_vehicle.none": "不允许女仆控制载具",
"maid_useful_task.allow_handle_vehicle.rot_only": "只允许女仆控制旋转",
"maid_useful_task.allow_handle_vehicle.full": "允许女仆控制载具",
"key.maid_useful_tasks.categories.main": "女仆实用任务",
"gui.maid_useful_task.logging.plant": "种植树苗", "gui.maid_useful_task.logging.plant": "种植树苗",
"gui.maid_useful_task.no": "否", "gui.maid_useful_task.no": "否",
"gui.maid_useful_task.yes": "是",
"gui.maid_useful_task.revive.ownerOnly": "只救援主人", "gui.maid_useful_task.revive.ownerOnly": "只救援主人",
"gui.maid_useful_task.logging.block_up": "上搭方块", "gui.maid_useful_task.yes": "",
"gui.maid_useful_task.logging.skip_non_nature": "跳过非自然原木" "key.maid_useful_tasks.categories.main": "女仆实用任务",
"key.maid_useful_tasks.switch_vehicle_control": "切换载具控制模式",
"maid_useful_task.allow_handle_vehicle.full": "允许女仆控制载具",
"maid_useful_task.allow_handle_vehicle.none": "不允许女仆控制载具",
"maid_useful_task.allow_handle_vehicle.rot_only": "只允许女仆控制旋转",
"task.maid_useful_task.locate": "定位",
"task.maid_useful_task.locate.desc": "女仆会根据手持物品定位指定的结构或你的出生点",
"task.maid_useful_task.maid_tree": "伐木",
"task.maid_useful_task.maid_tree.desc": "女仆会砍伐身边的原木并种下树苗",
"task.maid_useful_task.revive_player": "救援玩家",
"task.maid_useful_task.revive_player.desc": "女仆会救援附近倒地的玩家"
} }

View File

@@ -8,7 +8,8 @@
"FollowMaidMixin", "FollowMaidMixin",
"MaidCheckPickupItem", "MaidCheckPickupItem",
"MaidMoveControlMixin", "MaidMoveControlMixin",
"MaidRunOneMixin" "MaidRunOneMixin",
"VehicleBroomMixin"
], ],
"client": [ "client": [
], ],