This commit is contained in:
retuci0 committed 2026-02-22 12:01:00 +01:00
1 parent acecda3c0d
commit 412fe93a89
16 files changed
+581 -26

No files matched your search

+8 -4
View File
@@ -4,15 +4,19 @@
### adiciones
#### comandos nuevos:
- repesperar: combinación de \$repetir y \$esperar
#### módulos nuevos:
- andamios: coloca bloques a tus pies a medida que caminas
- cocaína: hace que todo vaya más rápido o más lento
### arreglos / mejoras
- arreglado el crash por no incluir el sistema de eventos en el mod (soy gilipollas)
- mejoras varias al módulo tobillos fuertes
- ahora el módulo de interfaces en portales funciona correctamente
- reponer ya no está repe
- opción para no romper el pico en selección de minado
## problemas reconocidos
- lo de siempre
+1 -1
View File
@@ -10,6 +10,6 @@ fabric_api_version=0.140.2+1.21.11
neutrino_version=1.1.0
mod_version=3.5
mod_version=3.6
maven_group=me.retucio
archives_base_name=sputnik
@@ -42,6 +42,7 @@ public class CommandManager {
addCommand(new PrefixCommand());
addCommand(new PurgeCommand());
addCommand(new RepeatCommand());
addCommand(new RepeatWaitCommand());
addCommand(new SaveScreenshotCommand());
addCommand(new SendCommand());
addCommand(new SpectateCommand());
@@ -0,0 +1,46 @@
package me.retucio.sputnik.command.commands;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import me.retucio.sputnik.command.Command;
import me.retucio.sputnik.util.ChatUtil;
import net.minecraft.command.CommandSource;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class RepeatWaitCommand extends Command {
public RepeatWaitCommand() {
super("repesperar", "combinación de $repetir y $esperar");
}
@Override
public void build(LiteralArgumentBuilder<CommandSource> builder) {
builder.then(argument("ms", IntegerArgumentType.integer(1))
.then(argument("veces", IntegerArgumentType.integer(1))
.then(argument("comando", StringArgumentType.greedyString())
.executes((context) -> {
int ms = context.getArgument("ms", Integer.class);
int times = context.getArgument("veces", Integer.class);
String cmd = context.getArgument("comando", String.class);
for (int i = 0; i < times; i++) {
int delay = i * ms;
int finalI = i;
new ScheduledThreadPoolExecutor(2).schedule(
() -> ChatUtil.info(
cmd.replaceAll("(?i)%index%",
String.valueOf(finalI))),
delay,
TimeUnit.MILLISECONDS
);
}
return SUCCESS;
})
)
)
);
}
}
@@ -0,0 +1,5 @@
package me.retucio.sputnik.event.input;
import com.github.retucio.neutrino.Event;
public class SneakEvent extends Event {}
@@ -0,0 +1,19 @@
package me.retucio.sputnik.mixin.mixins.player;
import me.retucio.sputnik.Sputnik;
import me.retucio.sputnik.event.input.SneakEvent;
import net.minecraft.util.PlayerInput;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PlayerInput.class)
public abstract class PlayerInputMixin {
@Inject(method = "sneak", at = @At("HEAD"), cancellable = true)
private void onSneak(CallbackInfoReturnable<Boolean> cir) {
SneakEvent event = Sputnik.EVENT_BUS.post(new SneakEvent());
if (event.isCancelled()) cir.cancel();
}
}
@@ -0,0 +1,23 @@
package me.retucio.sputnik.mixin.mixins.world;
import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.world.Timer;
import net.minecraft.client.render.RenderTickCounter;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(RenderTickCounter.Dynamic.class)
public abstract class RenderTickCounterDynamicMixin {
@Shadow
private float dynamicDeltaTicks;
@Inject(method = "beginRenderTick(J)I", at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/RenderTickCounter$Dynamic;lastTimeMillis:J", opcode = Opcodes.PUTFIELD))
private void onBeingRenderTick(long timeMillis, CallbackInfoReturnable<Integer> cir) {
dynamicDeltaTicks *= ModuleManager.INSTANCE.getModuleByClass(Timer.class).multiplier.getFloatValue();
}
}
@@ -116,6 +116,7 @@ public class ModuleManager {
add(new Jesus());
add(new ReverseStep());
add(new SafeWalk());
add(new Scaffold());
add(new Slippy());
add(new Step());
add(new TridentBoost());
@@ -171,6 +172,7 @@ public class ModuleManager {
add(new Racist());
add(new StrongholdTriangulator());
add(new TimeChanger());
add(new Timer());
}
@@ -0,0 +1,339 @@
package me.retucio.sputnik.module.modules.movement;
import com.github.retucio.neutrino.EventListener;
import com.google.common.collect.Streams;
import me.retucio.sputnik.event.input.SneakEvent;
import me.retucio.sputnik.event.interact.PlaceBlockEvent;
import me.retucio.sputnik.event.render.Render3DEvent;
import me.retucio.sputnik.module.Category;
import me.retucio.sputnik.module.Module;
import me.retucio.sputnik.module.setting.SettingGroup;
import me.retucio.sputnik.module.setting.settings.*;
import me.retucio.sputnik.util.Colors;
import me.retucio.sputnik.util.InventoryUtil;
import me.retucio.sputnik.util.Lists;
import me.retucio.sputnik.util.NetworkUtil;
import me.retucio.sputnik.util.render.RenderUtil;
import net.minecraft.block.Block;
import net.minecraft.block.FallingBlock;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d;
import java.util.List;
public class Scaffold extends Module {
private final SettingGroup sgBlocks = addSg(new SettingGroup("bloques", false));
private final SettingGroup sgBridge = addSg(new SettingGroup("puente", true));
private final SettingGroup sgRender = addSg(new SettingGroup("render", false));
// todo: arreglar esta puta mierda
private final BooleanSetting rotate = sgGeneral.add(new BooleanSetting(
"rotar",
"mover la cabeza",
false
));
/* ajustes de selección de bloques */
private final ListSetting<Block> blocks = sgBlocks.add(new ListSetting<>(
"bloques",
"bloques a aplicar al filtro",
Lists.blockList,
Lists.allFalse(Lists.blockList),
Lists.blockNames
));
private final EnumSetting<ListMode> blocksFilter = sgBlocks.add(new EnumSetting<>(
"filtro",
"tipo de filtro a usar",
ListMode.class, ListMode.BLACKLIST
));
private final BooleanSetting autoSelectItem = sgBlocks.add(new BooleanSetting(
"autoselect",
"seleccionar slot más cercano con bloques automáticamente",
true
));
/* extender puente */
private final BooleanSetting extend = sgBridge.add(new BooleanSetting(
"extender",
"poner bloques en frente al caminar",
false
));
private final NumberSetting extendDistance = sgBridge.add(new NumberSetting(
"distancia a extender",
"cuánto extender",
2,
0,
4,
0.1
));
/* torre */
private final BooleanSetting tower = sgBridge.add(new BooleanSetting(
"torre",
"hacer torres verticales chulas",
false
));
private final NumberSetting towerSpeed = sgBridge.add(new NumberSetting(
"velocidad de torre",
"a qué velocidad hacer la torre",
0.5,
0,
1,
0.01
));
private final BooleanSetting towerWhileMoving = sgBridge.add(new BooleanSetting(
"torre moviéndose",
"te permite hacer una torre mientras te mueves",
false
));
/* otros */
private final BooleanSetting mjBridge = sgBridge.add(new BooleanSetting(
"mj bridge",
"hacer que saltar no eleve el nivel y del puente",
false
));
private final BooleanSetting sneakForDown = sgBridge.add(new BooleanSetting(
"descender",
"agacharse para descender",
true
));
private final BooleanSetting headhitter = sgBridge.add(new BooleanSetting(
"headhitter",
"poner bloques sobre tu cabeza",
false
));
/* ajustes de renderizado */
private final BooleanSetting outlines = sgRender.add(new BooleanSetting(
"contorno",
"renderizar contorno del bloque colocado",
true
));
private final ColorSetting outlineColor = sgRender.add(new ColorSetting(
"color del contorno",
"color a usar al renderizar el contorno",
Colors.mainColor,
false
));
private final NumberSetting lineWidth = sgRender.add(new NumberSetting(
"grosor de línea",
"grosor de línea del contorno",
1.5,
0.1,
10,
0.1
));
private final BooleanSetting fillings = sgRender.add(new BooleanSetting(
"relleno",
"renderizar relleno del bloque colocado",
false
));
private final ColorSetting fillingColor = sgRender.add(new ColorSetting(
"color del relleno",
"color a uisar al renderizar el relleno",
Colors.withAlpha(Colors.mainColor, 60),
false
));
private final BlockPos.Mutable bp = new BlockPos.Mutable();
private Integer mjY = null;
public Scaffold() {
super("andamios", "pone bloques bajo tus pies de manera automática", Category.MOVEMENT);
extend.onUpdate(extendDistance::setVisible);
tower.onUpdate(v -> {
towerSpeed.setVisible(v);
towerWhileMoving.setVisible(v);
});
outlines.onUpdate(v -> {
outlineColor.setVisible(v);
lineWidth.setVisible(v);
});
fillings.onUpdate(fillingColor::setVisible);
}
@Override
public void onDisable() {
mjY = null;
}
@Override
public void onTick() {
if (mc.player == null || mc.world == null) return;
Vec3d pos = mc.player.getEntityPos();
// extender puente si se está moviendo hacia adelante
if (extend.getValue() && isMoving() && mc.player.forwardSpeed > 0) {
Vec3d dir = Vec3d.fromPolar(0, mc.player.getYaw()).normalize().multiply(extendDistance.getValue());
pos = pos.add(dir.x, 0, dir.z);
}
// seleccionar nivel Y
double y;
if (mjBridge.getValue() && mjY != null && isMoving()) {
y = mjY;
} else {
y = pos.y - 0.5;
}
// descender con la tecla de agacharse
if (sneakForDown.getValue() && mc.options.sneakKey.isPressed()) {
if (mc.world.isAir(bp.withY(bp.getY() - 1))) {
y -= 1;
}
}
// colocar bloque
bp.set(pos.x, y, pos.z);
place(bp);
// colocar bloque encima de la cabeza
if (headhitter.getValue() && mc.options.jumpKey.isPressed() && !mc.options.sneakKey.isPressed()) {
place(mc.player.getBlockPos().up(2));
}
// poner bloques a los pies del jugador mientras asciende para hacer la torre
if (tower.getValue()
&& mc.options.jumpKey.isPressed()
&& !mc.options.sneakKey.isPressed()
&& !mc.player.getInventory().getSelectedStack().isEmpty()
&& !mc.world.isAir(mc.player.getBlockPos().down())) {
Vec3d velocity = mc.player.getVelocity();
Box playerBox = mc.player.getBoundingBox();
if (Streams.stream(mc.world.getBlockCollisions(mc.player, playerBox.offset(0, 1, 0))).toList().isEmpty()) {
if (towerWhileMoving.getValue() || !isMoving()) {
velocity = new Vec3d(velocity.x, towerSpeed.getValue(), velocity.z);
}
mc.player.setVelocity(velocity);
} else {
mc.player.setVelocity(velocity.x, Math.ceil(mc.player.getY()) - mc.player.getY(), velocity.z);
mc.player.setOnGround(true);
}
}
}
@EventListener
private void onRenderWorld(Render3DEvent event) {
if (outlines.getValue()) RenderUtil.drawBlockOutline(event.getMatrices(), bp, outlineColor.getValue(), lineWidth.getFloatValue(), false);
if (fillings.getValue()) RenderUtil.drawBlockFilled(event.getMatrices(), bp, fillingColor.getValue(), false);
}
@EventListener
private void onPlaceBlock(PlaceBlockEvent event) {
// guardar último valor Y para el mj bridge
if (mjBridge.getValue()) {
mjY = event.getResult().getBlockPos().getY();
}
}
@EventListener
private void onSneak(SneakEvent event) {
// no agacharse
if (sneakForDown.getValue()) {
event.cancel();
}
}
private void place(BlockPos pos) {
int slot = -1;
// seleccionar bloque
if (autoSelectItem.getValue()) {
List<Integer> slots = InventoryUtil.findAllSlots(this::isValidBlock);
for (int s : slots) {
if (PlayerInventory.isValidHotbarIndex(s)) {
slot = s;
break;
}
}
if (slot == -1) return;
} else {
slot = mc.player.getInventory().getSelectedSlot();
}
if (mc.player.getInventory().getSelectedSlot() != slot) {
mc.player.getInventory().setSelectedSlot(slot);
}
// colocar bloque
NetworkUtil.placeBlock(
pos, Hand.MAIN_HAND,
mc.player.getInventory().getSelectedSlot(),
rotate.getValue(),
false,
true,
true
);
}
// método helper para ver si un bloque cumple con el filtro
private boolean isValidBlock(ItemStack stack) {
if (!(stack.getItem() instanceof BlockItem)) return false;
Block block = ((BlockItem) stack.getItem()).getBlock();
boolean contains = blocks.isEnabled(block);
if (blocksFilter.is(ListMode.BLACKLIST) && contains) return false;
if (blocksFilter.is(ListMode.WHITELIST) && !contains) return false;
if (!Block.isShapeFullCube(block.getDefaultState().getCollisionShape(mc.world, BlockPos.ORIGIN))) {
return false;
}
if (block instanceof FallingBlock) {
return !FallingBlock.canFallThrough(mc.world.getBlockState(mc.player.getBlockPos().down()));
}
return true;
}
private boolean isMoving() {
return mc.player.forwardSpeed != 0
|| mc.player.sidewaysSpeed != 0;
}
public enum ListMode {
WHITELIST("lista blanca (incluir)"),
BLACKLIST("lista negra (excluir");
private final String name;
ListMode(String name) { this.name = name; }
@Override public String toString() { return name; }
}
}
@@ -88,6 +88,12 @@ public class PacketMine extends Module {
0.1
));
private final BooleanSetting dontBreak = sgGeneral.add(new BooleanSetting(
"no romper",
"evita romper el pico",
true
));
public PacketMine() {
super("selección de minado",
"selecciona bloques a minar con paquetes",
@@ -150,7 +156,9 @@ public class PacketMine extends Module {
currentOrderIndex = (currentOrderIndex + 1) % miningBlocks.size();
break;
}
if (!miningBlocks.isEmpty()) {
currentOrderIndex = (currentOrderIndex + 1) % miningBlocks.size();
}
} while (currentOrderIndex != startIndex);
if (!processed) {
@@ -252,6 +260,12 @@ public class PacketMine extends Module {
return false;
}
if (dontBreak.getValue() && mc.player.getMainHandStack().getMaxDamage() - mc.player.getMainHandStack().getDamage() <= 1) {
ChatUtil.warn("pico por romperse");
toggle();
return false;
}
mc.interactionManager.sendSequencedPacket(mc.world, sequence ->
new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, pos, dir, sequence));
mining = true;
@@ -143,7 +143,7 @@ public class AutoFish extends Module {
private int switchToFishingRod() {
if (mc.player.getActiveItem().isOf(Items.FISHING_ROD)) return mc.player.getInventory().getSelectedSlot();
List<Integer> slots = InventoryUtil.findItem(Items.FISHING_ROD);
List<Integer> slots = InventoryUtil.findAllSlots(stack -> stack.isOf(Items.FISHING_ROD));
for (int slot : slots) {
if (PlayerInventory.isValidHotbarIndex(slot)) {
mc.player.getInventory().setSelectedSlot(slot);
@@ -163,7 +163,7 @@ public class AutoTool extends Module {
if (result.getType() == HitResult.Type.MISS || !(result instanceof BlockHitResult bhr)) return;
BlockState state = mc.world.getBlockState(bhr.getBlockPos());
List<ItemStack> tools = InventoryUtil.getStacksOfComponentType(DataComponentTypes.TOOL);
List<ItemStack> tools = InventoryUtil.find(DataComponentTypes.TOOL);
if (tools.isEmpty()) return;
Map<Float, ItemStack> speeds = new HashMap<>();
@@ -0,0 +1,21 @@
package me.retucio.sputnik.module.modules.world;
import me.retucio.sputnik.module.Category;
import me.retucio.sputnik.module.Module;
import me.retucio.sputnik.module.setting.settings.NumberSetting;
public class Timer extends Module {
public NumberSetting multiplier = sgGeneral.add(new NumberSetting(
"multi",
"como en el Balatro",
1,
0.1,
10,
0.1
));
public Timer() {
super("cocaína", "cambia la velocidad de todo el en juego", Category.WORLD);
}
}
@@ -70,7 +70,20 @@ public class InventoryUtil {
return stacks;
}
public static List<ItemStack> getStacksOfTag(TagKey<Item> tag) {
public static List<Integer> findAllSlots(Predicate<ItemStack> predicate) {
List<Integer> slots = new ArrayList<>();
if (mc.player == null) return slots;
for (int i = 0; i < mc.player.getInventory().size(); i++) {
ItemStack stack = mc.player.getInventory().getStack(i);
if (predicate.test(stack)) {
slots.add(i);
}
}
return slots;
}
public static List<ItemStack> find(TagKey<Item> tag) {
if (mc.player == null) return null;
List<ItemStack> stacks = new ArrayList<>();
for (ItemStack stack : mc.player.getInventory()) {
@@ -83,7 +96,7 @@ public class InventoryUtil {
return stacks;
}
public static List<ItemStack> getStacksOfComponentType(ComponentType<?> componentType) {
public static List<ItemStack> find(ComponentType<?> componentType) {
List<ItemStack> stacks = new ArrayList<>();
if (mc.player == null) return stacks;
for (ItemStack stack : mc.player.getInventory()) {
@@ -256,20 +269,6 @@ public class InventoryUtil {
return matchingSlots;
}
public static List<Integer> findItem(Item item) {
List<Integer> matchingSlots = new ArrayList<>();
PlayerInventory inv = mc.player.getInventory();
for (int i = 0; i < inv.size(); i++) {
ItemStack stack = inv.getStack(i);
if (!stack.isEmpty() && stack.isOf(item)) {
matchingSlots.add(i);
}
}
return matchingSlots;
}
public static void quickMoveAll(HandledScreen<?> screen, ItemStack reference) {
if (mc.player == null || mc.interactionManager == null) return;
@@ -349,6 +348,4 @@ public class InventoryUtil {
public static Inventory getEchestInv() {
return echestInv;
}
}
@@ -2,15 +2,27 @@ package me.retucio.sputnik.util;
import me.retucio.sputnik.event.network.PacketEvent;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.ShapeContext;
import net.minecraft.client.MinecraftClient;
import net.minecraft.command.argument.EntityAnchorArgumentType;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.listener.PacketListener;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket;
import net.minecraft.network.packet.s2c.play.WorldTimeUpdateS2CPacket;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import java.util.ArrayList;
import java.util.List;
@@ -87,4 +99,74 @@ public class NetworkUtil {
mc.player.setSneaking(wasSneaking);
}
public static boolean placeBlock(BlockPos blockPos, Hand hand, int slot, boolean rotate, boolean swingHand, boolean checkEntities, boolean swapBack) {
if (slot < 0 || slot > 8) return false;
Block toPlace = Blocks.OBSIDIAN;
ItemStack i = hand == Hand.MAIN_HAND ? mc.player.getInventory().getStack(slot) : mc.player.getOffHandStack();
if (i.getItem() instanceof BlockItem blockItem) toPlace = blockItem.getBlock();
if (!canPlaceBlock(blockPos, checkEntities, toPlace)) return false;
Vec3d hitPos = Vec3d.ofCenter(blockPos);
BlockPos neighbour;
Direction side = getClosestSide(blockPos);
if (side == null) {
side = Direction.UP;
neighbour = blockPos;
} else {
neighbour = blockPos.offset(side);
hitPos = hitPos.add(side.getOffsetX() * 0.5, side.getOffsetY() * 0.5, side.getOffsetZ() * 0.5);
}
BlockHitResult bhr = new BlockHitResult(hitPos, side.getOpposite(), neighbour, false);
int prevSlot = mc.player.getInventory().getSelectedSlot();
if (rotate) {
mc.player.setYaw((float) EntityUtil.getYaw(hitPos));
mc.player.setPitch((float) EntityUtil.getPitch(hitPos));
}
InventoryUtil.swapWithHotbar(mc.player.getInventory().getSelectedSlot(), slot);
interactBlock(bhr, hand, swingHand);
if (swapBack) {
InventoryUtil.swapWithHotbar(mc.player.getInventory().getSelectedSlot(), prevSlot);
}
return true;
}
public static boolean canPlaceBlock(BlockPos blockPos, boolean checkEntities, Block block) {
if (blockPos == null) return false;
if (!World.isValid(blockPos)) return false;
if (!mc.world.getBlockState(blockPos).isReplaceable()) return false;
return !checkEntities || mc.world.canPlace(block.getDefaultState(), blockPos, ShapeContext.absent());
}
public static Direction getClosestSide(BlockPos blockPos) {
Vec3d lookVec = blockPos.toCenterPos().subtract(mc.player.getEyePos());
double bestRelevancy = -Double.MAX_VALUE;
Direction bestSide = null;
for (Direction side : Direction.values()) {
BlockPos neighbor = blockPos.offset(side);
BlockState state = mc.world.getBlockState(neighbor);
if (state.isAir()) continue;
if (!state.getFluidState().isEmpty()) continue;
double relevancy = side.getAxis().choose(lookVec.getX(), lookVec.getY(), lookVec.getZ()) * side.getDirection().offset();
if (relevancy > bestRelevancy) {
bestRelevancy = relevancy;
bestSide = side;
}
}
return bestSide;
}
}
+3 -1
View File
@@ -23,6 +23,7 @@
"mixins.network.ServerConnectorMixin",
"mixins.network.YggdrasilUserApiServiceMixin",
"mixins.player.PlayerEntityMixin",
"mixins.player.PlayerInputMixin",
"mixins.player.PlayerInventoryMixin",
"mixins.world.BlockCollisionSpliteratorMixin"
],
@@ -96,6 +97,7 @@
"mixins.world.DamageParticleFactoryMixin",
"mixins.world.DamageParticleMixin",
"mixins.world.EmitterParticleMixin",
"mixins.world.ParticleManagerMixin"
"mixins.world.ParticleManagerMixin",
"mixins.world.RenderTickCounterDynamicMixin"
]
}