- Выберите загрузчик игры
- Fabric
Клесо свапа шаров таликов и тд сфер, фото прикреплю ниже вот код , жду del
Swap:
package ru.levin.modules.player;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.render.*;
import net.minecraft.client.util.InputUtil;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.screen.slot.SlotActionType;
import org.joml.Matrix4f;
import ru.levin.events.Event;
import ru.levin.events.impl.input.EventKey;
import ru.levin.events.impl.input.EventMouse;
import ru.levin.events.impl.render.EventRender2D;
import ru.levin.modules.Function;
import ru.levin.modules.FunctionAnnotation;
import ru.levin.modules.Type;
import ru.levin.modules.setting.BindSetting;
import ru.levin.modules.setting.BooleanSetting;
import ru.levin.modules.setting.ModeSetting;
import ru.levin.util.player.InventoryUtil;
import ru.levin.util.player.TimerUtil;
import ru.levin.util.render.RenderUtil;
import java.awt.*;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.function.Predicate;
@FunctionAnnotation(name = "SwapWheel", desc = "Круговое меню для быстрой смены предметов", type = Type.Render)
public class SwapWheel extends Function {
private final BindSetting wheelBind = new BindSetting("Клавиша открытия", 0);
private final ModeSetting show = new ModeSetting("Показывать", "Тотемы и головы", "Тотемы", "Головы", "Тотемы и головы");
private final BooleanSetting ftHwBypass = new BooleanSetting("Обход FT/HW", false, "Для серверов с античитом");
private final TimerUtil timer = new TimerUtil();
private boolean bypassActive = false;
private boolean awaitingSwap = false;
private int pendingSlot = -1;
private int pendingTargetSlot = -1;
private boolean wheelOpen = false;
private boolean cursorUnlocked = false;
private List<WheelEntry> wheelEntries = new ArrayList<>();
private int selectedSegment = -1;
public SwapWheel() {
addSettings(wheelBind, show, ftHwBypass);
}
@Override
public void onEvent(Event event) {
if (mc == null || mc.player == null || mc.world == null) return;
if (event instanceof EventKey e) {
if (mc.currentScreen != null) return;
if (e.key == wheelBind.getKey()) {
toggleWheel();
e.isCancel();
}
}
if (event instanceof EventMouse e) {
if (!wheelOpen || mc.currentScreen != null) return;
e.isCancel();
if (e.getButton() == 0) { // ЛКМ
if (selectedSegment >= 0 && selectedSegment < wheelEntries.size()) {
pickWheelSlot(selectedSegment);
} else {
toggleWheel();
}
}
if (e.getButton() == 1) {
toggleWheel();
}
}
if (event instanceof EventRender2D e) {
if (!wheelOpen) return;
if (mc.currentScreen != null) {
wheelOpen = false;
updateCursorLock(false);
return;
}
renderWheel(e);
}
}
@Override
public void onDisable() {
wheelOpen = false;
updateCursorLock(false);
bypassActive = false;
awaitingSwap = false;
super.onDisable();
}
private void toggleWheel() {
wheelOpen = !wheelOpen;
updateCursorLock(wheelOpen);
if (wheelOpen) {
wheelEntries = buildWheelEntries();
selectedSegment = -1;
}
}
private void updateCursorLock(boolean locked) {
if (mc == null || mc.mouse == null) return;
if (locked) {
if (!cursorUnlocked) {
mc.mouse.unlockCursor();
cursorUnlocked = true;
}
} else {
if (cursorUnlocked) {
if (mc.currentScreen == null) {
mc.mouse.lockCursor();
}
cursorUnlocked = false;
}
}
}
private void pickWheelSlot(int index) {
if (wheelEntries.isEmpty() || index >= wheelEntries.size()) {
toggleWheel();
return;
}
WheelEntry entry = wheelEntries.get(index);
ItemSlot slot = findBestSlot(entry.predicate);
if (slot == null) {
toggleWheel();
return;
}
moveToOffhand(slot);
toggleWheel();
}
private void moveToOffhand(ItemSlot slot) {
if (mc.player == null || mc.interactionManager == null || mc.player.currentScreenHandler == null) return;
if (slot.idForServer == 45) return;
int offhandSlot = 40;
int fromSlot = slot.idForServer;
int clickSlot = (fromSlot < 9) ? fromSlot + 36 : fromSlot;
if (ftHwBypass.get()) {
timer.reset();
bypassActive = true;
awaitingSwap = true;
pendingSlot = clickSlot;
pendingTargetSlot = offhandSlot;
mc.options.forwardKey.setPressed(false);
mc.options.backKey.setPressed(false);
mc.options.leftKey.setPressed(false);
mc.options.rightKey.setPressed(false);
mc.options.sprintKey.setPressed(false);
} else {
mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, clickSlot, offhandSlot, SlotActionType.SWAP, mc.player);
}
}
private void performSwap() {
if (mc.player == null || mc.interactionManager == null || mc.player.currentScreenHandler == null) return;
if (pendingSlot != -1 && pendingTargetSlot != -1) {
mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, pendingSlot, pendingTargetSlot, SlotActionType.SWAP, mc.player);
pendingSlot = -1;
pendingTargetSlot = -1;
}
}
private void resetBypass() {
bypassActive = false;
awaitingSwap = false;
pendingSlot = -1;
pendingTargetSlot = -1;
if (mc.options != null) {
updateKeyBinding(mc.options.forwardKey);
updateKeyBinding(mc.options.backKey);
updateKeyBinding(mc.options.leftKey);
updateKeyBinding(mc.options.rightKey);
updateKeyBinding(mc.options.sprintKey);
}
}
private void updateKeyBinding(KeyBinding keyMapping) {
if (keyMapping == null) return;
keyMapping.setPressed(InputUtil.isKeyPressed(mc.getWindow().getHandle(), keyMapping.getDefaultKey().getCode()));
}
private void handleBypass() {
if (!bypassActive) return;
mc.options.forwardKey.setPressed(false);
mc.options.backKey.setPressed(false);
mc.options.leftKey.setPressed(false);
mc.options.rightKey.setPressed(false);
mc.options.sprintKey.setPressed(false);
if (awaitingSwap && timer.hasTimeElapsed(90)) {
awaitingSwap = false;
performSwap();
}
if (timer.hasTimeElapsed(150)) {
resetBypass();
}
}
private ItemSlot findBestSlot(Predicate<ItemStack> predicate) {
if (predicate == null) return null;
List<ItemSlot> slots = new ArrayList<>();
for (int i = 0; i <= 8; i++) {
ItemStack stack = mc.player.getInventory().getStack(i);
if (!stack.isEmpty() && predicate.test(stack)) {
slots.add(new ItemSlot(i, stack));
}
}
for (int i = 9; i <= 35; i++) {
ItemStack stack = mc.player.getInventory().getStack(i);
if (!stack.isEmpty() && predicate.test(stack)) {
slots.add(new ItemSlot(i, stack));
}
}
if (slots.isEmpty()) return null;
slots.sort(Comparator.comparingInt(s -> {
if (s.idForServer >= 0 && s.idForServer <= 8) return 0;
return 1;
}));
return slots.get(0);
}
private List<WheelEntry> buildWheelEntries() {
if (mc.player == null) return new ArrayList<>();
List<WheelEntry> entries = new ArrayList<>();
HashMap<String, WheelEntryAccum> accum = new HashMap<>();
for (int i = 0; i <= 35; i++) {
ItemStack stack = mc.player.getInventory().getStack(i);
if (stack.isEmpty() || stack.getItem() == Items.AIR) continue;
if ((show.is("Тотемы") || show.is("Тотемы и головы")) && stack.getItem() == Items.TOTEM_OF_UNDYING) {
String key = "totem:" + getStackKey(stack);
WheelEntryAccum acc = accum.computeIfAbsent(key, k ->
new WheelEntryAccum(stack.copyWithCount(1), 0, s -> s.getItem() == Items.TOTEM_OF_UNDYING && getStackKey(s).equals(getStackKey(stack))));
acc.totalCount += stack.getCount();
}
if ((show.is("Головы") || show.is("Тотемы и головы")) && stack.getItem() == Items.PLAYER_HEAD) {
String key = "head:" + getStackKey(stack);
WheelEntryAccum acc = accum.computeIfAbsent(key, k ->
new WheelEntryAccum(stack.copyWithCount(1), 0, s -> s.getItem() == Items.PLAYER_HEAD && getStackKey(s).equals(getStackKey(stack))));
acc.totalCount += stack.getCount();
}
}
for (WheelEntryAccum acc : accum.values()) {
entries.add(new WheelEntry(acc.displayStack, acc.totalCount, acc.predicate));
}
entries.sort((a, b) -> {
if (a.displayStack.getItem() == Items.TOTEM_OF_UNDYING && b.displayStack.getItem() != Items.TOTEM_OF_UNDYING) return -1;
if (a.displayStack.getItem() != Items.TOTEM_OF_UNDYING && b.displayStack.getItem() == Items.TOTEM_OF_UNDYING) return 1;
return 0;
});
return entries;
}
private String getStackKey(ItemStack stack) {
if (stack.getItem() == Items.TOTEM_OF_UNDYING) {
if (stack.hasEnchantments()) return "enchanted";
return "normal";
}
if (stack.getItem() == Items.PLAYER_HEAD) {
try {
var components = stack.getComponents();
var profileComponent = components.get(net.minecraft.component.DataComponentTypes.PROFILE);
if (profileComponent != null && profileComponent.name() != null) {
return profileComponent.name().get();
}
} catch (Exception ignored) {}
return "player_head";
}
return stack.getItem().toString();
}
private void renderWheel(EventRender2D event) {
if (bypassActive) {
handleBypass();
}
int count = Math.max(3, wheelEntries.isEmpty() ? 4 : wheelEntries.size());
float cx = mc.getWindow().getScaledWidth() / 2f;
float cy = mc.getWindow().getScaledHeight() / 2f;
float outerR = 92f + Math.max(0, count - 8) * 6f;
float innerR = Math.max(26f, outerR - 38f);
float mouseX = (float) (mc.mouse.getX() / mc.getWindow().getScaleFactor());
float mouseY = (float) (mc.mouse.getY() / mc.getWindow().getScaleFactor());
selectedSegment = getHoverIndex(mouseX, mouseY, cx, cy, innerR, outerR, count);
if (selectedSegment >= count) selectedSegment = -1;
RenderSystem.enableBlend();
RenderSystem.disableDepthTest();
RenderSystem.disableCull();
RenderSystem.defaultBlendFunc();
Matrix4f matrix = event.getDrawContext().getMatrices().peek().getPositionMatrix();
Tessellator tessellator = RenderSystem.renderThreadTesselator();
BufferBuilder buffer = tessellator.begin(VertexFormat.DrawMode.TRIANGLES, VertexFormats.POSITION_COLOR);
drawBackgroundDarkening(event, cx, cy, outerR + 20);
for (int i = 0; i < count; i++) {
boolean isHover = i == selectedSegment;
int r, g, b, a;
if (isHover) {
r = 255; g = 209; b = 47; a = 200;
} else {
r = 40; g = 40; b = 55; a = 180;
}
float start = (float)(-Math.PI / 2.0 + 2.0 * Math.PI * (i / (double)count));
float end = (float)(-Math.PI / 2.0 + 2.0 * Math.PI * ((i + 1.0) / (double)count));
drawRingSegment(buffer, matrix, cx, cy, innerR, outerR, start, end, r, g, b, a);
}
BufferRenderer.drawWithGlobalProgram(buffer.end());
for (int i = 0; i < count && i < wheelEntries.size(); i++) {
WheelEntry entry = wheelEntries.get(i);
float start = (float)(-Math.PI / 2.0 + 2.0 * Math.PI * (i / (double)count));
float end = (float)(-Math.PI / 2.0 + 2.0 * Math.PI * ((i + 1.0) / (double)count));
float mid = (start + end) / 2f;
float iconR = (innerR + outerR) / 2f;
float ix = cx + (float)Math.cos(mid) * iconR;
float iy = cy + (float)Math.sin(mid) * iconR;
RenderUtil.drawRoundedRect(event.getDrawContext().getMatrices(), ix - 10, iy - 10, 20, 20, 4, new Color(0, 0, 0, 150).getRGB());
event.getDrawContext().drawItem(entry.displayStack, (int)(ix - 8), (int)(iy - 8));
if (entry.totalCount > 1) {
String countStr = String.valueOf(entry.totalCount);
event.getDrawContext().drawTextWithShadow(mc.textRenderer, countStr, (int)(ix + 5), (int)(iy + 3), 0xFFFFFF);
}
}
drawCenterCircle(event, cx, cy, innerR - 8);
RenderUtil.drawRoundedRect(event.getDrawContext().getMatrices(), cx - 16, cy - 16, 32, 32, 8, new Color(20, 20, 30, 220).getRGB());
RenderUtil.drawRoundedBorder(event.getDrawContext().getMatrices(), cx - 16, cy - 16, 32, 32, 8, 2f, new Color(255, 209, 47, 200).getRGB());
event.getDrawContext().drawItem(mc.player.getOffHandStack(), (int)cx - 8, (int)cy - 8);
drawCrosshair(event, cx, cy);
if (selectedSegment >= 0 && selectedSegment < wheelEntries.size()) {
WheelEntry entry = wheelEntries.get(selectedSegment);
String name = entry.displayStack.getName().getString();
if (name.length() > 30) name = name.substring(0, 27) + "...";
int textWidth = mc.textRenderer.getWidth(name);
float tooltipX = mouseX + 12;
float tooltipY = mouseY + 12;
if (tooltipX + textWidth + 12 > mc.getWindow().getScaledWidth()) {
tooltipX = mouseX - textWidth - 24;
}
if (tooltipY + 20 > mc.getWindow().getScaledHeight()) {
tooltipY = mouseY - 20;
}
RenderUtil.drawRoundedRect(event.getDrawContext().getMatrices(), tooltipX, tooltipY, textWidth + 12, 18, 4, new Color(20, 20, 30, 220).getRGB());
RenderUtil.drawRoundedBorder(event.getDrawContext().getMatrices(), tooltipX, tooltipY, textWidth + 12, 18, 4, 1f, new Color(255, 209, 47, 150).getRGB());
event.getDrawContext().drawTextWithShadow(mc.textRenderer, name, (int)(tooltipX + 6), (int)(tooltipY + 5), 0xFFFFFF);
}
RenderSystem.enableCull();
RenderSystem.enableDepthTest();
}
private void drawBackgroundDarkening(EventRender2D event, float cx, float cy, float radius) {
MatrixStack matrices = event.getDrawContext().getMatrices();
int screenWidth = mc.getWindow().getScaledWidth();
int screenHeight = mc.getWindow().getScaledHeight();
RenderUtil.drawRoundedRect(matrices, 0, 0, screenWidth, screenHeight, 0, new Color(0, 0, 0, 150).getRGB());
}
private void drawCenterCircle(EventRender2D event, float cx, float cy, float radius) {
MatrixStack matrices = event.getDrawContext().getMatrices();
RenderUtil.drawRoundedBorder(matrices, cx - radius, cy - radius, radius * 2, radius * 2, radius, 2f, new Color(255, 209, 47, 180).getRGB());
}
private void drawCrosshair(EventRender2D event, float cx, float cy) {
MatrixStack matrices = event.getDrawContext().getMatrices();
int size = 8;
int thickness = 2;
RenderUtil.drawRoundedRect(matrices, cx - size, cy - thickness / 2f, size * 2, thickness, 1, new Color(255, 255, 255, 200).getRGB());
RenderUtil.drawRoundedRect(matrices, cx - thickness / 2f, cy - size, thickness, size * 2, 1, new Color(255, 255, 255, 200).getRGB());
RenderUtil.drawRoundedRect(matrices, cx - 2, cy - 2, 4, 4, 2, new Color(255, 209, 47, 255).getRGB());
}
private void drawRingSegment(BufferBuilder buffer, Matrix4f matrix, float cx, float cy, float innerR, float outerR, float start, float end, int r, int g, int b, int a) {
int steps = Math.max(16, (int)(48f * (Math.abs(end - start) / ((float)Math.PI * 2f))));
float step = (end - start) / steps;
for (int i = 0; i < steps; i++) {
float a0 = start + step * i;
float a1 = start + step * (i + 1);
float x0o = cx + (float)Math.cos(a0) * outerR;
float y0o = cy + (float)Math.sin(a0) * outerR;
float x1o = cx + (float)Math.cos(a1) * outerR;
float y1o = cy + (float)Math.sin(a1) * outerR;
float x0i = cx + (float)Math.cos(a0) * innerR;
float y0i = cy + (float)Math.sin(a0) * innerR;
float x1i = cx + (float)Math.cos(a1) * innerR;
float y1i = cy + (float)Math.sin(a1) * innerR;
buffer.vertex(matrix, x0i, y0i, 0f).color(r, g, b, a);
buffer.vertex(matrix, x0o, y0o, 0f).color(r, g, b, a);
buffer.vertex(matrix, x1o, y1o, 0f).color(r, g, b, a);
buffer.vertex(matrix, x0i, y0i, 0f).color(r, g, b, a);
buffer.vertex(matrix, x1o, y1o, 0f).color(r, g, b, a);
buffer.vertex(matrix, x1i, y1i, 0f).color(r, g, b, a);
}
}
private int getHoverIndex(float mouseX, float mouseY, float cx, float cy, float innerR, float outerR, int count) {
float dx = mouseX - cx;
float dy = mouseY - cy;
float dist = (float)Math.sqrt(dx * dx + dy * dy);
if (dist < innerR || dist > outerR) return -1;
double ang = Math.atan2(dy, dx);
ang = ang + Math.PI / 2.0;
if (ang < 0) ang += Math.PI * 2.0;
int idx = (int)Math.floor(ang / (Math.PI * 2.0) * count);
if (idx < 0 || idx >= count) return -1;
return idx;
}
private static class WheelEntryAccum {
final ItemStack displayStack;
int totalCount;
final Predicate<ItemStack> predicate;
WheelEntryAccum(ItemStack displayStack, int totalCount, Predicate<ItemStack> predicate) {
this.displayStack = displayStack;
this.totalCount = totalCount;
this.predicate = predicate;
}
}
private static class WheelEntry {
final ItemStack displayStack;
final int totalCount;
final Predicate<ItemStack> predicate;
WheelEntry(ItemStack displayStack, int totalCount, Predicate<ItemStack> predicate) {
this.displayStack = displayStack;
this.totalCount = totalCount;
this.predicate = predicate;
}
}
private static class ItemSlot {
final int idForServer;
final ItemStack itemStack;
ItemSlot(int idForServer, ItemStack itemStack) {
this.idForServer = idForServer;
this.itemStack = itemStack;
}
}
}