This commit is contained in:
retuci0 committed 2026-05-07 16:27:24 +02:00
1 parent 531c3ef9aa
commit 09ed268576
10 files changed
+297 -107

No files matched your search

+5 -3
View File
@@ -1,4 +1,4 @@
# v4.8 # v4.9
## novedades ## novedades
@@ -8,13 +8,15 @@
#### módulos nuevos: #### módulos nuevos:
- notificaciones: te avisa de ciertos eventos mediante notificaciones
### arreglos / mejoras ### arreglos / mejoras
- `puntos de desconexión` ya renderiza la caja correctamente - `puntos de desconexión` ya renderiza la caja correctamente
- movido `aviso de baja durabilidad` a `notificaciones`
## problemas reconocidos ## problemas reconocidos
- lo de siempre, además de: - lo de siempre, además de:
- `inventario plus` no funciona en creativo - `inventario plus` no funciona en creativo
- `RPC de Discord` no funciona e incluso puede provocar crashes - `RPC de Discord` no funciona e incluso puede provocar crashes
- las cajas `puntos de desconexión` están mal renderizadas
+1 -1
View File
@@ -10,6 +10,6 @@ discord_rpc_version=1.0.3
neutrino_version=1.1.0 neutrino_version=1.1.0
jdk_version=25 jdk_version=25
mod_version=4.8 mod_version=4.9
maven_group=me.retucio maven_group=me.retucio
archives_base_name=sputnik archives_base_name=sputnik
@@ -24,6 +24,7 @@ import me.retucio.sputnik.ui.screen.UpdateScreen;
import me.retucio.sputnik.ui.widgets.buttons.settings.BindButton; import me.retucio.sputnik.ui.widgets.buttons.settings.BindButton;
import me.retucio.sputnik.ui.widgets.buttons.SettingButton; import me.retucio.sputnik.ui.widgets.buttons.SettingButton;
import me.retucio.sputnik.ui.widgets.buttons.settings.TextButton; import me.retucio.sputnik.ui.widgets.buttons.settings.TextButton;
import me.retucio.sputnik.ui.widgets.misc.NotificationWidget;
import me.retucio.sputnik.ui.widgets.panels.settings.ClientSettingsPanel; import me.retucio.sputnik.ui.widgets.panels.settings.ClientSettingsPanel;
import me.retucio.sputnik.ui.widgets.panels.SettingsPanel; import me.retucio.sputnik.ui.widgets.panels.SettingsPanel;
import me.retucio.sputnik.ui.widgets.Button; import me.retucio.sputnik.ui.widgets.Button;
@@ -6,6 +6,7 @@ import me.retucio.sputnik.module.modules.client.DiscordRPC;
import me.retucio.sputnik.module.modules.client.Friends; import me.retucio.sputnik.module.modules.client.Friends;
import me.retucio.sputnik.module.modules.client.Hud; import me.retucio.sputnik.module.modules.client.Hud;
import me.retucio.sputnik.module.modules.camera.*; import me.retucio.sputnik.module.modules.camera.*;
import me.retucio.sputnik.module.modules.client.Notifications;
import me.retucio.sputnik.module.modules.combat.*; import me.retucio.sputnik.module.modules.combat.*;
import me.retucio.sputnik.module.modules.inventory.*; import me.retucio.sputnik.module.modules.inventory.*;
import me.retucio.sputnik.module.modules.misc.*; import me.retucio.sputnik.module.modules.misc.*;
@@ -81,6 +82,7 @@ public class ModuleManager {
add(new DiscordRPC()); add(new DiscordRPC());
add(new Friends()); add(new Friends());
add(new Hud()); add(new Hud());
add(new Notifications());
} }
private void addCombat() { private void addCombat() {
@@ -154,7 +156,6 @@ public class ModuleManager {
add(new HandView()); add(new HandView());
add(new KeyPearl()); add(new KeyPearl());
add(new NoFall()); add(new NoFall());
add(new WarnLowDurability());
} }
private void addRender() { private void addRender() {
@@ -0,0 +1,219 @@
package me.retucio.sputnik.module.modules.client;
import me.retucio.sputnik.module.Category;
import me.retucio.sputnik.module.Module;
import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.misc.FakePlayer;
import me.retucio.sputnik.module.setting.SettingGroup;
import me.retucio.sputnik.module.setting.settings.*;
import me.retucio.sputnik.ui.hud.HudRenderer;
import me.retucio.sputnik.ui.widgets.misc.NotificationWidget;
import me.retucio.sputnik.util.Lists;
import net.minecraft.ChatFormatting;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import java.util.ArrayList;
import java.util.List;
public class Notifications extends Module {
private final SettingGroup sgSound = addSg(new SettingGroup("sonido", false));
private final SettingGroup sgPlayer = addSg(new SettingGroup("jugador en rango", true));
private final SettingGroup sgDurability = addSg(new SettingGroup("baja durabilidad", true));
/* ajustes generales */
private final NumberSetting duration = sgGeneral.add(new NumberSetting(
"duración",
"duración de las notis en segundos",
5, 0.1, 10, 0.1
));
private final BooleanSetting popup = sgGeneral.add(new BooleanSetting(
"pop-up",
"mostrar pop-up de notificación",
true
));
/* ajustes del volumen */
private final OptionSetting<SoundEvent> sound = sgSound.add(new OptionSetting<>(
"sonido",
"sonido a reproducir con las notis",
Lists.soundList,
SoundEvents.NOTE_BLOCK_BELL.value(),
Lists.soundNames
));
private final NumberSetting volume = sgSound.add(new NumberSetting(
"volumen",
"volumen del sonido",
70, 0, 125, 1
));
private final NumberSetting pitch = sgSound.add(new NumberSetting(
"frecuencia",
"altura del sonido",
70, 0, 125, 1
));
/* cuando un jugador entra en rango */
private final BooleanSetting warnPlayerInRange = sgPlayer.add(new BooleanSetting(
"jugador en rango",
"notificar cuando un jugador entre en rango",
true
));
private final NumberSetting playerRange = sgPlayer.add(new NumberSetting(
"rango de jugadores",
"rango a tener en cuenta al notificar",
12,
1,
32,
1
)).visibility(warnPlayerInRange::getValue);
private final BooleanSetting ignoreFakePlayer = sgPlayer.add(new BooleanSetting(
"ignorar jugador falso",
"ignorar al muñeco de \"jugador falso\"",
false
));
/* cuando una herramienta tiene la durabilidad baja */
private final BooleanSetting warnToolLowDurability = sgDurability.add(new BooleanSetting(
"baja durabilidad",
"notificar cuando la herramienta en uso tiene baja durabilidad",
true
));
private final ListSetting<Item> excludeItems = sgDurability.add(new ListSetting<>(
"items a excluir",
"no avisar de la baja durabilidad de estos",
Lists.itemList,
Lists.allFalse(Lists.itemList),
Lists.itemNames
));
private final NumberSetting limitPercentage = sgDurability.add(new NumberSetting(
"porcentaje", "porcentaje de durabilidad restante a la que se te avisa",
5, 1, 100, 1
));
/* fields */
private final List<Player> notifiedPlayers = new ArrayList<>();
private final List<ItemStack> notifiedTools = new ArrayList<>();
private float prevPercentage = -1;
public Notifications() {
super(
"notificaciones",
"te notifica cuando sucedan ciertos eventos",
Category.CLIENT
);
duration.onUpdate(v -> NotificationWidget.duration = (int) (v * 1000));
}
@Override
public void onDisable() {
notifiedPlayers.clear();
notifiedTools.clear();
super.onDisable();
}
@Override
public void onTick() {
if (mc.player == null || mc.level == null) return;
checkForPlayersInRange();
checkForLowDurabilityTools();
}
// comprobar si algún jugador ha entrado en el rango
private void checkForPlayersInRange() {
if (!warnPlayerInRange.getValue()) return;
for (Player player : mc.level.players()) {
if (player == mc.player) continue;
if (player == ModuleManager.INSTANCE.getModuleByClass(FakePlayer.class).getPlayer()
&& ignoreFakePlayer.getValue()) continue;
float d = player.distanceTo(mc.player);
if (d <= playerRange.getValue() * 16) {
if (!notifiedPlayers.contains(player)) {
notifiedPlayers.add(player);
String title = ChatFormatting.GREEN + player.getDisplayName().getString() + ChatFormatting.RESET + " ha entrado en rango!";
String desc = player.getDisplayName().getString() + " está a " + ChatFormatting.GOLD + (int) d + ChatFormatting.RESET + " bloques de distancia.";
push(title, desc);
}
} else {
notifiedPlayers.remove(player);
}
}
}
// comprobar si la herramienta en uso tiene la durabilidad por debajo del porcentaje seleccionado
private void checkForLowDurabilityTools() {
if (!warnToolLowDurability.getValue()) return;
ItemStack stack = mc.player.getItemInHand(InteractionHand.MAIN_HAND);
if (notifiedTools.contains(stack) || excludeItems.isEnabled(stack.getItem())) return;
float percentage = (1 - (float) stack.getDamageValue() / stack.getMaxDamage()) * 100;
if (percentage <= limitPercentage.getValue() && percentage < prevPercentage) {
String customName = stack.getCustomName() == null ? "" : " \"" + stack.getCustomName().getString() + "\"";
String desc = ChatFormatting.AQUA + stack.getItemName().getString()
+ ChatFormatting.GREEN + customName + ChatFormatting.RESET
+ " a " + ChatFormatting.GOLD + ((int) percentage + "") + "%"
+ ChatFormatting.RESET + " de durabilidad";
push("baja durabilidad!", desc);
notifiedTools.add(stack);
}
prevPercentage = percentage;
}
// enviar una notificación
private void push(String title, String desc) {
if (popup.getValue()) {
HudRenderer.pushNotification(title, desc);
}
if (sound.getValue() != SoundEvents.EMPTY) {
mc.level.playSound(mc.player, mc.player.blockPosition(),
sound.getValue(),
SoundSource.AMBIENT,
toExponential(volume),
toExponential(pitch)
);
}
}
// el sistema decibélico es un sistema logarítmico
private float toExponential(NumberSetting setting) {
double linear = setting.getValue();
double normalized = linear / (setting.getMax() - setting.getMax() / 4);
double exponential = Math.pow(normalized, 3);
if (exponential < 0.01) exponential = 0;
return (float) exponential;
}
}
@@ -1,102 +0,0 @@
package me.retucio.sputnik.module.modules.player;
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.BooleanSetting;
import me.retucio.sputnik.module.setting.settings.NumberSetting;
import me.retucio.sputnik.module.setting.settings.OptionSetting;
import me.retucio.sputnik.util.ChatUtil;
import me.retucio.sputnik.util.Lists;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.ItemStack;
import java.util.ArrayList;
import java.util.List;
public class WarnLowDurability extends Module {
private final SettingGroup sgWarn = addSg(new SettingGroup("aviso", true));
private final SettingGroup sgSound = addSg(new SettingGroup("sonido", true));
private final NumberSetting limitPercentage = sgGeneral.add(new NumberSetting("porcentaje", "porcentaje de durabilidad restante a la que se te avisa",
5, 1, 100, 1));
private final BooleanSetting message = sgWarn.add(new BooleanSetting("enviar mensaje", "enviar un mensaje para alertar al usuario", true));
private final BooleanSetting playSound = sgWarn.add(new BooleanSetting("reproducir sonido", "reproducir un sonido para alertar al usuario", true));
private final OptionSetting<SoundEvent> sound = sgSound.add(new OptionSetting<>("sonido", "qué sonido reproducir",
Lists.soundList, SoundEvents.NOTE_BLOCK_BELL.value(), Lists.soundNames));
private final NumberSetting volume = sgSound.add(new NumberSetting("volumen", "volumen del sonido", 70, 0, 125, 1));
private final NumberSetting pitch = sgSound.add(new NumberSetting("frecuencia", "altura del sonido", 70, 0, 125, 1));
private final List<ItemStack> warned = new ArrayList<>();
private float prevPercentage = -1;
public WarnLowDurability() {
super("aviso de baja dur.",
"te avisa cuando la herramienta que sostengas sobrepase un límite de durabilidad",
Category.PLAYER);
playSound.onUpdate(v -> {
sound.visibility(v);
volume.visibility(v);
pitch.visibility(v);
});
}
@Override
public void onTick() {
if (mc.player == null || mc.level == null) return;
ItemStack stack = mc.player.getItemInHand(InteractionHand.MAIN_HAND);
if (warned.contains(stack)) return;
float percentage = (1 - (float) stack.getDamageValue() / stack.getMaxDamage()) * 100;
if (percentage <= limitPercentage.getValue() && percentage < prevPercentage) {
if (playSound.getValue())
mc.level.playSound(mc.player, mc.player.blockPosition(),
sound.getValue(),
SoundSource.AMBIENT,
toExponential(volume),
toExponential(pitch)
);
if (message.getValue()) {
String customName = stack.getCustomName() == null ? "" : " \"" + stack.getCustomName().getString() + "\"";
Component text = Component.literal(ChatFormatting.AQUA + stack.getItemName().getString()
+ ChatFormatting.GREEN + customName + ChatFormatting.RESET
+ " a " + ChatFormatting.GOLD + ((int) percentage + "") + "%"
+ ChatFormatting.RESET + " de durabilidad");
ChatUtil.warn(text);
}
warned.add(stack);
}
prevPercentage = percentage;
}
@Override
public void onDisable() {
warned.clear();
super.onDisable();
}
// el sistema decibélico es un sistema logarítmico
private float toExponential(NumberSetting setting) {
double linear = setting.getValue();
double normalized = linear / (setting.getMax() - setting.getMax() / 4);
double exponential = Math.pow(normalized, 3);
if (exponential < 0.01) exponential = 0;
return (float) exponential;
}
}
@@ -4,6 +4,7 @@ import me.retucio.sputnik.config.ConfigManager;
import me.retucio.sputnik.module.ModuleManager; import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.client.Hud; import me.retucio.sputnik.module.modules.client.Hud;
import me.retucio.sputnik.ui.hud.elements.*; import me.retucio.sputnik.ui.hud.elements.*;
import me.retucio.sputnik.ui.widgets.misc.NotificationWidget;
import net.minecraft.client.DeltaTracker; import net.minecraft.client.DeltaTracker;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.GuiGraphicsExtractor;
@@ -14,6 +15,7 @@ import java.awt.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Stack;
public class HudRenderer { public class HudRenderer {
@@ -21,6 +23,7 @@ public class HudRenderer {
private static final Minecraft mc = Minecraft.getInstance(); private static final Minecraft mc = Minecraft.getInstance();
private static final List<HudElement> elements = new ArrayList<>(); private static final List<HudElement> elements = new ArrayList<>();
private static final Stack<NotificationWidget> notifications = new Stack<>();
private static boolean initialized = false; private static boolean initialized = false;
public static void init() { public static void init() {
@@ -101,6 +104,16 @@ public class HudRenderer {
element.renderInGame(gui, dt.getGameTimeDeltaTicks(), hud); element.renderInGame(gui, dt.getGameTimeDeltaTicks(), hud);
} }
} }
List<NotificationWidget> toRemove = new ArrayList<>();
for (NotificationWidget notification : notifications) {
notification.setIndex(notifications.indexOf(notification));
notification.render(gui, 0, 0, 0);
if (System.currentTimeMillis() >= notification.popTime) {
toRemove.add(notification);
}
}
notifications.removeAll(toRemove);
} }
private static boolean shouldSkipRendering() { private static boolean shouldSkipRendering() {
@@ -116,6 +129,10 @@ public class HudRenderer {
|| mc.screen instanceof HudEditorScreen; || mc.screen instanceof HudEditorScreen;
} }
public static void pushNotification(String title, String desc) {
notifications.push(new NotificationWidget(title, desc));
}
public static List<HudElement> getElements() { public static List<HudElement> getElements() {
return elements; return elements;
} }
@@ -15,6 +15,7 @@ import me.retucio.sputnik.ui.widgets.buttons.FriendButton;
import me.retucio.sputnik.ui.widgets.buttons.settings.ListButton; import me.retucio.sputnik.ui.widgets.buttons.settings.ListButton;
import me.retucio.sputnik.ui.widgets.buttons.ModuleButton; import me.retucio.sputnik.ui.widgets.buttons.ModuleButton;
import me.retucio.sputnik.ui.widgets.buttons.SettingButton; import me.retucio.sputnik.ui.widgets.buttons.SettingButton;
import me.retucio.sputnik.ui.widgets.misc.NotificationWidget;
import me.retucio.sputnik.ui.widgets.panels.FriendsPanel; import me.retucio.sputnik.ui.widgets.panels.FriendsPanel;
import me.retucio.sputnik.ui.widgets.panels.settings.ClientSettingsPanel; import me.retucio.sputnik.ui.widgets.panels.settings.ClientSettingsPanel;
import me.retucio.sputnik.ui.widgets.panels.settings.ColorPickerPanel; import me.retucio.sputnik.ui.widgets.panels.settings.ColorPickerPanel;
@@ -0,0 +1,49 @@
package me.retucio.sputnik.ui.widgets.misc;
import me.retucio.sputnik.ui.widgets.Widget;
import me.retucio.sputnik.util.Colors;
import net.minecraft.client.gui.GuiGraphicsExtractor;
public class NotificationWidget extends Widget {
public static int duration = 5000;
private static final int PADDING = 4;
private final String title, desc;
private int index;
public final long pushTime;
public final long popTime;
public NotificationWidget(String title, String desc) {
super(0, 0,
Math.max(mc.font.width(title), mc.font.width(desc)) + PADDING * 2,
mc.font.lineHeight * 2 + PADDING * 3);
this.title = title;
this.desc = desc;
this.x = mc.getWindow().getGuiScaledWidth() - w - 2;
this.pushTime = System.currentTimeMillis();
this.popTime = pushTime + duration;
}
@Override
public void render(GuiGraphicsExtractor gui, int mx, int my, float d) {
x = mc.getWindow().getGuiScaledWidth() - w - 2;
y = mc.getWindow().getGuiScaledHeight() - (index + 1) * (h + 2);
gui.fill(x, y, x + w, y + h, Colors.panelBgColor.getRGB());
gui.text(mc.font, title, x + PADDING, y + PADDING, -1, true);
gui.text(mc.font, desc, x + PADDING, y + PADDING + mc.font.lineHeight + 2, 0xFFAAAAAA, true);
float progress = (float) (popTime - System.currentTimeMillis()) / duration;
progress = Math.clamp(progress, 0f, 1f);
gui.fill(x, y + h - 2, x + (int) (progress * w), y + h, Colors.mainColor.getRGB());
}
public void setIndex(int index) {
this.index = index;
}
}
@@ -5,6 +5,7 @@ import net.minecraft.core.particles.ParticleType;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.inventory.MenuType; import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
@@ -65,6 +66,7 @@ public class Lists {
soundList.stream().map(sound -> Component.translatable( soundList.stream().map(sound -> Component.translatable(
sound.location().toShortLanguageKey() sound.location().toShortLanguageKey()
).getString()).toList()); ).getString()).toList());
soundNames.replace(SoundEvents.EMPTY, "NINGUNO");
screenNames = getMapOfLists(screenList, screenNames = getMapOfLists(screenList,
screenList.stream().map(screen -> Component.translatable( screenList.stream().map(screen -> Component.translatable(