weeeee
This commit is contained in:
parent
c1de6e5ac4
commit
bfc37b3b61
@ -6,7 +6,7 @@ minecraft_version=1.21.4
|
||||
yarn_mappings=1.21.4+build.8
|
||||
loader_version=0.16.10
|
||||
# Mod Properties
|
||||
mod_version=1.14.514.004
|
||||
mod_version=1.14.514.006
|
||||
maven_group=com.example
|
||||
archives_base_name=autocrossbow
|
||||
# Dependencies
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https://mirrors.aliyun.com/macports/distfiles/gradle/gradle-8.14.1-bin.zip
|
||||
distributionUrl=https://mirrors.aliyun.com/macports/distfiles/gradle/gradle-8.14.3-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
@ -1,46 +1,103 @@
|
||||
package com.example.autocrossbow;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
|
||||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.option.KeyBinding;
|
||||
import net.minecraft.client.util.InputUtil;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.item.CrossbowItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket;
|
||||
import net.minecraft.screen.slot.SlotActionType;
|
||||
import net.minecraft.text.ClickEvent;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Hand;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.suggestion.SuggestionProvider;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
public class AutoCrossbowMod implements ClientModInitializer {
|
||||
|
||||
|
||||
private static boolean enabled = false;
|
||||
private static KeyBinding toggleKeyBinding;
|
||||
private static boolean wasUsing = false;
|
||||
private static AutoCrossbowMode currentMode = AutoCrossbowMode.NORMAL;
|
||||
|
||||
|
||||
private static KeyBinding toggleModKeyBinding;
|
||||
private static KeyBinding toggleModeKeyBinding;
|
||||
|
||||
|
||||
private static boolean isRightClickPressed = false;
|
||||
private static boolean wasRightClickPressed = false;
|
||||
|
||||
private static int chargeProgress = 0;
|
||||
|
||||
private static long lastActionTime = 0;
|
||||
private static final long ACTION_COOLDOWN_MS = 50;
|
||||
|
||||
public enum AutoCrossbowMode {
|
||||
NORMAL("normal"), // 普通自动
|
||||
RAPID_FIRE_SHOOT("rapid_shoot"), // 连发发射
|
||||
RAPID_FIRE_LOAD("rapid_load"); // 连发装填
|
||||
|
||||
private final String name;
|
||||
|
||||
AutoCrossbowMode(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public static AutoCrossbowMode fromString(String text) {
|
||||
for (AutoCrossbowMode mode : AutoCrossbowMode.values()) {
|
||||
if (mode.name.equalsIgnoreCase(text)) {
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public AutoCrossbowMode next() {
|
||||
return values()[(this.ordinal() + 1) % values().length];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
toggleKeyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||
"key.autocrossbow.toggle",
|
||||
|
||||
toggleModKeyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||
"key.autocrossbow.toggle_mod",
|
||||
InputUtil.Type.KEYSYM,
|
||||
GLFW.GLFW_KEY_UNKNOWN, // 默认UNKNOW,自己去设置
|
||||
GLFW.GLFW_KEY_UNKNOWN,
|
||||
"category.autocrossbow"
|
||||
));
|
||||
|
||||
toggleModeKeyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||
"key.autocrossbow.toggle_mode",
|
||||
InputUtil.Type.KEYSYM,
|
||||
GLFW.GLFW_KEY_UNKNOWN,
|
||||
"category.autocrossbow"
|
||||
));
|
||||
|
||||
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||
while (toggleKeyBinding.wasPressed()) {
|
||||
enabled = !enabled;
|
||||
if (client.player != null) {
|
||||
client.player.sendMessage(
|
||||
Text.translatable("message.autocrossbow.status",
|
||||
Text.translatable(enabled ? "message.autocrossbow.enabled" : "message.autocrossbow.disabled")),
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
handleKeybinds(client);
|
||||
|
||||
if (!enabled || client.player == null || client.interactionManager == null) {
|
||||
return;
|
||||
@ -50,38 +107,290 @@ public class AutoCrossbowMod implements ClientModInitializer {
|
||||
Hand hand = Hand.MAIN_HAND;
|
||||
ItemStack stack = player.getStackInHand(hand);
|
||||
|
||||
isRightClickPressed = client.options.useKey.isPressed();
|
||||
|
||||
if (!(stack.getItem() instanceof CrossbowItem)) {
|
||||
|
||||
resetActionStates();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isUsing = client.options.useKey.isPressed();
|
||||
|
||||
if (CrossbowItem.isCharged(stack) && isUsing) {
|
||||
client.interactionManager.interactItem(player, hand);
|
||||
return;
|
||||
|
||||
switch (currentMode) {
|
||||
case NORMAL:
|
||||
handleNormalMode(client, player, hand, stack);
|
||||
break;
|
||||
case RAPID_FIRE_SHOOT:
|
||||
handleRapidFireShootMode(client, player, hand, stack);
|
||||
break;
|
||||
case RAPID_FIRE_LOAD:
|
||||
handleRapidFireLoadMode(client, player, hand, stack);
|
||||
break;
|
||||
}
|
||||
|
||||
if (isUsing) {
|
||||
if (!player.isUsingItem()) {
|
||||
client.interactionManager.interactItem(player, hand);
|
||||
chargeProgress = 0;
|
||||
}
|
||||
else if (player.getActiveHand() == hand) {
|
||||
chargeProgress++;
|
||||
|
||||
wasRightClickPressed = isRightClickPressed;
|
||||
});
|
||||
|
||||
int pullTime = CrossbowItem.getPullTime(stack, player);
|
||||
|
||||
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
|
||||
dispatcher.register(ClientCommandManager.literal("autocrossbow")
|
||||
.executes(context -> {
|
||||
|
||||
PlayerEntity player = MinecraftClient.getInstance().player;
|
||||
if (player != null) {
|
||||
player.sendMessage(Text.translatable("command.autocrossbow.status",
|
||||
Text.translatable(enabled ? "message.autocrossbow.enabled" : "message.autocrossbow.disabled"),
|
||||
Text.translatable("message.autocrossbow.mode." + currentMode.getName())), false);
|
||||
|
||||
// TODO 目前测试稳定的只有快速装填3,其他有待优化
|
||||
if (chargeProgress >= pullTime * 1.1f) {
|
||||
client.interactionManager.stopUsingItem(player);
|
||||
wasUsing = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (wasUsing) {
|
||||
wasUsing = false;
|
||||
chargeProgress = 0;
|
||||
}
|
||||
|
||||
MutableText toggleEnabledText = Text.translatable("command.autocrossbow.toggle_enabled")
|
||||
.styled(s -> s.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/autocrossbow enabled " + !enabled)));
|
||||
player.sendMessage(toggleEnabledText, false);
|
||||
|
||||
|
||||
MutableText toggleModeText = Text.translatable("command.autocrossbow.toggle_mode")
|
||||
.styled(s -> s.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/autocrossbow mode " + currentMode.next().getName())));
|
||||
player.sendMessage(toggleModeText, false);
|
||||
}
|
||||
return 1;
|
||||
})
|
||||
.then(ClientCommandManager.literal("enabled")
|
||||
.then(ClientCommandManager.argument("value", BoolArgumentType.bool())
|
||||
.executes(context -> {
|
||||
enabled = BoolArgumentType.getBool(context, "value");
|
||||
PlayerEntity player = MinecraftClient.getInstance().player;
|
||||
if (player != null) {
|
||||
player.sendMessage(Text.translatable("message.autocrossbow.status",
|
||||
Text.translatable(enabled ? "message.autocrossbow.enabled" : "message.autocrossbow.disabled"),
|
||||
Text.translatable("message.autocrossbow.mode." + currentMode.getName())), false);
|
||||
}
|
||||
return 1;
|
||||
})
|
||||
)
|
||||
)
|
||||
.then(ClientCommandManager.literal("mode")
|
||||
.then(ClientCommandManager.argument("modeName", StringArgumentType.word())
|
||||
.suggests(MODE_SUGGESTION_PROVIDER)
|
||||
.executes(context -> {
|
||||
String modeName = StringArgumentType.getString(context, "modeName");
|
||||
AutoCrossbowMode newMode = AutoCrossbowMode.fromString(modeName);
|
||||
PlayerEntity player = MinecraftClient.getInstance().player;
|
||||
if (newMode != null) {
|
||||
currentMode = newMode;
|
||||
if (player != null) {
|
||||
player.sendMessage(Text.translatable("message.autocrossbow.mode_changed",
|
||||
Text.translatable("message.autocrossbow.mode." + currentMode.getName())), false);
|
||||
}
|
||||
} else {
|
||||
if (player != null) {
|
||||
player.sendMessage(Text.translatable("command.autocrossbow.invalid_mode", modeName), false);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void handleKeybinds(MinecraftClient client) {
|
||||
while (toggleModKeyBinding.wasPressed()) {
|
||||
enabled = !enabled;
|
||||
if (client.player != null) {
|
||||
client.player.sendMessage(
|
||||
Text.translatable("message.autocrossbow.status",
|
||||
Text.translatable(enabled ? "message.autocrossbow.enabled" : "message.autocrossbow.disabled"),
|
||||
Text.translatable("message.autocrossbow.mode." + currentMode.getName())),
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
while (toggleModeKeyBinding.wasPressed()) {
|
||||
currentMode = currentMode.next();
|
||||
if (client.player != null) {
|
||||
client.player.sendMessage(
|
||||
Text.translatable("message.autocrossbow.mode_changed",
|
||||
Text.translatable("message.autocrossbow.mode." + currentMode.getName())),
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void resetActionStates() {
|
||||
isRightClickPressed = false;
|
||||
wasRightClickPressed = false;
|
||||
chargeProgress = 0;
|
||||
lastActionTime = 0;
|
||||
}
|
||||
|
||||
|
||||
private void handleNormalMode(MinecraftClient client, PlayerEntity player, Hand hand, ItemStack stack) {
|
||||
if (CrossbowItem.isCharged(stack) && isRightClickPressed) {
|
||||
|
||||
client.interactionManager.interactItem(player, hand);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isRightClickPressed) {
|
||||
|
||||
if (!player.isUsingItem()) {
|
||||
client.interactionManager.interactItem(player, hand);
|
||||
chargeProgress = 0;
|
||||
} else if (player.getActiveHand() == hand) {
|
||||
chargeProgress++;
|
||||
|
||||
int pullTime = CrossbowItem.getPullTime(stack, player);
|
||||
|
||||
|
||||
if (chargeProgress >= pullTime * 1.1f) {
|
||||
client.interactionManager.stopUsingItem(player);
|
||||
}
|
||||
}
|
||||
} else if (wasRightClickPressed) {
|
||||
|
||||
chargeProgress = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void handleRapidFireShootMode(MinecraftClient client, PlayerEntity player, Hand hand, ItemStack stack) {
|
||||
if (!isRightClickPressed) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (System.currentTimeMillis() - lastActionTime < ACTION_COOLDOWN_MS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (CrossbowItem.isCharged(stack)) {
|
||||
|
||||
client.interactionManager.interactItem(player, hand);
|
||||
player.swingHand(hand);
|
||||
lastActionTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
|
||||
int nextSlot = findNextCrossbow(player.getInventory(), true, player.getInventory().selectedSlot);
|
||||
if (nextSlot != -1) {
|
||||
swapToSlot(client, player, nextSlot);
|
||||
} else {
|
||||
|
||||
player.sendMessage(Text.translatable("message.autocrossbow.no_more_charged"), true);
|
||||
currentMode = AutoCrossbowMode.NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void handleRapidFireLoadMode(MinecraftClient client, PlayerEntity player, Hand hand, ItemStack stack) {
|
||||
if (!isRightClickPressed) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (player.isUsingItem() && player.getActiveHand() == hand) {
|
||||
chargeProgress++;
|
||||
int pullTime = CrossbowItem.getPullTime(stack, player);
|
||||
|
||||
if (chargeProgress >= pullTime * 1.1f) {
|
||||
|
||||
client.interactionManager.stopUsingItem(player);
|
||||
chargeProgress = 0;
|
||||
lastActionTime = System.currentTimeMillis();
|
||||
|
||||
|
||||
int nextSlot = findNextCrossbow(player.getInventory(), false, player.getInventory().selectedSlot);
|
||||
if (nextSlot != -1) {
|
||||
swapToSlot(client, player, nextSlot);
|
||||
} else {
|
||||
player.sendMessage(Text.translatable("message.autocrossbow.no_more_uncharged"), true);
|
||||
currentMode = AutoCrossbowMode.NORMAL;
|
||||
}
|
||||
}
|
||||
} else if (!CrossbowItem.isCharged(stack)) {
|
||||
|
||||
|
||||
if (System.currentTimeMillis() - lastActionTime < ACTION_COOLDOWN_MS) {
|
||||
return;
|
||||
}
|
||||
client.interactionManager.interactItem(player, hand);
|
||||
chargeProgress = 0;
|
||||
lastActionTime = System.currentTimeMillis();
|
||||
} else {
|
||||
|
||||
|
||||
if (System.currentTimeMillis() - lastActionTime < ACTION_COOLDOWN_MS) {
|
||||
return;
|
||||
}
|
||||
int nextSlot = findNextCrossbow(player.getInventory(), false, player.getInventory().selectedSlot);
|
||||
if (nextSlot != -1) {
|
||||
swapToSlot(client, player, nextSlot);
|
||||
lastActionTime = System.currentTimeMillis();
|
||||
} else {
|
||||
player.sendMessage(Text.translatable("message.autocrossbow.no_more_uncharged"), true);
|
||||
currentMode = AutoCrossbowMode.NORMAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int findNextCrossbow(PlayerInventory inventory, boolean chargedRequired, int currentSelectedSlot) {
|
||||
|
||||
for (int i = 0; i < PlayerInventory.HOTBAR_SIZE; i++) {
|
||||
if (i == currentSelectedSlot) continue;
|
||||
|
||||
ItemStack stack = inventory.getStack(i);
|
||||
if (stack.getItem() instanceof CrossbowItem) {
|
||||
boolean isCharged = CrossbowItem.isCharged(stack);
|
||||
if (chargedRequired == isCharged) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int i = PlayerInventory.HOTBAR_SIZE; i < inventory.main.size(); i++) {
|
||||
ItemStack stack = inventory.getStack(i);
|
||||
if (stack.getItem() instanceof CrossbowItem) {
|
||||
boolean isCharged = CrossbowItem.isCharged(stack);
|
||||
if (chargedRequired == isCharged) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void swapToSlot(MinecraftClient client, PlayerEntity player, int targetSlot) {
|
||||
if (client.interactionManager == null || player.playerScreenHandler == null) return;
|
||||
|
||||
if (targetSlot >= 0 && targetSlot < PlayerInventory.HOTBAR_SIZE) {
|
||||
player.getInventory().selectedSlot = targetSlot;
|
||||
|
||||
client.getNetworkHandler().sendPacket(new UpdateSelectedSlotC2SPacket(targetSlot));
|
||||
} else {
|
||||
|
||||
client.interactionManager.clickSlot(
|
||||
player.playerScreenHandler.syncId,
|
||||
targetSlot,
|
||||
player.getInventory().selectedSlot,
|
||||
SlotActionType.SWAP,
|
||||
player
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static final SuggestionProvider<FabricClientCommandSource> MODE_SUGGESTION_PROVIDER = (context, builder) -> {
|
||||
Arrays.stream(AutoCrossbowMode.values())
|
||||
.map(AutoCrossbowMode::getName)
|
||||
.forEach(builder::suggest);
|
||||
return builder.buildFuture();
|
||||
};
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
package com.example.autocrossbow.client;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
|
||||
public class AutoCrossbowModClient implements ClientModInitializer {
|
||||
|
||||
// 额
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
}
|
||||
}
|
@ -1,7 +1,18 @@
|
||||
{
|
||||
"key.autocrossbow.toggle": "Toggle Auto Crossbow",
|
||||
"key.autocrossbow.toggle_mod": "Toggle Auto Crossbow Mod",
|
||||
"key.autocrossbow.toggle_mode": "Cycle Crossbow Mode",
|
||||
"category.autocrossbow": "Auto Crossbow Mod",
|
||||
"message.autocrossbow.status": "Auto Crossbow: %s",
|
||||
"message.autocrossbow.status": "Auto Crossbow: %s, Mode: %s",
|
||||
"message.autocrossbow.enabled": "Enabled",
|
||||
"message.autocrossbow.disabled": "Disabled"
|
||||
"message.autocrossbow.disabled": "Disabled",
|
||||
"message.autocrossbow.mode_changed": "Crossbow Mode: %s",
|
||||
"message.autocrossbow.mode.normal": "Normal",
|
||||
"message.autocrossbow.mode.rapid_shoot": "Rapid Fire (Shoot)",
|
||||
"message.autocrossbow.mode.rapid_load": "Rapid Fire (Load)",
|
||||
"message.autocrossbow.no_more_charged": "No more charged crossbows found!",
|
||||
"message.autocrossbow.no_more_uncharged": "No more uncharged crossbows found!",
|
||||
"command.autocrossbow.status": "§b[Auto Crossbow]§f Status: %s, Mode: %s",
|
||||
"command.autocrossbow.toggle_enabled": "Click to toggle mod enabled/disabled",
|
||||
"command.autocrossbow.toggle_mode": "Click to cycle mode",
|
||||
"command.autocrossbow.invalid_mode": "Invalid mode: '%s'. Available modes: normal, rapid_shoot, rapid_load."
|
||||
}
|
||||
|
@ -1,7 +1,18 @@
|
||||
{
|
||||
"key.autocrossbow.toggle": "切换连弩模式",
|
||||
"key.autocrossbow.toggle_mod": "切换诸葛连弩开关",
|
||||
"key.autocrossbow.toggle_mode": "切换连弩模式",
|
||||
"category.autocrossbow": "诸葛连弩",
|
||||
"message.autocrossbow.status": "§b[诸葛连弩]§f 状态: %s",
|
||||
"message.autocrossbow.status": "§b[诸葛连弩]§f 状态:%s,模式:%s",
|
||||
"message.autocrossbow.enabled": "§a已启用",
|
||||
"message.autocrossbow.disabled": "§c已禁用"
|
||||
"message.autocrossbow.disabled": "§c已禁用",
|
||||
"message.autocrossbow.mode_changed": "连弩模式:%s",
|
||||
"message.autocrossbow.mode.normal": "正常模式",
|
||||
"message.autocrossbow.mode.rapid_shoot": "连发 - 发射模式",
|
||||
"message.autocrossbow.mode.rapid_load": "连发 - 装填模式",
|
||||
"message.autocrossbow.no_more_charged": "背包中没有更多已上膛的弩了!",
|
||||
"message.autocrossbow.no_more_uncharged": "背包中没有更多未上膛的弩了!",
|
||||
"command.autocrossbow.status": "§b[诸葛连弩]§f 状态:%s,模式:%s",
|
||||
"command.autocrossbow.toggle_enabled": "点击切换模组启用/禁用",
|
||||
"command.autocrossbow.toggle_mode": "点击切换模式",
|
||||
"command.autocrossbow.invalid_mode": "无效模式:“%s”。可用模式:normal, rapid_shoot, rapid_load。"
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user