Last active
March 29, 2025 01:45
-
-
Save EvanHsieh0415/0b317050d40872084d643d2b9777f4cd to your computer and use it in GitHub Desktop.
【KJS 7 &AE 2】 实现中键从AE中获取光标指向方块 - [KJS]KubeJS https://www.mcmod.cn/post/4954.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// requires: ae2 | |
(() => { | |
const { keyPickItem } = Client.options; // 「选取方块」对应的 KeyMapping | |
ClientEvents.tick((event) => { | |
let { player } = event; | |
if (!keyPickItem.isDown()) return; | |
player.sendData("kubejs.key.pickItem", {}); | |
}); | |
})(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// requires: ae2 | |
(() => { | |
const $ILinkStatus = Java.loadClass("appeng.api.storage.ILinkStatus"); | |
const $WirelessTerminalItem = Java.loadClass("appeng.items.tools.powered.WirelessTerminalItem"); | |
const $IActionSource = Java.loadClass("appeng.api.networking.security.IActionSource"); | |
const $AEItemKey = Java.loadClass("appeng.api.stacks.AEItemKey"); | |
const $MenuLocators = Java.loadClass("appeng.menu.locator.MenuLocators"); | |
const $StorageHelper = Java.loadClass("appeng.api.storage.StorageHelper"); | |
const $Actionable = Java.loadClass("appeng.api.config.Actionable"); | |
/** | |
* 判断物品堆是否为无线终端 | |
* @param { $Item_ | $ItemStack_ } item | |
* @returns { boolean } | |
*/ | |
function isWirelessTerminal(item) { | |
return item.item instanceof $WirelessTerminalItem; | |
} | |
// 快捷栏(0-8) | |
const HOTBAR_INDEX = [0, 9]; | |
// 背包剩余槽位(9-35) | |
const INVENTORY_INDEX = [9, 36]; | |
/** | |
* 寻找无线终端 | |
* @param { $Player_ } player | |
* @returns { $ItemStack_ | null } | |
*/ | |
function findWirelessTerminal(player) { | |
/** @type {(() => ($ItemStack_|null))[]} */ | |
const checkSlots = [ | |
// 优先检查主手 | |
() => player.mainHandItem, | |
// 其次检查副手 | |
() => player.offhandItem, | |
// 检查快捷栏 | |
() => { | |
for (let slot = HOTBAR_INDEX[0]; slot < HOTBAR_INDEX[1]; slot++) { | |
let stack = player.inventory.getStackInSlot(slot); | |
if (isWirelessTerminal(stack)) return stack; | |
} | |
return null; | |
}, | |
// 检查 Curios 饰品栏 | |
() => { | |
if (!Platform.isModLoaded("powerfuljs")) return null; | |
const capabilities = Capabilities.entity("curios:item_handler"); | |
if (capabilities === null) return null; | |
const curios = player.getCapability(capabilities); | |
if (curios === null) return null; | |
const index = curios.find(isWirelessTerminal); | |
if (index != -1) return curios.getStackInSlot(index); | |
return null; | |
}, | |
// 检查背包剩余槽位 | |
() => { | |
for (let slot = INVENTORY_INDEX[0]; slot < INVENTORY_INDEX[1]; slot++) { | |
let stack = player.inventory.getStackInSlot(slot); | |
if (isWirelessTerminal(stack)) return stack; | |
} | |
return null; | |
}, | |
]; | |
for (let slotCheck of checkSlots) { | |
let stack = slotCheck(); | |
if (stack !== null && isWirelessTerminal(stack)) return stack; | |
} | |
return null; | |
} | |
/** | |
* 将物品放入离当前选中槽位最近的空快捷栏槽位 | |
* @param { $Player_ } player | |
* @param { $ItemStack_ } itemStack | |
* @returns { number } 成功设置的槽位号,找不到返回-1 | |
*/ | |
function setEmptyHandSlot(player, itemStack) { | |
const selectedSlot = player.selectedSlot; | |
const slots = [0, 1, 2, 3, 4, 5, 6, 7, 8]; | |
// 按与选中槽位的距离排序:优先当前槽位→左右相邻→逐渐向外扩展 | |
slots.sort((a, b) => { | |
let distA = Math.abs(a - selectedSlot); | |
let distB = Math.abs(b - selectedSlot); | |
// 距离相同则按序号排序 | |
return distA - distB || a - b; | |
}); | |
const selectedItem = player.inventory.getStackInSlot(selectedSlot); | |
if (selectedItem.empty) { | |
player.inventory.setStackInSlot(selectedSlot, itemStack); | |
return selectedSlot; | |
} | |
// 寻找第一个非手持且为空的槽位 | |
for (let slot of slots) { | |
if (slot === selectedSlot) continue; | |
let slotItem = player.inventory.getStackInSlot(slot); | |
if (slotItem.empty) { | |
player.inventory.setStackInSlot(slot, itemStack); | |
return slot; | |
} | |
} | |
return -1; // 全满 | |
} | |
NetworkEvents.dataReceived("kubejs.key.pickItem", (event) => { | |
const { player } = event; | |
const keyStats = player.persistentData.getBoolean("kubejs:key_pickItem"); | |
if (keyStats) { | |
player.persistentData.putBoolean("kubejs:key_pickItem", false); | |
return; | |
} else { | |
player.persistentData.putBoolean("kubejs:key_pickItem", true); | |
} | |
const hitResult = player.rayTrace(); | |
if (!hitResult.block) return; | |
const itemStack = hitResult.block.item; | |
if (player.inventory.find({ item: itemStack.id }) > -1) return; | |
const wirelessTerminal = findWirelessTerminal(player); | |
if (wirelessTerminal == null) return; | |
/** @type {{ item: $WirelessTerminalItem_ }} */ | |
const { item } = wirelessTerminal; | |
const menu = item.getMenuHost(player, $MenuLocators.forStack(wirelessTerminal), null); | |
const linkStatus = menu.getLinkStatus(); | |
// 检查无线终端与ME网络的链接状态 | |
if (linkStatus !== $ILinkStatus.ofConnected()) { | |
// 若无线终端无法访问链接网络,显示无法访问的原因 | |
player.setStatusMessage(linkStatus.statusDescription()); | |
return; | |
} | |
// ME 网络的存储服务 | |
const { inventory } = menu; | |
const AEItemKey = $AEItemKey["of(net.minecraft.world.item.ItemStack)"](itemStack); | |
const result = $StorageHelper.poweredExtraction( | |
menu, | |
inventory, | |
AEItemKey, | |
1, | |
$IActionSource.ofPlayer(player), | |
$Actionable.SIMULATE | |
); | |
if (result <= 0) return; | |
const emptySlot = setEmptyHandSlot(player, itemStack); | |
if (emptySlot == -1) return; | |
player.selectedSlot = emptySlot; | |
$StorageHelper.poweredExtraction( | |
menu, | |
inventory, | |
AEItemKey, | |
1, | |
$IActionSource.ofPlayer(player), | |
$Actionable.MODULATE | |
); | |
}); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment