玩家救援联动

This commit is contained in:
xypp
2025-04-30 14:20:12 +08:00
parent a330813d38
commit ecddd67a18
20 changed files with 539 additions and 10 deletions

View File

@@ -0,0 +1,46 @@
package studio.fantasyit.maid_useful_task;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
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.
// Demonstrates how to use Forge's config APIs
@Mod.EventBusSubscriber(modid = MaidUsefulTask.MODID, bus = Mod.EventBusSubscriber.Bus.MOD)
public class Config {
private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();
private static final ForgeConfigSpec.BooleanValue ENABLE_LOGGING = BUILDER
.define("functions.logging", true);
private static final ForgeConfigSpec.BooleanValue ENABLE_REVIVE = BUILDER
.define("functions.revive", true);
private static final ForgeConfigSpec.BooleanValue ENABLE_LOCATE = BUILDER
.define("functions.locate", true);
private static final ForgeConfigSpec.BooleanValue ENABLE_REVIVE_AGGRO = BUILDER
.define("revive.aggro", false);
private static final ForgeConfigSpec.BooleanValue ENABLE_REVIVE_TOTEM = BUILDER
.define("revive.totem", true);
static final ForgeConfigSpec SPEC = BUILDER.build();
public static boolean enableLoggingTask = false;
public static boolean enableReviveTask = false;
public static boolean enableLocateTask = false;
public static boolean enableReviveAggro = false;
public static boolean enableReviveTotem = false;
@SubscribeEvent
static void onLoad(final ModConfigEvent event) {
enableLoggingTask = ENABLE_LOGGING.get();
enableReviveTask = ENABLE_REVIVE.get();
enableLocateTask = ENABLE_LOCATE.get();
enableReviveAggro = ENABLE_REVIVE_AGGRO.get();
enableReviveTotem = ENABLE_REVIVE_TOTEM.get();
}
}

View File

@@ -42,6 +42,7 @@ public class MaidUsefulTask {
@SuppressWarnings("removal")
public MaidUsefulTask() {
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.SPEC);
MemoryModuleRegistry.register(modEventBus);
GuiRegistry.init(modEventBus);
MaidVehicleManager.register();

View File

@@ -7,10 +7,13 @@ import com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.ExtraMaidBrainMa
import com.github.tartaricacid.touhoulittlemaid.entity.data.TaskDataRegister;
import com.github.tartaricacid.touhoulittlemaid.entity.task.TaskManager;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import studio.fantasyit.maid_useful_task.compat.PlayerRevive;
import studio.fantasyit.maid_useful_task.data.MaidConfigKeys;
import studio.fantasyit.maid_useful_task.data.MaidLoggingConfig;
import studio.fantasyit.maid_useful_task.data.MaidReviveConfig;
import studio.fantasyit.maid_useful_task.registry.MemoryModuleRegistry;
import studio.fantasyit.maid_useful_task.task.MaidLocateTask;
import studio.fantasyit.maid_useful_task.task.MaidRevivePlayerTask;
import studio.fantasyit.maid_useful_task.task.MaidTreeTask;
import java.util.List;
@@ -20,8 +23,13 @@ public class UsefulTaskExtension implements ILittleMaid {
@Override
public void addMaidTask(TaskManager manager) {
ILittleMaid.super.addMaidTask(manager);
manager.add(new MaidTreeTask());
manager.add(new MaidLocateTask());
if (Config.enableLoggingTask)
manager.add(new MaidTreeTask());
if (Config.enableLocateTask)
manager.add(new MaidLocateTask());
if (Config.enableReviveTask)
if (PlayerRevive.isEnable())
manager.add(new MaidRevivePlayerTask());
}
@Override
@@ -48,5 +56,8 @@ public class UsefulTaskExtension implements ILittleMaid {
MaidConfigKeys.addKey(MaidLoggingConfig.LOCATION,
MaidLoggingConfig.KEY = register.register(new MaidLoggingConfig()),
MaidLoggingConfig.Data::getDefault);
MaidConfigKeys.addKey(MaidReviveConfig.LOCATION,
MaidReviveConfig.KEY = register.register(new MaidReviveConfig()),
MaidReviveConfig.Data::getDefault);
}
}

View File

@@ -0,0 +1,185 @@
package studio.fantasyit.maid_useful_task.behavior;
import com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.sensor.MaidNearestLivingEntitySensor;
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.InteractionHand;
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.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 PlayerReviveBehavior extends Behavior<EntityMaid> {
protected static class TryAttackMaidGoal extends TargetGoal {
private final EntityMaid maid;
public TryAttackMaidGoal(Mob p_26140_, EntityMaid maid) {
super(p_26140_, true);
this.maid = maid;
}
@Override
public boolean canUse() {
return mob.canAttack(maid);
}
@Override
public void start() {
mob.setTarget(maid);
super.start();
}
public boolean isMaid(EntityMaid maid) {
return maid.getUUID().equals(this.maid.getUUID());
}
}
public PlayerReviveBehavior() {
super(Map.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.VALUE_PRESENT), 600);
}
@Override
protected boolean checkExtraStartConditions(ServerLevel p_22538_, EntityMaid maid) {
Optional<NearestVisibleLivingEntities> memory = maid.getBrain().getMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES);
return memory.map(list -> list
.find(entity -> entity instanceof Player)
.map(ep -> PlayerReviveServer.getBleeding((ServerPlayer) ep))
.anyMatch(IBleeding::isBleeding)
).orElse(false);
}
ServerPlayer targetPlayer;
IBleeding bleeding;
boolean startedRevive;
Set<UUID> aggroEntities;
@Override
protected void start(ServerLevel level, EntityMaid maid, long p_22542_) {
super.start(level, maid, p_22542_);
aggroEntities = new HashSet<>();
startedRevive = false;
boolean ownerOnly = maid.getOrCreateData(MaidReviveConfig.KEY, MaidReviveConfig.Data.getDefault()).ownerOnly();
LivingEntity owner = maid.getOwner();
Optional<NearestVisibleLivingEntities> memory = maid.getBrain().getMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES);
targetPlayer = memory.flatMap(list -> list
.find(entity -> entity instanceof Player)
.map(ep -> (ServerPlayer) ep)
.filter(sp -> (owner != null && sp.is(owner)) || !ownerOnly)
.filter(ep -> PlayerReviveServer.getBleeding(ep).isBleeding())
.findFirst()
).orElse(null);
if (targetPlayer != null) {
bleeding = PlayerReviveServer.getBleeding(targetPlayer);
BehaviorUtils.setWalkAndLookTargetMemories(maid, targetPlayer, 0.5f, 2);
}
useTotemOfUndying(level, maid);
}
private void useTotemOfUndying(ServerLevel level, EntityMaid maid) {
if (!Config.enableReviveTotem) return;
ItemStack itemstack = InvUtil.tryExtractOneMatches(maid.getMaidBauble(), (stack) -> stack.is(Items.TOTEM_OF_UNDYING));
if (!itemstack.isEmpty()) {
targetPlayer.awardStat(Stats.ITEM_USED.get(Items.TOTEM_OF_UNDYING), 1);
CriteriaTriggers.USED_TOTEM.trigger(targetPlayer, itemstack);
targetPlayer.setHealth(1.0F);
targetPlayer.removeAllEffects();
targetPlayer.addEffect(new MobEffectInstance(MobEffects.REGENERATION, 900, 1));
targetPlayer.addEffect(new MobEffectInstance(MobEffects.ABSORPTION, 100, 1));
targetPlayer.addEffect(new MobEffectInstance(MobEffects.FIRE_RESISTANCE, 800, 0));
level.broadcastEntityEvent(targetPlayer, (byte) 35);
PlayerReviveServer.revive(targetPlayer);
}
}
private void checkCanReviveAndStartRevive(ServerLevel level, EntityMaid maid) {
if (PlayerRevive.CONFIG.revive.needReviveItem) {
if (PlayerRevive.CONFIG.revive.consumeReviveItem && !bleeding.isItemConsumed()) {
ItemStack extractedForConsume = InvUtil.tryExtractOneMatches(maid.getAvailableInv(true), PlayerRevive.CONFIG.revive.reviveItem::is);
if (!PlayerRevive.CONFIG.revive.reviveItem.is(extractedForConsume)) {
targetPlayer = null;
return;
}
bleeding.setItemConsumed();
}
}
PlayerReviveServer.removePlayerAsHelper(WrappedMaidFakePlayer.get(maid));
bleeding.revivingPlayers().add(WrappedMaidFakePlayer.get(maid));
aggroEntitiesAround(level, maid);
}
@Override
protected boolean canStillUse(ServerLevel p_22545_, EntityMaid maid, long p_22547_) {
if (targetPlayer == null) return false;
if (targetPlayer.distanceTo(maid) > PlayerRevive.CONFIG.revive.maxDistance) return false;
return bleeding.isBleeding();
}
protected void aggroEntitiesAround(ServerLevel level, EntityMaid maid) {
if (!Config.enableReviveAggro) return;
List<Monster> entities = level.getEntities(EntityTypeTest.forClass(Monster.class),
AABB.ofSize(maid.position(), 16, 16, 16),
entity -> true
);
for (Monster entity : entities) {
if (!aggroEntities.contains(entity.getUUID())) {
entity.targetSelector.addGoal(10, new TryAttackMaidGoal(entity, maid));
aggroEntities.add(entity.getUUID());
}
}
}
@Override
protected void tick(ServerLevel level, EntityMaid maid, long p_22553_) {
super.tick(level, maid, p_22553_);
if (p_22553_ % 20 == 0)
BehaviorUtils.setWalkAndLookTargetMemories(maid, targetPlayer, 0.5f, 2);
if (!startedRevive) {
if (maid.distanceTo(targetPlayer) < PlayerRevive.CONFIG.revive.maxDistance) {
checkCanReviveAndStartRevive(level, maid);
startedRevive = true;
}
} else {
if (p_22553_ % 20 == 0)
aggroEntitiesAround(level, maid);
}
}
@Override
protected void stop(ServerLevel p_22548_, EntityMaid maid, long p_22550_) {
PlayerReviveServer.removePlayerAsHelper(WrappedMaidFakePlayer.get(maid));
for (UUID uuid : aggroEntities) {
Entity entity = p_22548_.getEntity(uuid);
if (entity instanceof Monster monster && entity.isAlive())
monster.targetSelector.removeAllGoals(g -> g instanceof TryAttackMaidGoal tg && tg.isMaid(maid));
}
}
}

View File

@@ -0,0 +1,9 @@
package studio.fantasyit.maid_useful_task.compat;
import net.minecraftforge.fml.ModList;
public class PlayerRevive {
public static boolean isEnable(){
return ModList.get().isLoaded("playerrevive");
}
}

View File

@@ -0,0 +1,58 @@
package studio.fantasyit.maid_useful_task.data;
import com.github.tartaricacid.touhoulittlemaid.api.entity.data.TaskDataKey;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import studio.fantasyit.maid_useful_task.MaidUsefulTask;
public class MaidReviveConfig implements TaskDataKey<MaidReviveConfig.Data> {
public static final class Data implements IConfigSetter {
private boolean ownerOnly;
public Data(boolean ownerOnly) {
this.ownerOnly = ownerOnly;
}
public static Data getDefault() {
return new Data(false);
}
public boolean ownerOnly() {
return ownerOnly;
}
public void ownerOnly(boolean ownerOnly) {
this.ownerOnly = ownerOnly;
}
@Override
public void setConfigValue(String name, String value) {
switch (name) {
case "ownerOnly":
ownerOnly = Boolean.parseBoolean(value);
break;
}
}
}
public static TaskDataKey<Data> KEY = null;
public static final ResourceLocation LOCATION = new ResourceLocation(MaidUsefulTask.MODID, "revive");
@Override
public ResourceLocation getKey() {
return LOCATION;
}
@Override
public CompoundTag writeSaveData(Data data) {
CompoundTag tag = new CompoundTag();
tag.putBoolean("ownerOnly", data.ownerOnly);
return tag;
}
@Override
public Data readSaveData(CompoundTag compound) {
boolean plant = compound.getBoolean("ownerOnly");
return new Data(plant);
}
}

View File

@@ -0,0 +1,53 @@
package studio.fantasyit.maid_useful_task.menu;
import com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.task.MaidTaskConfigGui;
import com.github.tartaricacid.touhoulittlemaid.client.gui.widget.button.MaidConfigButton;
import com.github.tartaricacid.touhoulittlemaid.inventory.container.task.TaskConfigContainer;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
import studio.fantasyit.maid_useful_task.data.MaidLoggingConfig;
import studio.fantasyit.maid_useful_task.data.MaidReviveConfig;
import studio.fantasyit.maid_useful_task.network.MaidConfigurePacket;
import studio.fantasyit.maid_useful_task.registry.GuiRegistry;
import studio.fantasyit.maid_useful_task.util.TranslateUtil;
public class MaidReviveConfigGui extends MaidTaskConfigGui<MaidReviveConfigGui.Container> {
private MaidReviveConfig.Data currentData;
public MaidReviveConfigGui(Container screenContainer, Inventory inv, Component titleIn) {
super(screenContainer, inv, titleIn);
}
public static class Container extends TaskConfigContainer {
public Container(int id, Inventory inventory, int entityId) {
super(GuiRegistry.MAID_LOGGING_CONFIG_GUI.get(), id, inventory, entityId);
}
}
@Override
protected void initAdditionData() {
this.currentData = this.maid.getOrCreateData(MaidReviveConfig.KEY, MaidReviveConfig.Data.getDefault());
}
@Override
protected void initAdditionWidgets() {
super.initAdditionWidgets();
int startLeft = leftPos + 87;
int startTop = topPos + 36;
this.addRenderableWidget(new MaidConfigButton(startLeft, startTop + 0,
Component.translatable("gui.maid_useful_task.revive.ownerOnly"),
TranslateUtil.getBooleanTranslate(this.currentData.ownerOnly()),
button -> {
this.currentData.ownerOnly(false);
button.setValue(TranslateUtil.getBooleanTranslate(false));
MaidConfigurePacket.send(this.maid, MaidReviveConfig.LOCATION, "ownerOnly", "false");
},
button -> {
this.currentData.ownerOnly(true);
button.setValue(TranslateUtil.getBooleanTranslate(true));
MaidConfigurePacket.send(this.maid, MaidReviveConfig.LOCATION, "ownerOnly", "true");
}
));
}
}

View File

@@ -7,6 +7,7 @@ import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import studio.fantasyit.maid_useful_task.MaidUsefulTask;
import studio.fantasyit.maid_useful_task.menu.MaidLoggingConfigGui;
import studio.fantasyit.maid_useful_task.menu.MaidReviveConfigGui;
@Mod.EventBusSubscriber(modid = MaidUsefulTask.MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
public class ClientGuiRegistry {
@@ -15,5 +16,8 @@ public class ClientGuiRegistry {
event.enqueueWork(() -> {
MenuScreens.register(GuiRegistry.MAID_LOGGING_CONFIG_GUI.get(), MaidLoggingConfigGui::new);
});
event.enqueueWork(() -> {
MenuScreens.register(GuiRegistry.MAID_REVIVE_CONFIG_GUI.get(), MaidReviveConfigGui::new);
});
}
}

View File

@@ -8,11 +8,14 @@ import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
import studio.fantasyit.maid_useful_task.MaidUsefulTask;
import studio.fantasyit.maid_useful_task.menu.MaidLoggingConfigGui;
import studio.fantasyit.maid_useful_task.menu.MaidReviveConfigGui;
public class GuiRegistry {
public static final DeferredRegister<MenuType<?>> MENU_TYPES = DeferredRegister.create(ForgeRegistries.MENU_TYPES, MaidUsefulTask.MODID);
public static final RegistryObject<MenuType<MaidLoggingConfigGui.Container>> MAID_LOGGING_CONFIG_GUI = MENU_TYPES.register("maid_logging_config_gui",
() -> IForgeMenuType.create((windowId, inv, data) -> new MaidLoggingConfigGui.Container(windowId, inv, data.readInt())));
public static final RegistryObject<MenuType<MaidReviveConfigGui.Container>> MAID_REVIVE_CONFIG_GUI = MENU_TYPES.register("maid_revive_config_gui",
() -> IForgeMenuType.create((windowId, inv, data) -> new MaidReviveConfigGui.Container(windowId, inv, data.readInt())));
public static void init(IEventBus modEventBus) {
MENU_TYPES.register(modEventBus);

View File

@@ -13,6 +13,7 @@ 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.Config;
import studio.fantasyit.maid_useful_task.MaidUsefulTask;
import studio.fantasyit.maid_useful_task.behavior.common.FindTargetMoveBehavior;
import studio.fantasyit.maid_useful_task.behavior.common.FindTargetWaitBehavior;
@@ -52,7 +53,10 @@ public class MaidLocateTask implements IMaidTask, IMaidFindTargetTask {
public boolean enableLookAndRandomWalk(EntityMaid maid) {
return false;
}
@Override
public boolean isEnable(EntityMaid maid) {
return Config.enableLocateTask;
}
@Override
public @Nullable BlockPos findTarget(ServerLevel level, EntityMaid maid) {
BlockPos target = null;

View File

@@ -0,0 +1,83 @@
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.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.entity.ai.behavior.BehaviorControl;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import org.jetbrains.annotations.Nullable;
import studio.fantasyit.maid_useful_task.Config;
import studio.fantasyit.maid_useful_task.MaidUsefulTask;
import studio.fantasyit.maid_useful_task.behavior.PlayerReviveBehavior;
import studio.fantasyit.maid_useful_task.compat.PlayerRevive;
import studio.fantasyit.maid_useful_task.menu.MaidLoggingConfigGui;
import studio.fantasyit.maid_useful_task.menu.MaidReviveConfigGui;
import java.util.ArrayList;
import java.util.List;
public class MaidRevivePlayerTask implements IMaidTask {
public static final ResourceLocation UID = new ResourceLocation(MaidUsefulTask.MODID, "revive_player");
@Override
public ResourceLocation getUid() {
return UID;
}
@Override
public ItemStack getIcon() {
return Items.ENCHANTED_GOLDEN_APPLE.getDefaultInstance();
}
@Nullable
@Override
public SoundEvent getAmbientSound(EntityMaid entityMaid) {
return null;
}
@Override
public boolean isEnable(EntityMaid maid) {
return PlayerRevive.isEnable() && Config.enableReviveAggro;
}
@Override
public boolean enableLookAndRandomWalk(EntityMaid maid) {
return false;
}
@Override
public boolean enablePanic(EntityMaid maid) {
return false;
}
@Override
public List<Pair<Integer, BehaviorControl<? super EntityMaid>>> createBrainTasks(EntityMaid entityMaid) {
ArrayList<Pair<Integer, BehaviorControl<? super EntityMaid>>> ret = new ArrayList<>();
ret.add(Pair.of(1, new PlayerReviveBehavior()));
return ret;
}
@Override
public MenuProvider getTaskConfigGuiProvider(EntityMaid maid) {
return new MenuProvider() {
@Override
public Component getDisplayName() {
return Component.literal("");
}
@Override
public AbstractContainerMenu createMenu(int index, Inventory playerInventory, Player player) {
return new MaidReviveConfigGui.Container(index, playerInventory, maid.getId());
}
};
}
}

View File

@@ -23,6 +23,7 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import studio.fantasyit.maid_useful_task.Config;
import studio.fantasyit.maid_useful_task.MaidUsefulTask;
import studio.fantasyit.maid_useful_task.behavior.common.*;
import studio.fantasyit.maid_useful_task.data.MaidLoggingConfig;
@@ -60,6 +61,11 @@ public class MaidTreeTask implements IMaidTask, IMaidBlockPlaceTask, IMaidBlockD
return null;
}
@Override
public boolean isEnable(EntityMaid maid) {
return Config.enableLoggingTask;
}
@Override
public MenuProvider getTaskConfigGuiProvider(EntityMaid maid) {
return new MenuProvider() {

View File

@@ -0,0 +1,31 @@
package studio.fantasyit.maid_useful_task.util;
import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class InvUtil {
public static ItemStack tryExtractOneMatches(IItemHandler inv, Predicate<ItemStack> predicate) {
int count = 0;
for (int i = 0; i < inv.getSlots(); i++) {
ItemStack stackInSlot = inv.getStackInSlot(i);
if(stackInSlot.isEmpty()) continue;
if (predicate.test(stackInSlot)) {
ItemStack get = inv.extractItem(i, 1, false);
if (!get.isEmpty()) {
return get;
}
}
}
return ItemStack.EMPTY;
}
}

View File

@@ -210,6 +210,24 @@ public class WrappedMaidFakePlayer extends FakePlayer {
return maid.position();
}
@Override
public float distanceTo(Entity p_20271_) {
if (maid == null) return super.distanceTo(p_20271_);
return maid.distanceTo(p_20271_);
}
@Override
public double distanceToSqr(double p_20276_, double p_20277_, double p_20278_) {
if (maid == null) return super.distanceToSqr(p_20276_, p_20277_, p_20278_);
return maid.distanceToSqr(p_20276_, p_20277_, p_20278_);
}
@Override
public double distanceToSqr(Vec3 p_20239_) {
if (maid == null) return super.distanceToSqr(p_20239_);
return maid.distanceToSqr(p_20239_);
}
@Override
public void teleportTo(double p_8969_, double p_8970_, double p_8971_) {
if (maid == null) return;

View File

@@ -3,6 +3,8 @@
"task.maid_useful_task.maid_tree.description": "The maid will cut down the logs around her and plant saplings.",
"task.maid_useful_task.locate": "Locate",
"task.maid_useful_task.locate.description": "The maid can locate the some structure or your home with specific items.",
"task.maid_useful_task.revive_player": "Revive Player",
"task.maid_useful_task.revive_player.description": "The maid will revive nearby bleeding player.",
"key.maid_useful_tasks.switch_vehicle_control": "Switch Vehicle Control Mode",
"maid_useful_task.allow_handle_vehicle.none": "Not allowing maid control vehicle",
"maid_useful_task.allow_handle_vehicle.rot_only": "Allow maid control rotation only",
@@ -10,5 +12,6 @@
"key.maid_useful_tasks.categories.main": "Maid Useful Tasks",
"gui.maid_useful_task.logging.plant": "Plant Saplings",
"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"
}

View File

@@ -1,4 +1,8 @@
{
"gui.maid_useful_task.logging.plant": "种植树苗",
"gui.maid_useful_task.no": "否",
"gui.maid_useful_task.revive.ownerOnly": "Only revive owner",
"gui.maid_useful_task.yes": "是",
"key.maid_useful_tasks.categories.main": "女仆实用任务",
"key.maid_useful_tasks.switch_vehicle_control": "切换载具控制模式",
"maid_useful_task.allow_handle_vehicle.full": "允许女仆控制载具",
@@ -7,5 +11,7 @@
"task.maid_useful_task.locate": "定位",
"task.maid_useful_task.locate.description": "女仆会根据手持物品定位指定的结构或你的出生点",
"task.maid_useful_task.maid_tree": "伐木",
"task.maid_useful_task.maid_tree.description": "女仆会砍伐身边的原木并种下树苗"
"task.maid_useful_task.maid_tree.description": "女仆会砍伐身边的原木并种下树苗",
"task.maid_useful_task.revive_player": "救援玩家",
"task.maid_useful_task.revive_player.description": "女仆会救援附近倒地的玩家"
}