Files
OpenSlinky/SlinkyClient/src/main/java/dev/slinky/client/placement/PlacementSelection.java
T
2026-10-14 22:15:53 -05:00

291 lines
7.5 KiB
Java

package dev.slinky.client.placement;
import dev.slinky.client.ClientContext;
import dev.slinky.client.action.ActionAccess;
import dev.slinky.client.action.ModuleActionService;
import dev.slinky.client.inventory.InventoryActions;
import java.util.function.IntUnaryOperator;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemStack;
public final class PlacementSelection {
private static int preferred;
private static boolean startAfterCurrent;
private static Object selectionOwner;
private static PlacementSelection.Inventory inventoryOwner;
private static Object restorationOwner;
private static int originalSlot;
private static int inactivity;
private static int capturedType;
private static int capturedCount;
private static int lastSlot;
private static int repetitions;
private PlacementSelection() {
}
public static synchronized void remember(int type, boolean afterCurrent) {
preferred = type;
startAfterCurrent = afterCurrent;
}
public static PlacementSelection.Inventory inventory(final InventoryPlayer player) {
return new PlacementSelection.Inventory() {
@Override
public int current() {
return player.currentItem;
}
@Override
public void current(int slot) {
player.currentItem = slot;
}
private ItemStack at(int slot) {
return player.getStackInSlot(slot);
}
@Override
public boolean stack(int slot) {
return this.at(slot) != null;
}
@Override
public boolean item(int slot) {
return this.at(slot) != null && this.at(slot).getItem() != null;
}
@Override
public int type(int slot) {
return InventoryActions.type(this.at(slot));
}
@Override
public boolean block(int slot) {
return ActionAccess.isBlock(this.at(slot));
}
@Override
public int count(int slot) {
return this.at(slot).stackSize;
}
};
}
public static synchronized void frameReset() {
if (selectionOwner != null) {
ModuleActionService.release(selectionOwner);
}
selectionOwner = null;
inactivity++;
preferred = 0;
startAfterCurrent = false;
}
public static synchronized void capture(PlacementSelection.Inventory i) {
if (capturedType == 0) {
int slot = i.current();
if (i.stack(slot) && i.block(slot)) {
capturedType = i.type(slot);
capturedCount = i.count(slot);
if (Integer.compareUnsigned(inactivity, 20) > 0 || lastSlot != slot) {
repetitions = capturedCount;
}
inactivity = 0;
lastSlot = slot;
}
}
}
public static void capture(ClientContext c) {
if (c.ready()) {
capture(inventory(c.player().inventory));
}
}
public static synchronized void consume(PlacementSelection.Inventory i) {
if (capturedType != 0) {
int slot = i.current();
boolean depleted = !i.stack(slot) || !i.item(slot) || i.type(slot) == 0;
if (!depleted && i.count(slot) < capturedCount) {
depleted = --repetitions == 0;
}
if (depleted) {
preferred = capturedType;
startAfterCurrent = true;
}
capturedType = 0;
}
}
public static void consume(ClientContext c) {
if (c.ready()) {
consume(inventory(c.player().inventory));
}
}
public static synchronized int preferred() {
return preferred;
}
public static synchronized boolean afterCurrent() {
return startAfterCurrent;
}
public static int bridgeRank(int id) {
switch (id) {
case 1:
case 2:
case 3:
case 35:
case 45:
return 2;
case 5:
case 17:
case 20:
case 24:
case 87:
return 1;
default:
int offset = id - 121;
return Integer.compareUnsigned(offset, 41) <= 0 && (2473901162497L >>> (offset & 63) & 1L) != 0L ? 1 : -1;
}
}
public static int blockInRank(int id) {
switch (id) {
case 1:
case 2:
case 3:
case 20:
case 24:
case 45:
case 87:
case 159:
return 2;
case 4:
case 5:
case 17:
case 121:
case 162:
return 3;
case 35:
return 1;
case 49:
return 4;
default:
return -1;
}
}
public static int choose(int[] ids, int current, int preferredId, boolean afterCurrent, IntUnaryOperator rank) {
int first = current + (afterCurrent ? 1 : 0);
int chosen = -1;
int best = -1;
for (int n = 0; n < 9; n++) {
int slot = (first + n) % 9;
int id = ids[slot];
if (id != 0) {
if (preferredId != 0 && id == preferredId) {
return slot;
}
int score = rank.applyAsInt(id);
if (score > best) {
best = score;
chosen = slot;
}
}
}
return chosen;
}
public static synchronized boolean select(ClientContext c, Object token, boolean force, boolean blockIn) {
return selectionOwner == null && c.ready() && (force || preferred != 0) ? select(inventory(c.player().inventory), token, force, blockIn) : false;
}
public static synchronized boolean select(PlacementSelection.Inventory inventory, Object token, boolean force, boolean blockIn) {
if (selectionOwner == null && (force || preferred != 0)) {
int[] ids = new int[9];
for (int i = 0; i < 9; i++) {
ids[i] = inventory.type(i);
}
int chosen = choose(ids, inventory.current(), preferred, startAfterCurrent, blockIn ? PlacementSelection::blockInRank : PlacementSelection::bridgeRank);
if (chosen != -1 && ModuleActionService.claim(token)) {
if (restorationOwner != token) {
originalSlot = inventory.current();
inventoryOwner = inventory;
restorationOwner = token;
}
selectionOwner = token;
inventory.current(chosen);
return true;
} else {
return false;
}
} else {
return false;
}
}
public static synchronized void release(Object token) {
if (restorationOwner == token) {
inventoryOwner.current(originalSlot);
restorationOwner = null;
inventoryOwner = null;
}
if (selectionOwner == token) {
selectionOwner = null;
}
ModuleActionService.release(token);
}
public static synchronized void reset() {
if (inventoryOwner != null) {
inventoryOwner.current(originalSlot);
}
if (selectionOwner != null) {
ModuleActionService.release(selectionOwner);
}
restorationOwner = null;
selectionOwner = null;
inventoryOwner = null;
preferred = 0;
startAfterCurrent = false;
repetitions = 0;
lastSlot = 0;
capturedCount = 0;
capturedType = 0;
inactivity = 0;
}
public interface Inventory {
int current();
void current(int var1);
boolean stack(int var1);
boolean item(int var1);
int type(int var1);
boolean block(int var1);
int count(int var1);
}
}