Compare commits

...
2 Commits
Author SHA1 Message Date
retucio ab191a9016 v6.6 2026-10-11 11:56:22 +02:00
retucio 629d03ff92 v6.5 2026-09-14 19:17:07 +02:00
98 changed files with 1656 additions and 1099 deletions

No files matched your search

+2 -2
View File
@@ -5,7 +5,7 @@
# jenny's mod 2 (100% real) # jenny's mod 2 (100% real)
> Minecraft Fabric 26.2 mod that adds some "QOL" features, mostly related to the camera. > Minecraft Fabric 26.3 mod that adds some "QOL" features, mostly related to the camera.
## installation ## installation
@@ -16,7 +16,7 @@
4. move it to your mods dir (prolly `%appdata%/.minecraft/mods`) 4. move it to your mods dir (prolly `%appdata%/.minecraft/mods`)
make sure to have a Minecraft and Fabric version compatible with the mod (MC `26.2`; Fabric `0.19.3`) make sure to have a Minecraft and Fabric version compatible with the mod (MC `26.3`; Fabric `0.19.5`)
issues could arise when using it with other mods, especially other clients, since they could conflict issues could arise when using it with other mods, especially other clients, since they could conflict
+3 -3
View File
@@ -5,17 +5,17 @@
# jenny's mod 2 100% real # jenny's mod 2 100% real
> mod para Minecraft Fabric 26.2 que añade algunas cosas "QOL", mayormente relacionadas a la cámara. > mod para Minecraft Fabric 26.3 que añade algunas cosas "QOL", mayormente relacionadas a la cámara.
## instalación ## instalación
### para gente normal: ### para gente normal:
1. ir a [lanzamientos](https://codeberg.org/retucio/sputnik/releases) 1. ir a [lanzamientos](https://codeberg.org/retucio/sputnik/releases)
2. selecionar la versión más reciente 2. seleccionar la versión más reciente
3. descargar el .jar 3. descargar el .jar
4. moverlo a tu directorio de mods (probablemente `%appdata%/.minecraft/mods`) 4. moverlo a tu directorio de mods (probablemente `%appdata%/.minecraft/mods`)
asegúrate de tener una version de Minecraft y Fabric compatibles con el mod (MC `26.2`; Fabric `0.19.3`) asegúrate de tener una version de Minecraft y Fabric compatibles con el mod (MC `26.3`; Fabric `0.19.5`)
es posible que haya problemas al usarlo junto a otros mods, especialmente junto a otros clientes, pues pueden conflictar entre ellos. es posible que haya problemas al usarlo junto a otros mods, especialmente junto a otros clientes, pues pueden conflictar entre ellos.
### para frikis de 200 de iq ### para frikis de 200 de iq
+6 -6
View File
@@ -1,20 +1,20 @@
# v6.4 # v6.6
## novedades ## novedades
- README en inglés - actualizado a 26.3, un verdadero grano en el culo
- capturas actualizadas (las de los README)
### adiciones ### adiciones
#### módulos nuevos: - pestaña de ajustes del mod
- macros de tecla
### arreglos / mejoras ### arreglos / mejoras
- ahora la detección de clics sobre cabezales de grupos de ajustes funciona correctamente - algún que otro bugfix
## problemas reconocidos ## problemas reconocidos
- `reponer` no funciona - `reponer` no funciona
- `copiar` tras sacar una captura con `capturas` no funciona correctamente - `copiar` tras sacar una captura con `capturas` no funciona correctamente
- lo de siempre. - \+ lo de siempre.
+6 -6
View File
@@ -1,15 +1,15 @@
org.gradle.jvmargs=-Xmx2G org.gradle.jvmargs=-Xmx2G
org.gradle.parallel=true org.gradle.parallel=true
minecraft_version=26.2 minecraft_version=26.3
loader_version=0.19.3 loader_version=0.19.5
loom_version=1.17-SNAPSHOT loom_version=1.18-SNAPSHOT
fabric_api_version=0.154.0+26.2 fabric_api_version=0.160.7+26.3
discord_rpc_version=1.0.3 discord_rpc_version=1.0.3
neutrino_version=1.1.0 neutrino_version=1.1.0
jdk_version=25 jdk_version=25
mod_version=6.4 mod_version=6.6
maven_group=me.retucio maven_group=me.retucio
archives_base_name=sputnik archives_base_name=sputnik
+1 -1
View File
@@ -1,6 +1,6 @@
#Sat Aug 29 22:10:52 CEST 2026 #Sat Aug 29 22:10:52 CEST 2026
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.0-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
+45 -13
View File
@@ -2,6 +2,7 @@ package me.retucio.sputnik;
import com.github.retucio.neutrino.EventBus; import com.github.retucio.neutrino.EventBus;
import com.github.retucio.neutrino.EventListener; import com.github.retucio.neutrino.EventListener;
import com.mojang.blaze3d.platform.InputConstants;
import me.retucio.sputnik.cape.CapeManager; import me.retucio.sputnik.cape.CapeManager;
import me.retucio.sputnik.command.CommandManager; import me.retucio.sputnik.command.CommandManager;
import me.retucio.sputnik.command.commands.BindCommand; import me.retucio.sputnik.command.commands.BindCommand;
@@ -55,8 +56,6 @@ import net.minecraft.network.chat.Component;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.lwjgl.glfw.GLFW;
public class Sputnik implements ClientModInitializer { public class Sputnik implements ClientModInitializer {
@@ -118,7 +117,7 @@ public class Sputnik implements ClientModInitializer {
CapeManager.INSTANCE = new CapeManager(); CapeManager.INSTANCE = new CapeManager();
EVENT_BUS.post(new LoadCapeManagerEvent()); EVENT_BUS.post(new LoadCapeManagerEvent());
ModuleManager.INSTANCE = new ModuleManager(); ModuleManager.INSTANCE = new ModuleManager();
EVENT_BUS.post(new LoadModuleManagerEvent()); EVENT_BUS.post(new LoadModuleManagerEvent());
CommandManager.INSTANCE = new CommandManager(); CommandManager.INSTANCE = new CommandManager();
@@ -157,32 +156,64 @@ public class Sputnik implements ClientModInitializer {
// se ejecuta cada vez que se presiona una tecla // se ejecuta cada vez que se presiona una tecla
public void onInput(int key, int action) { public void onInput(int key, int action) {
// En SDL el valor 0 es UNKNOWN (y los botones del ratón empiezan en 1).
if (key == InputConstants.UNKNOWN.getValue() || key == -1) return;
// prevenir interrumpir combos de F3 // prevenir interrumpir combos de F3
if (key == GLFW.GLFW_KEY_F3) return; if (key == InputConstants.KEY_F3) return;
boolean anyFocused = isAnySettingButtonFocused() || ClickGui.INSTANCE.isCapturingInput(); boolean anyFocused = isAnySettingButtonFocused() || ClickGui.INSTANCE.isCapturingInput();
ClickGui.INSTANCE.setAnyFocused(anyFocused); ClickGui.INSTANCE.setAnyFocused(anyFocused);
if (action != GLFW.GLFW_RELEASE) { // Las KeySetting y los campos de texto reciben el mismo código SDL scancode que
// guardan sus valores; procesarlos antes evita que el bind capturado dispare un módulo.
if (anyFocused) handleSettingButtonsKey(key, action);
if (action != InputConstants.RELEASE) {
if (BindCommand.onKeyPress(key)) return; if (BindCommand.onKeyPress(key)) return;
if (action == GLFW.GLFW_PRESS && MacroManager.INSTANCE.onKeyPress(key)) return; if (action == InputConstants.PRESS && MacroManager.INSTANCE.onKeyPress(key)) return;
if (action == GLFW.GLFW_PRESS) { if (action == InputConstants.PRESS) {
handleModuleToggle(key, anyFocused); handleModuleToggle(key, anyFocused);
handleClickGuiKey(key, anyFocused); handleClickGuiKey(key, anyFocused);
handleHudEditorKey(key, anyFocused); handleHudEditorKey(key, anyFocused);
} }
// solo reenviar teclas del teclado
if (key >= 32) {
handleSettingButtonsKey(key, action);
}
} else if (!anyFocused) { } else if (!anyFocused) {
handleModuleRelease(key); handleModuleRelease(key);
} }
} }
public boolean onMouseInput(int button, int action) {
KeyUtil.setMouseButtonDown(button, action == InputConstants.PRESS);
boolean captured = false;
for (Button settingButton : ClickGui.INSTANCE.getClientSettingsPanel().getButtons()) {
if (settingButton instanceof BindButton bindButton && bindButton.isFocused()) {
bindButton.onMouse(button, action);
captured = true;
}
}
for (SettingsPanel panel : ClickGui.INSTANCE.getSettingsPanels()) {
for (Button settingButton : panel.getButtons()) {
if (settingButton instanceof BindButton bindButton && bindButton.isFocused()) {
bindButton.onMouse(button, action);
captured = true;
}
}
}
if (captured) return true;
onInput(KeyUtil.encodeMouseButton(button), action);
return false;
}
// verifica si algún botón de ajustes está escuchando // verifica si algún botón de ajustes está escuchando
private boolean isAnySettingButtonFocused() { private boolean isAnySettingButtonFocused() {
if (ClickGui.INSTANCE == null) return false; if (ClickGui.INSTANCE == null) return false;
for (Button button : ClickGui.INSTANCE.getClientSettingsPanel().getButtons())
if ((button instanceof BindButton bindButton && bindButton.isFocused())
|| (button instanceof TextButton textButton && textButton.isFocused())
|| (button instanceof FileButton fileButton && fileButton.isFocused())) {
return true;
}
for (SettingsPanel sf : ClickGui.INSTANCE.getSettingsPanels()) for (SettingsPanel sf : ClickGui.INSTANCE.getSettingsPanels())
for (Button sb : sf.getButtons()) for (Button sb : sf.getButtons())
if ((sb instanceof BindButton b && b.isFocused()) if ((sb instanceof BindButton b && b.isFocused())
@@ -200,7 +231,7 @@ public class Sputnik implements ClientModInitializer {
for (Module module : ModuleManager.INSTANCE.getModules()) { for (Module module : ModuleManager.INSTANCE.getModules()) {
// evitar interrumpir combinaciones de teclas del F3 // evitar interrumpir combinaciones de teclas del F3
if (key != module.getKey() || anyFocused || KeyUtil.isKeyDown(GLFW.GLFW_KEY_F3)) continue; if (key != module.getKey() || anyFocused || KeyUtil.isKeyDown(InputConstants.KEY_F3)) continue;
if (module.shouldToggleOnBindRelease() && !module.isEnabled()) if (module.shouldToggleOnBindRelease() && !module.isEnabled())
module.setEnabled(true); module.setEnabled(true);
@@ -211,6 +242,7 @@ public class Sputnik implements ClientModInitializer {
// se ocupa de hacer los botones de ajustes que lo necesiten escuchar teclas // se ocupa de hacer los botones de ajustes que lo necesiten escuchar teclas
private void handleSettingButtonsKey(int key, int action) { private void handleSettingButtonsKey(int key, int action) {
ClickGui.INSTANCE.getClientSettingsPanel().onKey(key, action);
for (SettingsPanel sf : ClickGui.INSTANCE.getSettingsPanels()) { for (SettingsPanel sf : ClickGui.INSTANCE.getSettingsPanels()) {
for (SettingButton<?> sb : sf.getButtons()) { for (SettingButton<?> sb : sf.getButtons()) {
if (sb instanceof BindButton bb) bb.onKey(key, action); if (sb instanceof BindButton bb) bb.onKey(key, action);
@@ -296,4 +328,4 @@ public class Sputnik implements ClientModInitializer {
public static String getVersionName() { public static String getVersionName() {
return MOD_ID + "_v" + MOD_VERSION + "_" + SharedConstants.getCurrentVersion().name(); return MOD_ID + "_v" + MOD_VERSION + "_" + SharedConstants.getCurrentVersion().name();
} }
} }
@@ -16,7 +16,7 @@ import java.util.List;
public abstract class Command { public abstract class Command {
// utilizar los "registries" ya existentes de Brigadier para el autocompletado // utilizar los "registries" ya existentes de Brigadier para el autocompletado
protected static final CommandBuildContext REGISTRY_ACCESS = Commands.createValidationContext(VanillaRegistries.createLookup()); protected static final CommandBuildContext REGISTRY_ACCESS = Commands.createValidationContext(VanillaRegistries.createWorldLookup());
protected static final int SUCCESS = com.mojang.brigadier.Command.SINGLE_SUCCESS; protected static final int SUCCESS = com.mojang.brigadier.Command.SINGLE_SUCCESS;
protected static final Minecraft mc = Minecraft.getInstance(); protected static final Minecraft mc = Minecraft.getInstance();
@@ -36,11 +36,12 @@ public class MacroCommand extends Command {
list(); list();
return SUCCESS; return SUCCESS;
})) }))
// por ahora "add" solo crea macros de chat
.then(literal("add") .then(literal("add")
.then(argument("nombre", StringArgumentType.word()).executes(ctx -> { .then(argument("nombre", StringArgumentType.word()).executes(ctx -> {
String name = ctx.getArgument("nombre", String.class); String name = ctx.getArgument("nombre", String.class);
if (MacroManager.INSTANCE.add(new Macro(name))) if (MacroManager.INSTANCE.add(new Macro.Chat(name)))
ChatUtil.info(Component.translatable("sputnik.commands.macro.added", ChatUtil.info(Component.translatable("sputnik.commands.macro.added",
ChatFormatting.AQUA + name)); ChatFormatting.AQUA + name));
else else
@@ -60,7 +61,7 @@ public class MacroCommand extends Command {
.then(literal("line") .then(literal("line")
.then(argument("nombre", StringArgumentType.word()).suggests(MACROS) .then(argument("nombre", StringArgumentType.word()).suggests(MACROS)
.then(argument("línea", StringArgumentType.greedyString()).executes(ctx -> { .then(argument("línea", StringArgumentType.greedyString()).executes(ctx -> {
Macro macro = get(ctx.getArgument("nombre", String.class)); Macro.Chat macro = getChat(ctx.getArgument("nombre", String.class));
if (macro == null) return SUCCESS; if (macro == null) return SUCCESS;
String line = ctx.getArgument("línea", String.class); String line = ctx.getArgument("línea", String.class);
@@ -73,7 +74,7 @@ public class MacroCommand extends Command {
})))) }))))
.then(literal("clear") .then(literal("clear")
.then(argument("nombre", StringArgumentType.word()).suggests(MACROS).executes(ctx -> { .then(argument("nombre", StringArgumentType.word()).suggests(MACROS).executes(ctx -> {
Macro macro = get(ctx.getArgument("nombre", String.class)); Macro.Chat macro = getChat(ctx.getArgument("nombre", String.class));
if (macro == null) return SUCCESS; if (macro == null) return SUCCESS;
macro.getLines().clear(); macro.getLines().clear();
@@ -97,6 +98,19 @@ public class MacroCommand extends Command {
return macro; return macro;
} }
// para los subcomandos que solo tienen sentido con líneas de chat (line, clear): si la
// macro existe pero es de otro tipo, avisa y devuelve null
private static Macro.Chat getChat(String name) {
Macro macro = get(name);
if (macro == null) return null;
if (!(macro instanceof Macro.Chat chat)) {
ChatUtil.error(Component.translatable("sputnik.commands.macro.notchat", macro.getName()));
return null;
}
return chat;
}
private static void list() { private static void list() {
List<Macro> macros = MacroManager.INSTANCE.getMacros(); List<Macro> macros = MacroManager.INSTANCE.getMacros();
@@ -106,9 +120,17 @@ public class MacroCommand extends Command {
} }
ChatUtil.info(Component.translatable("sputnik.commands.macro.list", macros.size())); ChatUtil.info(Component.translatable("sputnik.commands.macro.list", macros.size()));
for (Macro macro : macros) for (Macro macro : macros) {
// líneas en las de chat, teclas en las Keybind
int count = switch (macro) {
case Macro.Chat chat -> chat.getLines().size();
case Macro.Keybind keybind -> keybind.getKeys().size();
default -> 0;
};
ChatUtil.addMessage(ChatFormatting.GRAY + " - " + macro.getName() ChatUtil.addMessage(ChatFormatting.GRAY + " - " + macro.getName()
+ ChatFormatting.DARK_GRAY + " [" + KeyUtil.getKeyName(macro.getKey()) + "] " + ChatFormatting.DARK_GRAY + " [" + KeyUtil.getKeyName(macro.getKey()) + "] "
+ macro.getLines().size()); + count);
}
} }
} }
@@ -50,7 +50,7 @@ public class SendCommand extends Command {
message, message,
instant, instant,
salt, salt,
messageSignature, java.util.Optional.ofNullable(messageSignature),
lastSeenMessages.update() lastSeenMessages.update()
)); ));
} }
@@ -58,4 +58,4 @@ public class SendCommand extends Command {
return SUCCESS; return SUCCESS;
})); }));
} }
} }
@@ -8,7 +8,7 @@ import me.retucio.sputnik.event.input.KeyEvent;
import me.retucio.sputnik.util.EntityUtil; import me.retucio.sputnik.util.EntityUtil;
import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.commands.SharedSuggestionProvider;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.awt.*; import java.awt.*;
@@ -43,7 +43,7 @@ public class SpectateCommand extends Command {
@EventListener @EventListener
public void onKey(KeyEvent event) { public void onKey(KeyEvent event) {
if (mc.getCameraEntity() != mc.player && mc.gui.screen() == null if (mc.getCameraEntity() != mc.player && mc.gui.screen() == null
&& event.getKey() == GLFW.GLFW_KEY_ESCAPE && event.getAction() != GLFW.GLFW_RELEASE ) { && event.getKey() == InputConstants.KEY_ESCAPE && event.getAction() != InputConstants.RELEASE ) {
event.cancel(); event.cancel();
mc.setCameraEntity(mc.player); mc.setCameraEntity(mc.player);
} }
@@ -1,6 +1,7 @@
package me.retucio.sputnik.config; package me.retucio.sputnik.config;
import me.retucio.sputnik.util.I18nUtil; import me.retucio.sputnik.util.I18nUtil;
import me.retucio.sputnik.util.KeyUtil;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@@ -14,7 +15,7 @@ import java.util.Map;
public class BinarySerializer { public class BinarySerializer {
private static final int MAGIC_NUMBER = 0x53505554; // "SPUT" private static final int MAGIC_NUMBER = 0x53505554; // "SPUT"
private static final int VERSION = 3; private static final int VERSION = 6;
private static final int MIN_VERSION = 2; private static final int MIN_VERSION = 2;
private static final byte TYPE_NULL = 0; private static final byte TYPE_NULL = 0;
@@ -26,6 +27,9 @@ public class BinarySerializer {
private static final byte TYPE_INT_ARRAY = 6; private static final byte TYPE_INT_ARRAY = 6;
private static final byte TYPE_FRAME_DATA = 7; private static final byte TYPE_FRAME_DATA = 7;
private static final byte MACRO_CHAT = 0;
private static final byte MACRO_KEYBIND = 1;
public static void writeConfig(ClientConfig config, File file) throws IOException { public static void writeConfig(ClientConfig config, File file) throws IOException {
byte[] bytes = toBytes(config); byte[] bytes = toBytes(config);
writeBytes(bytes, file); writeBytes(bytes, file);
@@ -72,7 +76,7 @@ public class BinarySerializer {
writeStringIntArrayMap(out, config.hudPositions); writeStringIntArrayMap(out, config.hudPositions);
writeStringBooleanMap(out, config.hudVisibilities); writeStringBooleanMap(out, config.hudVisibilities);
writeStringStringMap(out, config.hudImagePaths); writeStringStringMap(out, config.hudImagePaths);
writeStringStringMap(out, config.friends); writeFriendsMap(out, config.friends);
writeMacros(out, config.macros); writeMacros(out, config.macros);
writeString(out, config.currentProfile); writeString(out, config.currentProfile);
@@ -123,9 +127,16 @@ public class BinarySerializer {
Map<String, int[]> hudPositions = readStringIntArrayMap(in); Map<String, int[]> hudPositions = readStringIntArrayMap(in);
Map<String, Boolean> hudVisibilities = readStringBooleanMap(in); Map<String, Boolean> hudVisibilities = readStringBooleanMap(in);
Map<String, String> hudImagePaths = readStringStringMap(in); Map<String, String> hudImagePaths = readStringStringMap(in);
Map<String, String> friends = readStringStringMap(in); Map<String, ClientConfig.FriendData> friends = version >= 4
? readFriendsMap(in)
: migrateFriendsMap(readStringStringMap(in));
// v3 y v4: macros sin tipo (todas eran de chat). v5+: con tipo
List<ClientConfig.MacroData> macros;
if (version >= 5) macros = readMacros(in);
else if (version >= 3) macros = readLegacyMacros(in);
else macros = new ArrayList<>();
List<ClientConfig.MacroData> macros = version >= 3 ? readMacros(in) : new ArrayList<>();
String currentProfile = version >= 3 ? readString(in) : ""; String currentProfile = version >= 3 ? readString(in) : "";
// leer pos. de la barra de búsqueda // leer pos. de la barra de búsqueda
@@ -145,11 +156,22 @@ public class BinarySerializer {
config.macros = macros; config.macros = macros;
config.currentProfile = currentProfile == null ? "" : currentProfile; config.currentProfile = currentProfile == null ? "" : currentProfile;
if (searchBarPosition != null) config.searchBarPosition = searchBarPosition; if (searchBarPosition != null) config.searchBarPosition = searchBarPosition;
config.legacyKeyCodes = version < 6;
return config; return config;
} }
} }
public static void migrateLegacyKeyCodes(ClientConfig config) {
config.macros = config.macros.stream().map(macro -> {
int key = KeyUtil.fromLegacyGlfwKey(macro.key());
List<ClientConfig.KeyData> keys = macro.keys() == null ? List.of() : macro.keys().stream()
.map(entry -> new ClientConfig.KeyData(KeyUtil.fromLegacyGlfwKey(entry.key()), entry.action()))
.toList();
return new ClientConfig.MacroData(macro.type(), macro.name(), key, macro.lines(), keys);
}).toList();
}
private static void writeStringBooleanMap(DataOutputStream out, Map<String, Boolean> map) private static void writeStringBooleanMap(DataOutputStream out, Map<String, Boolean> map)
throws IOException { throws IOException {
if (map == null) { if (map == null) {
@@ -369,7 +391,7 @@ public class BinarySerializer {
} }
private static void writeStringStringMap(DataOutputStream out, Map<String, String> map) private static void writeStringStringMap(DataOutputStream out, Map<String, String> map)
throws IOException { throws IOException {
if (map == null) { if (map == null) {
out.writeInt(0); out.writeInt(0);
return; return;
@@ -382,7 +404,7 @@ public class BinarySerializer {
} }
private static Map<String, String> readStringStringMap(DataInputStream in) private static Map<String, String> readStringStringMap(DataInputStream in)
throws IOException { throws IOException {
int size = in.readInt(); int size = in.readInt();
Map<String, String> map = new HashMap<>(size); Map<String, String> map = new HashMap<>(size);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
@@ -393,6 +415,9 @@ public class BinarySerializer {
return map; return map;
} }
// v5+: por macro va un id de tipo, luego nombre y tecla, y por último lo propio del tipo
// (líneas en las de chat, pares tecla/acción en las Keybind). los null (que pueden venir
// de un json antiguo) se tratan como chat / lista vacía
private static void writeMacros(DataOutputStream out, List<ClientConfig.MacroData> macros) private static void writeMacros(DataOutputStream out, List<ClientConfig.MacroData> macros)
throws IOException { throws IOException {
if (macros == null) { if (macros == null) {
@@ -401,14 +426,59 @@ public class BinarySerializer {
} }
out.writeInt(macros.size()); out.writeInt(macros.size());
for (ClientConfig.MacroData macro : macros) { for (ClientConfig.MacroData macro : macros) {
boolean keybind = macro.type() == ClientConfig.MacroType.KEYBIND;
out.writeByte(keybind ? MACRO_KEYBIND : MACRO_CHAT);
writeString(out, macro.name()); writeString(out, macro.name());
out.writeInt(macro.key()); out.writeInt(macro.key());
out.writeInt(macro.lines().size());
for (String line : macro.lines()) writeString(out, line); if (keybind) {
List<ClientConfig.KeyData> keys = macro.keys() == null ? List.of() : macro.keys();
out.writeInt(keys.size());
for (ClientConfig.KeyData k : keys) {
out.writeInt(k.key());
out.writeInt(k.action());
}
} else {
List<String> lines = macro.lines() == null ? List.of() : macro.lines();
out.writeInt(lines.size());
for (String line : lines) writeString(out, line);
}
} }
} }
private static List<ClientConfig.MacroData> readMacros(DataInputStream in) throws IOException { private static List<ClientConfig.MacroData> readMacros(DataInputStream in) throws IOException {
int size = in.readInt();
List<ClientConfig.MacroData> macros = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
byte type = in.readByte();
String name = readString(in);
int key = in.readInt();
switch (type) {
case MACRO_CHAT -> {
int lineCount = in.readInt();
List<String> lines = new ArrayList<>(lineCount);
for (int j = 0; j < lineCount; j++) lines.add(readString(in));
macros.add(ClientConfig.MacroData.chat(name, key, lines));
}
case MACRO_KEYBIND -> {
int keyCount = in.readInt();
List<ClientConfig.KeyData> keys = new ArrayList<>(keyCount);
for (int j = 0; j < keyCount; j++) keys.add(new ClientConfig.KeyData(in.readInt(), in.readInt()));
macros.add(ClientConfig.MacroData.keybind(name, key, keys));
}
// no hay forma de saltarse una macro de un tipo que no conocemos (no se sabe
// cuánto ocupa), así que lo único seguro es fallar
default -> throw new IOException(I18nUtil.fmt("sputnik.config.error.invalidmacro",
"tipo de macro desconocido: %s", type));
}
}
return macros;
}
// v3 y v4: formato de antes de que hubiera tipos (nombre, tecla, líneas). eran todas de chat
private static List<ClientConfig.MacroData> readLegacyMacros(DataInputStream in) throws IOException {
int size = in.readInt(); int size = in.readInt();
List<ClientConfig.MacroData> macros = new ArrayList<>(size); List<ClientConfig.MacroData> macros = new ArrayList<>(size);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
@@ -417,11 +487,50 @@ public class BinarySerializer {
int lineCount = in.readInt(); int lineCount = in.readInt();
List<String> lines = new ArrayList<>(lineCount); List<String> lines = new ArrayList<>(lineCount);
for (int j = 0; j < lineCount; j++) lines.add(readString(in)); for (int j = 0; j < lineCount; j++) lines.add(readString(in));
macros.add(new ClientConfig.MacroData(name, key, lines)); macros.add(ClientConfig.MacroData.chat(name, key, lines));
} }
return macros; return macros;
} }
private static void writeFriendsMap(DataOutputStream out, Map<String, ClientConfig.FriendData> map)
throws IOException {
if (map == null) {
out.writeInt(0);
return;
}
out.writeInt(map.size());
for (Map.Entry<String, ClientConfig.FriendData> entry : map.entrySet()) {
writeString(out, entry.getKey());
ClientConfig.FriendData data = entry.getValue();
writeString(out, data.name());
writeString(out, data.nick());
out.writeLong(data.befriendedAt());
}
}
private static Map<String, ClientConfig.FriendData> readFriendsMap(DataInputStream in)
throws IOException {
int size = in.readInt();
Map<String, ClientConfig.FriendData> map = new HashMap<>(size);
for (int i = 0; i < size; i++) {
String uuid = readString(in);
String name = readString(in);
String nick = readString(in);
long befriendedAt = in.readLong();
map.put(uuid, new ClientConfig.FriendData(name, nick, befriendedAt));
}
return map;
}
private static Map<String, ClientConfig.FriendData> migrateFriendsMap(Map<String, String> legacy) {
Map<String, ClientConfig.FriendData> map = new HashMap<>(legacy.size());
long now = System.currentTimeMillis();
for (Map.Entry<String, String> entry : legacy.entrySet()) {
map.put(entry.getKey(), new ClientConfig.FriendData(entry.getValue(), entry.getValue(), now));
}
return map;
}
private static void writeString(DataOutputStream out, String str) throws IOException { private static void writeString(DataOutputStream out, String str) throws IOException {
if (str == null) { if (str == null) {
out.writeInt(-1); out.writeInt(-1);
@@ -4,8 +4,6 @@ import com.github.retucio.neutrino.EventListener;
import me.retucio.sputnik.event.sputnik.*; import me.retucio.sputnik.event.sputnik.*;
import me.retucio.sputnik.module.setting.settings.*; import me.retucio.sputnik.module.setting.settings.*;
import me.retucio.sputnik.ui.screen.ClickGui; import me.retucio.sputnik.ui.screen.ClickGui;
import me.retucio.sputnik.ui.widgets.panels.FriendsPanel;
import me.retucio.sputnik.util.ChatUtil;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
@@ -44,14 +42,18 @@ public class ClientConfig {
// posición de la barra de búsqueda (x, y) // posición de la barra de búsqueda (x, y)
public int[] searchBarPosition = new int[] { 340, 16 }; public int[] searchBarPosition = new int[] { 340, 16 };
// amigos: uuid -> nombre // amigos: uuid -> FriendData (nombre, apodo, fecha)
public Map<String, String> friends = new HashMap<>(); public Map<String, FriendData> friends = new HashMap<>();
// macros, de cualquier tipo (ver MacroData)
public List<MacroData> macros = new ArrayList<>(); public List<MacroData> macros = new ArrayList<>();
// perfil cargado actualmente, vacío si es la config. suelta // perfil cargado actualmente, vacío si es la config. suelta
public String currentProfile = ""; public String currentProfile = "";
// Set only when loading a config written with GLFW keycodes (pre-26.3).
public transient boolean legacyKeyCodes;
public ClientConfig() { public ClientConfig() {
EVENT_BUS.subscribe(this); EVENT_BUS.subscribe(this);
} }
@@ -146,31 +148,15 @@ public class ClientConfig {
ConfigManager.INSTANCE.markDirty(); ConfigManager.INSTANCE.markDirty();
} }
@EventListener
public void onExtendFriendsPanel(FriendPanelEvent.Extend event) {
extendablePanels.put("amigos", new PanelData(
ClickGui.INSTANCE.getFriendsPanel().getX(),
ClickGui.INSTANCE.getFriendsPanel().getY(),
ClickGui.INSTANCE.getFriendsPanel().isExtended()));
ConfigManager.INSTANCE.markDirty();
}
@EventListener
public void onMoveFriendsPanel(FriendPanelEvent.Move event) {
extendablePanels.put("amigos", new PanelData(
ClickGui.INSTANCE.getFriendsPanel().getX(),
ClickGui.INSTANCE.getFriendsPanel().getY(),
ClickGui.INSTANCE.getFriendsPanel().isExtended()));
ConfigManager.INSTANCE.markDirty();
}
@EventListener @EventListener
public void onAddFriend(FriendEvent.Add event) { public void onAddFriend(FriendEvent.Add event) {
if (isApplying()) return; if (isApplying()) return;
String uuid = event.getFriend().getUuid().toString(); String uuid = event.getFriend().getUuid().toString();
String name = event.getFriend().getName();
if (!friends.containsKey(uuid)) { if (!friends.containsKey(uuid)) {
friends.put(uuid, name); friends.put(uuid, new FriendData(
event.getFriend().getName(),
event.getFriend().getNick(),
event.getFriend().getBefriendedAt()));
} }
ConfigManager.INSTANCE.markDirty(); ConfigManager.INSTANCE.markDirty();
} }
@@ -182,11 +168,42 @@ public class ClientConfig {
ConfigManager.INSTANCE.markDirty(); ConfigManager.INSTANCE.markDirty();
} }
@EventListener
public void onRenameFriend(FriendEvent.Rename event) {
if (isApplying()) return;
String uuid = event.getFriend().getUuid().toString();
FriendData existing = friends.get(uuid);
if (existing == null) return; // no debería pasar, pero porsiaca
friends.put(uuid, new FriendData(existing.name(), event.getFriend().getNick(), existing.befriendedAt()));
ConfigManager.INSTANCE.markDirty();
}
public record PanelData(int x, int y, boolean extended) implements Serializable { public record PanelData(int x, int y, boolean extended) implements Serializable {
@Serial private static final long serialVersionUID = 1L; @Serial private static final long serialVersionUID = 1L;
} }
public record MacroData(String name, int key, List<String> lines) implements Serializable { public record FriendData(String name, String nick, long befriendedAt) implements Serializable {
@Serial private static final long serialVersionUID = 1L; @Serial private static final long serialVersionUID = 1L;
} }
public enum MacroType { CHAT, KEYBIND }
public record KeyData(int key, int action) implements Serializable {
@Serial private static final long serialVersionUID = 1L;
}
public record MacroData(MacroType type, String name, int key,
List<String> lines, List<KeyData> keys
) implements Serializable {
@Serial private static final long serialVersionUID = 2L;
public static MacroData chat(String name, int key, List<String> lines) {
return new MacroData(MacroType.CHAT, name, key, List.copyOf(lines), List.of());
}
public static MacroData keybind(String name, int key, List<KeyData> keys) {
return new MacroData(MacroType.KEYBIND, name, key, List.of(), List.copyOf(keys));
}
}
} }
@@ -16,13 +16,12 @@ import me.retucio.sputnik.ui.hud.HudElement;
import me.retucio.sputnik.ui.hud.HudRenderer; import me.retucio.sputnik.ui.hud.HudRenderer;
import me.retucio.sputnik.ui.widgets.Panel; import me.retucio.sputnik.ui.widgets.Panel;
import me.retucio.sputnik.ui.widgets.panels.ExtendablePanel; import me.retucio.sputnik.ui.widgets.panels.ExtendablePanel;
import me.retucio.sputnik.ui.widgets.panels.FriendsPanel;
import me.retucio.sputnik.ui.widgets.panels.ModulePanel; import me.retucio.sputnik.ui.widgets.panels.ModulePanel;
import me.retucio.sputnik.ui.screen.ClickGui; import me.retucio.sputnik.ui.screen.ClickGui;
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.util.ChatUtil;
import me.retucio.sputnik.util.I18nUtil; import me.retucio.sputnik.util.I18nUtil;
import me.retucio.sputnik.util.KeyUtil;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import java.io.File; import java.io.File;
@@ -153,6 +152,7 @@ public class ConfigManager {
try (FileReader reader = new FileReader(LEGACY_JSON_FILE)) { try (FileReader reader = new FileReader(LEGACY_JSON_FILE)) {
Gson gson = new GsonBuilder().setPrettyPrinting().create(); Gson gson = new GsonBuilder().setPrettyPrinting().create();
setConfig(gson.fromJson(reader, ClientConfig.class)); setConfig(gson.fromJson(reader, ClientConfig.class));
config.legacyKeyCodes = true;
Sputnik.LOGGER.info(I18nUtil.fmt("sputnik.config.info.json", Sputnik.LOGGER.info(I18nUtil.fmt("sputnik.config.info.json",
"ajustes json cargados (migración)")); "ajustes json cargados (migración)"));
@@ -177,7 +177,9 @@ public class ConfigManager {
if (!shouldApply()) return false; if (!shouldApply()) return false;
applying = true; applying = true;
boolean migratedKeys = config.legacyKeyCodes;
try { try {
migrateLegacyKeyCodes();
// los del mod primero: entre ellos está "teclas multimódulo", que decide si al // los del mod primero: entre ellos está "teclas multimódulo", que decide si al
// asignar una tecla se le quita a los demás módulos. aplicándolos los últimos, // asignar una tecla se le quita a los demás módulos. aplicándolos los últimos,
// las teclas de los módulos se cargaban con el valor por defecto de ese ajuste // las teclas de los módulos se cargaban con el valor por defecto de ese ajuste
@@ -202,9 +204,32 @@ public class ConfigManager {
loaded = true; loaded = true;
} }
if (migratedKeys) writeSnapshot(true);
return true; return true;
} }
private void migrateLegacyKeyCodes() {
if (!config.legacyKeyCodes) return;
ClientSettingsPanel.clientSettings.getSettings().forEach(this::migrateLegacyKeySetting);
ModuleManager.INSTANCE.getModules().forEach(module ->
module.getSettings().forEach(this::migrateLegacyKeySetting));
BinarySerializer.migrateLegacyKeyCodes(config);
config.legacyKeyCodes = false;
}
private void migrateLegacyKeySetting(Setting<?> setting) {
if (!(setting instanceof KeySetting)) return;
String key = getSettingKey(setting);
Object value = config.settings.get(key);
if (value instanceof Integer code) {
config.settings.put(key, KeyUtil.fromLegacyGlfwKey(code));
} else if (value instanceof Double code) {
config.settings.put(key, KeyUtil.fromLegacyGlfwKey(code.intValue()));
}
}
// true mientras se está cargando la config. sobre los ajustes. lo mira KeySetting para no // true mientras se está cargando la config. sobre los ajustes. lo mira KeySetting para no
// tratar las teclas guardadas como si el usuario las acabara de asignar, y ClientConfig // tratar las teclas guardadas como si el usuario las acabara de asignar, y ClientConfig
// para no reescribir en la config. lo que se le está aplicando // para no reescribir en la config. lo que se le está aplicando
@@ -301,7 +326,7 @@ public class ConfigManager {
public void setMacros(List<Macro> macros) { public void setMacros(List<Macro> macros) {
ensureConfig(); ensureConfig();
config.macros = macros.stream() config.macros = macros.stream()
.map(macro -> new ClientConfig.MacroData(macro.getName(), macro.getKey(), List.copyOf(macro.getLines()))) .map(ConfigManager::toMacroData)
.toList(); .toList();
markDirty(); markDirty();
} }
@@ -316,9 +341,10 @@ public class ConfigManager {
// ------------------ APLICAR AJUSTES ------------------ // ------------------ APLICAR AJUSTES ------------------
public void applyFriends() { public void applyFriends() {
config.friends.forEach((uuid, name) -> { config.friends.forEach((uuid, data) -> {
Friend friend = new Friend(UUID.fromString(uuid)); Friend friend = new Friend(UUID.fromString(uuid), data.befriendedAt());
friend.setName(name); friend.setName(data.name());
friend.setNick(data.nick());
FriendManager.INSTANCE.add(friend); FriendManager.INSTANCE.add(friend);
}); });
Sputnik.LOGGER.info(I18nUtil.fmt("sputnik.config.info.friends", Sputnik.LOGGER.info(I18nUtil.fmt("sputnik.config.info.friends",
@@ -327,10 +353,37 @@ public class ConfigManager {
public void applyMacros() { public void applyMacros() {
MacroManager.INSTANCE.setMacros(config.macros.stream() MacroManager.INSTANCE.setMacros(config.macros.stream()
.map(data -> new Macro(data.name(), data.key(), data.lines())) .map(ConfigManager::fromMacroData)
.toList()); .toList());
} }
private static ClientConfig.MacroData toMacroData(Macro macro) {
return switch (macro) {
case Macro.Chat chat -> ClientConfig.MacroData.chat(
chat.getName(), chat.getKey(), chat.getLines());
case Macro.Keybind keybind -> ClientConfig.MacroData.keybind(
keybind.getName(), keybind.getKey(),
keybind.getKeys().stream()
.map(k -> new ClientConfig.KeyData(k.key(), k.action()))
.toList());
default -> throw new IllegalArgumentException(
"tipo de macro sin serializar: " + macro.getClass().getName());
};
}
private static Macro fromMacroData(ClientConfig.MacroData data) {
if (data.type() == ClientConfig.MacroType.KEYBIND) {
List<Macro.Keybind.Key> keys = data.keys() == null ? List.of() : data.keys().stream()
.map(k -> new Macro.Keybind.Key(k.key(), k.action()))
.toList();
return new Macro.Keybind(data.name(), data.key(), keys);
}
return new Macro.Chat(data.name(), data.key(), data.lines() == null ? List.of() : data.lines());
}
// el HudRenderer coloca sus elementos al construirse, pero al cambiar de perfil ya existen // el HudRenderer coloca sus elementos al construirse, pero al cambiar de perfil ya existen
public void applyHudElements() { public void applyHudElements() {
if (HudRenderer.INSTANCE == null) return; if (HudRenderer.INSTANCE == null) return;
@@ -424,7 +477,6 @@ public class ConfigManager {
applyExtendablePanel(panel); applyExtendablePanel(panel);
} }
applyExtendablePanel(ClickGui.INSTANCE.getClientSettingsPanel()); applyExtendablePanel(ClickGui.INSTANCE.getClientSettingsPanel());
applyExtendablePanel(ClickGui.INSTANCE.getFriendsPanel());
Sputnik.LOGGER.info(I18nUtil.fmt("sputnik.config.info.extendablepanels", Sputnik.LOGGER.info(I18nUtil.fmt("sputnik.config.info.extendablepanels",
"posiciones de marcos extendibles aplicadas")); "posiciones de marcos extendibles aplicadas"));
@@ -440,9 +492,6 @@ public class ConfigManager {
if (panel instanceof ClientSettingsPanel) { if (panel instanceof ClientSettingsPanel) {
panelData = config.extendablePanels.get("ajustes"); panelData = config.extendablePanels.get("ajustes");
} }
if (panel instanceof FriendsPanel) {
panelData = config.extendablePanels.get("amigos");
}
if (panelData != null) { if (panelData != null) {
panel.setX(panelData.x()); panel.setX(panelData.x());
@@ -598,8 +647,6 @@ public class ConfigManager {
ClientSettingsModule settings = ClientSettingsPanel.clientSettings; ClientSettingsModule settings = ClientSettingsPanel.clientSettings;
if (!settings.autosave.getValue()) return; if (!settings.autosave.getValue()) return;
// desde el último guardado, no desde el último cambio: contando desde el cambio,
// tocando ajustes cada menos del intervalo no se autoguardaba nunca
long intervalMs = (long) (settings.autosaveInterval.getValue() * 1000); long intervalMs = (long) (settings.autosaveInterval.getValue() * 1000);
if (System.currentTimeMillis() - lastSaveTime < intervalMs) return; if (System.currentTimeMillis() - lastSaveTime < intervalMs) return;
@@ -608,4 +655,4 @@ public class ConfigManager {
Component.translatable("sputnik.config.autosaving.desc").getString()); Component.translatable("sputnik.config.autosaving.desc").getString());
save(); save();
} }
} }
@@ -3,7 +3,8 @@ package me.retucio.sputnik.event.sputnik;
import com.github.retucio.neutrino.Event; import com.github.retucio.neutrino.Event;
import me.retucio.sputnik.friend.Friend; import me.retucio.sputnik.friend.Friend;
// evento lanzado cuando se agrega o se elimina un amigo
// evento lanzado cuando se agrega, elimina o renombra un amigo
public class FriendEvent extends Event { public class FriendEvent extends Event {
private final Friend friend; private final Friend friend;
@@ -23,4 +24,8 @@ public class FriendEvent extends Event {
public static class Remove extends FriendEvent { public static class Remove extends FriendEvent {
public Remove(Friend friend) { super(friend); } public Remove(Friend friend) { super(friend); }
} }
}
public static class Rename extends FriendEvent {
public Rename(Friend friend) { super(friend); }
}
}
@@ -1,9 +0,0 @@
package me.retucio.sputnik.event.sputnik;
import com.github.retucio.neutrino.Event;
public class FriendPanelEvent {
public static class Extend extends Event {} // al extenderlo / contraerlo
public static class Move extends Event {} // al cambiarlo de posición
}
@@ -1,6 +1,7 @@
package me.retucio.sputnik.friend; package me.retucio.sputnik.friend;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.PlayerInfo;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -13,12 +14,20 @@ public class Friend {
private static final Minecraft mc = Minecraft.getInstance(); private static final Minecraft mc = Minecraft.getInstance();
private String name; private String name;
private String nick;
private final UUID uuid; private final UUID uuid;
private final long befriendedAt;
private boolean searchMatch; private boolean searchMatch;
public Friend(UUID uuid) { public Friend(UUID uuid) {
this.uuid = uuid; this.uuid = uuid;
this.befriendedAt = System.currentTimeMillis();
}
public Friend(UUID uuid, long befriendedAt) {
this.uuid = uuid;
this.befriendedAt = befriendedAt;
} }
public String getName() { public String getName() {
@@ -29,10 +38,27 @@ public class Friend {
this.name = name; this.name = name;
} }
public String getNick() {
return nick;
}
public void setNick(String nick) {
this.nick = nick;
}
// apodo si existe, si no el nombre real
public String getDisplayName() {
return (nick == null || nick.isBlank()) ? name : nick;
}
public UUID getUuid() { public UUID getUuid() {
return uuid; return uuid;
} }
public long getBefriendedAt() {
return befriendedAt;
}
public @Nullable Player getPlayer() { public @Nullable Player getPlayer() {
if (mc.level == null) return null; if (mc.level == null) return null;
Entity entity = mc.level.getEntity(uuid); Entity entity = mc.level.getEntity(uuid);
@@ -40,6 +66,11 @@ public class Friend {
return player; return player;
} }
public @Nullable PlayerInfo getPlayerInfo() {
if (mc.getConnection() == null) return null;
return mc.getConnection().getPlayerInfo(uuid);
}
public boolean isSearchMatch() { public boolean isSearchMatch() {
return searchMatch; return searchMatch;
} }
@@ -56,4 +87,4 @@ public class Friend {
NOT_BEFRIENDED, NOT_BEFRIENDED,
NO_FRIENDS; // :( NO_FRIENDS; // :(
} }
} }
@@ -29,6 +29,7 @@ public class FriendManager {
public void add(UUID uuid) { public void add(UUID uuid) {
Friend friend = new Friend(uuid); Friend friend = new Friend(uuid);
friend.setName(friend.getPlayer().getName().getString()); friend.setName(friend.getPlayer().getName().getString());
friend.setNick(friend.getName());
add(friend); add(friend);
} }
@@ -61,6 +62,11 @@ public class FriendManager {
return Friend.Status.SUCCESS; return Friend.Status.SUCCESS;
} }
public void rename(Friend friend, String nick) {
friend.setNick(nick);
Sputnik.EVENT_BUS.post(new FriendEvent.Rename(friend));
}
public Friend get(UUID uuid) { public Friend get(UUID uuid) {
for (Friend friend : friends) { for (Friend friend : friends) {
if (friend.getUuid().equals(uuid)) { if (friend.getUuid().equals(uuid)) {
@@ -1,38 +1,22 @@
package me.retucio.sputnik.macro; package me.retucio.sputnik.macro;
import me.retucio.sputnik.util.ChatUtil; import me.retucio.sputnik.util.ChatUtil;
import me.retucio.sputnik.util.KeyUtil;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Macro { public abstract class Macro {
private String name; protected String name;
private int key; protected int key;
private final List<String> lines = new ArrayList<>();
private boolean searchMatch = true; protected Macro(String name, int key) {
public Macro(String name) {
this(name, GLFW.GLFW_KEY_UNKNOWN, List.of());
}
public Macro(String name, int key, List<String> lines) {
this.name = name; this.name = name;
this.key = key; this.key = key;
this.lines.addAll(lines);
}
// cada línea se manda como si el usuario la hubiera escrito en el chat, así que valen
// comandos del mod, comandos del servidor y mensajes normales
public void run() {
if (Minecraft.getInstance().player == null) return;
for (String line : lines) {
if (!line.isBlank()) ChatUtil.simulateChatMessage(line);
}
} }
public String getName() { return name; } public String getName() { return name; }
@@ -41,13 +25,80 @@ public class Macro {
public int getKey() { return key; } public int getKey() { return key; }
public void setKey(int key) { this.key = key; } public void setKey(int key) { this.key = key; }
public List<String> getLines() { return lines; } private boolean searchMatch = true;
public void setLines(List<String> lines) {
this.lines.clear();
this.lines.addAll(lines);
}
public boolean isSearchMatch() { return searchMatch; } public boolean isSearchMatch() { return searchMatch; }
public void setSearchMatch(boolean searchMatch) { this.searchMatch = searchMatch; } public void setSearchMatch(boolean searchMatch) { this.searchMatch = searchMatch; }
}
public abstract void run();
// cada línea se manda como si el usuario la hubiera escrito en el chat, así que valen
// comandos del mod, comandos del servidor y mensajes normales
public static class Chat extends Macro {
private final List<String> lines = new ArrayList<>();
public Chat(String name) {
this(name, InputConstants.UNKNOWN.getValue(), List.of());
}
public Chat(String name, int key, List<String> lines) {
super(name, key);
this.lines.addAll(lines);
}
@Override
public void run() {
if (Minecraft.getInstance().player == null) return;
for (String line : lines) {
if (!line.isBlank()) ChatUtil.simulateChatMessage(line);
}
}
public List<String> getLines() {
return lines;
}
public void setLines(List<String> lines) {
this.lines.clear();
this.lines.addAll(lines);
}
}
public static class Keybind extends Macro {
private final List<Key> keys = new ArrayList<>();
public Keybind(String name) {
this(name, InputConstants.UNKNOWN.getValue(), List.of());
}
public Keybind(String name, int key, List<Key> keys) {
super(name, key);
this.keys.addAll(keys);
}
@Override
public void run() {
for (Key k : keys) {
k.use();
}
}
public List<Key> getKeys() {
return keys;
}
public void setKeys(List<Key> keys) {
this.keys.clear();
this.keys.addAll(keys);
}
public record Key(int key, int action) {
public void use() {
KeyUtil.pressKey(key, action);
}
}
}
}
@@ -2,7 +2,7 @@ package me.retucio.sputnik.macro;
import me.retucio.sputnik.config.ConfigManager; import me.retucio.sputnik.config.ConfigManager;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -14,6 +14,9 @@ public class MacroManager {
private final List<Macro> macros = new ArrayList<>(); private final List<Macro> macros = new ArrayList<>();
// para evitar disparar un macro que presiona su propia tecla infinitamente
private boolean running = false;
public boolean add(Macro macro) { public boolean add(Macro macro) {
if (getByName(macro.getName()) != null) return false; if (getByName(macro.getName()) != null) return false;
macros.add(macro); macros.add(macro);
@@ -34,15 +37,20 @@ public class MacroManager {
} }
public boolean onKeyPress(int key) { public boolean onKeyPress(int key) {
if (key == GLFW.GLFW_KEY_UNKNOWN || Minecraft.getInstance().gui.screen() != null) return false; if (running || key == InputConstants.UNKNOWN.getValue() || Minecraft.getInstance().gui.screen() != null) return false;
boolean ran = false; running = true;
for (Macro macro : new ArrayList<>(macros)) { try {
if (macro.getKey() != key) continue; boolean ran = false;
macro.run(); for (Macro macro : new ArrayList<>(macros)) {
ran = true; if (macro.getKey() != key) continue;
macro.run();
ran = true;
}
return ran;
} finally {
running = false;
} }
return ran;
} }
public void setMacros(List<Macro> macros) { public void setMacros(List<Macro> macros) {
@@ -1,6 +1,7 @@
package me.retucio.sputnik.mixin.accessors; package me.retucio.sputnik.mixin.accessors;
import net.minecraft.client.renderer.item.ItemStackRenderState; import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.resources.model.geometry.ItemQuads;
import net.minecraft.client.resources.model.cuboid.ItemTransform; import net.minecraft.client.resources.model.cuboid.ItemTransform;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Accessor;
@@ -11,4 +12,7 @@ public interface LayerRenderStateAccessor {
@Accessor("itemTransform") @Accessor("itemTransform")
ItemTransform sputnik$getTransform(); ItemTransform sputnik$getTransform();
}
@Accessor("quads")
ItemQuads sputnik$getQuads();
}
@@ -1,7 +1,7 @@
package me.retucio.sputnik.mixin.mixins.hud; package me.retucio.sputnik.mixin.mixins.hud;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.renderpearl.api.pipeline.RenderPipeline;
import me.retucio.sputnik.Sputnik; import me.retucio.sputnik.Sputnik;
import me.retucio.sputnik.event.render.Render2DEvent; import me.retucio.sputnik.event.render.Render2DEvent;
import me.retucio.sputnik.module.ModuleManager; import me.retucio.sputnik.module.ModuleManager;
@@ -79,7 +79,7 @@ public abstract class HudMixin {
HudRenderer.INSTANCE.render(gui, dt); HudRenderer.INSTANCE.render(gui, dt);
} }
@Redirect(method = "extractCrosshair", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphicsExtractor;blitSprite(Lcom/mojang/blaze3d/pipeline/RenderPipeline;Lnet/minecraft/resources/Identifier;IIII)V", ordinal = 0)) @Redirect(method = "extractCrosshair", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphicsExtractor;blitSprite(Lcom/mojang/renderpearl/api/pipeline/RenderPipeline;Lnet/minecraft/resources/Identifier;IIII)V", ordinal = 0))
private void onRenderCrosshair(GuiGraphicsExtractor gui, RenderPipeline pipeline, Identifier id, int x, int y, int width, int height) { private void onRenderCrosshair(GuiGraphicsExtractor gui, RenderPipeline pipeline, Identifier id, int x, int y, int width, int height) {
// dangerous abbreviation // dangerous abbreviation
CrosshairPlus cp = ModuleManager.INSTANCE.getModuleByClass(CrosshairPlus.class); CrosshairPlus cp = ModuleManager.INSTANCE.getModuleByClass(CrosshairPlus.class);
@@ -2,6 +2,7 @@ package me.retucio.sputnik.mixin.mixins.io;
import me.retucio.sputnik.Sputnik; import me.retucio.sputnik.Sputnik;
import me.retucio.sputnik.event.input.KeyEvent; import me.retucio.sputnik.event.input.KeyEvent;
import com.mojang.blaze3d.platform.InputConstants;
import net.minecraft.client.KeyboardHandler; import net.minecraft.client.KeyboardHandler;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
@@ -14,9 +15,9 @@ public abstract class KeyboardHandlerMixin {
@Inject(method = "keyPress", at = @At("HEAD"), cancellable = true) @Inject(method = "keyPress", at = @At("HEAD"), cancellable = true)
private void onKeyPress(long handle, int action, net.minecraft.client.input.KeyEvent input, CallbackInfo ci) { private void onKeyPress(long handle, int action, net.minecraft.client.input.KeyEvent input, CallbackInfo ci) {
if (input.key() == -1) return; if (input.key() == InputConstants.UNKNOWN.getValue() || input.key() == -1) return;
Sputnik.INSTANCE.onInput(input.key(), action); Sputnik.INSTANCE.onInput(input.key(), action);
KeyEvent event = Sputnik.EVENT_BUS.post(new KeyEvent(input.key(), input.scancode(), action)); KeyEvent event = Sputnik.EVENT_BUS.post(new KeyEvent(input.key(), input.keycode(), action));
if (event.isCancelled()) ci.cancel(); if (event.isCancelled()) ci.cancel();
} }
} }
@@ -16,7 +16,10 @@ public abstract class MouseHandlerMixin {
@Inject(method = "onButton", at = @At("HEAD"), cancellable = true) @Inject(method = "onButton", at = @At("HEAD"), cancellable = true)
private void onMouseButton(long handle, MouseButtonInfo input, int action, CallbackInfo ci) { private void onMouseButton(long handle, MouseButtonInfo input, int action, CallbackInfo ci) {
Sputnik.INSTANCE.onInput(input.button(), action); if (Sputnik.INSTANCE.onMouseInput(input.button(), action)) {
ci.cancel();
return;
}
MouseClickEvent event = Sputnik.EVENT_BUS.post(new MouseClickEvent(action, input.button())); MouseClickEvent event = Sputnik.EVENT_BUS.post(new MouseClickEvent(action, input.button()));
if (event.isCancelled()) ci.cancel(); if (event.isCancelled()) ci.cancel();
} }
@@ -3,18 +3,13 @@ package me.retucio.sputnik.mixin.mixins.network;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
import me.retucio.sputnik.command.CommandManager; import me.retucio.sputnik.command.CommandManager;
import me.retucio.sputnik.event.network.SendMessageEvent; import me.retucio.sputnik.event.network.SendMessageEvent;
import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.render.NoRender;
import me.retucio.sputnik.util.ChatUtil; import me.retucio.sputnik.util.ChatUtil;
import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import static me.retucio.sputnik.Sputnik.*; import static me.retucio.sputnik.Sputnik.*;
@@ -51,11 +46,4 @@ public abstract class ClientPacketListenerMixin {
mc.gui.hud.getChat().addRecentChat(content); mc.gui.hud.getChat().addRecentChat(content);
ci.cancel(); ci.cancel();
} }
@Redirect(method = "handleEntityEvent", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;displayItemActivation(Lnet/minecraft/world/item/ItemStack;)V"))
private void noRenderTotemPop(GameRenderer instance, ItemStack itemStack) {
NoRender noRender = ModuleManager.INSTANCE.getModuleByClass(NoRender.class);
if (!noRender.isEnabled() || noRender.totemPop.getValue())
mc.gameRenderer.displayItemActivation(itemStack);
}
} }
@@ -1,17 +1,17 @@
package me.retucio.sputnik.mixin.mixins.network; package me.retucio.sputnik.mixin.mixins.network;
import com.mojang.authlib.yggdrasil.YggdrasilUserApiService; import com.mojang.authlib.services.MinecraftServicesUserApiService;
import com.mojang.authlib.yggdrasil.response.UserAttributesResponse; import com.mojang.authlib.services.response.UserAttributesResponse;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
// código robado de: https://github.com/kb-1000/no-telemetry // código robado de: https://github.com/kb-1000/no-telemetry
@Mixin(YggdrasilUserApiService.class) @Mixin(MinecraftServicesUserApiService.class)
public abstract class YggdrasilUserApiServiceMixin { public abstract class YggdrasilUserApiServiceMixin {
@Redirect(method = "fetchProperties", at = @At(value = "INVOKE", target = "Lcom/mojang/authlib/yggdrasil/response/UserAttributesResponse$Privileges;getTelemetry()Z", remap = false), remap = false, require = 0) @Redirect(method = "fetchProperties", at = @At(value = "INVOKE", target = "Lcom/mojang/authlib/services/response/UserAttributesResponse$Privileges;getTelemetry()Z", remap = false), remap = false, require = 0)
private boolean getTelemetry(UserAttributesResponse.Privileges instance) { private boolean getTelemetry(UserAttributesResponse.Privileges instance) {
return false; return false;
} }
@@ -4,6 +4,7 @@ import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.render.GlintPlus; import me.retucio.sputnik.module.modules.render.GlintPlus;
import net.minecraft.client.renderer.entity.layers.EquipmentLayerRenderer; import net.minecraft.client.renderer.entity.layers.EquipmentLayerRenderer;
import net.minecraft.client.renderer.rendertype.RenderType; import net.minecraft.client.renderer.rendertype.RenderType;
import net.minecraft.resources.Identifier;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.ModifyVariable;
@@ -12,9 +13,9 @@ import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(EquipmentLayerRenderer.class) @Mixin(EquipmentLayerRenderer.class)
public abstract class EquipmentLayerRendererMixin { public abstract class EquipmentLayerRendererMixin {
@Redirect(method = "renderLayers(Lnet/minecraft/client/resources/model/EquipmentClientInfo$LayerType;Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/client/model/Model;Ljava/lang/Object;Lnet/minecraft/world/item/ItemStack;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;ILnet/minecraft/resources/Identifier;II)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/rendertype/RenderTypes;armorEntityGlint()Lnet/minecraft/client/renderer/rendertype/RenderType;")) @Redirect(method = "renderLayers(Lnet/minecraft/client/resources/model/EquipmentClientInfo$LayerType;Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/client/model/Model;Ljava/lang/Object;Lnet/minecraft/world/item/ItemStack;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;ILnet/minecraft/resources/Identifier;II)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/rendertype/RenderTypes;armorCutoutNoCullGlint(Lnet/minecraft/resources/Identifier;)Lnet/minecraft/client/renderer/rendertype/RenderType;"))
private RenderType redirectArmorEntityGlint() { private RenderType redirectArmorEntityGlint(Identifier texture) {
GlintPlus glintPlus = ModuleManager.INSTANCE.getModuleByClass(GlintPlus.class); GlintPlus glintPlus = ModuleManager.INSTANCE.getModuleByClass(GlintPlus.class);
return glintPlus.getArmorEntityGlint(); return glintPlus.getArmorEntityGlint(texture);
} }
} }
@@ -15,8 +15,11 @@ import com.mojang.blaze3d.resource.CrossFrameResourcePool;
import net.minecraft.client.DeltaTracker; import net.minecraft.client.DeltaTracker;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.ItemInHandRenderer; import net.minecraft.client.renderer.FirstPersonHandsAndItemsRenderer;
import net.minecraft.client.renderer.state.level.CameraRenderState; import net.minecraft.client.renderer.state.level.CameraRenderState;
import net.minecraft.client.renderer.state.level.PlayerRenderState;
import net.minecraft.client.renderer.item.ItemModelResolver;
import com.mojang.renderpearl.api.textures.GpuTextureView;
import net.minecraft.client.resources.model.ModelManager; import net.minecraft.client.resources.model.ModelManager;
import org.joml.Matrix4fc; import org.joml.Matrix4fc;
@@ -52,23 +55,20 @@ public abstract class GameRendererMixin {
private CrossFrameResourcePool resourcePool; private CrossFrameResourcePool resourcePool;
@Inject(method = "<init>", at = @At("TAIL")) @Inject(method = "<init>", at = @At("TAIL"))
private void getModules(Minecraft minecraft, ItemInHandRenderer itemInHandRenderer, ModelManager modelManager, CallbackInfo ci) { private void getModules(Minecraft minecraft, FirstPersonHandsAndItemsRenderer itemInHandRenderer, ModelManager modelManager, ItemModelResolver itemModelResolver, CallbackInfo ci) {
zoom = ModuleManager.INSTANCE.getModuleByClass(Zoom.class);; zoom = ModuleManager.INSTANCE.getModuleByClass(Zoom.class);;
freecam = ModuleManager.INSTANCE.getModuleByClass(Freecam.class); freecam = ModuleManager.INSTANCE.getModuleByClass(Freecam.class);
noRender = ModuleManager.INSTANCE.getModuleByClass(NoRender.class); noRender = ModuleManager.INSTANCE.getModuleByClass(NoRender.class);
lsd = ModuleManager.INSTANCE.getModuleByClass(Lsd.class); lsd = ModuleManager.INSTANCE.getModuleByClass(Lsd.class);
} }
// se aplica justo donde vanilla mete sus efectos de post (nausea, etc.): el mundo ya está @Inject(method = "render", at = @At(value = "INVOKE", shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/LevelRenderer;blitEntityOutline()V"))
// en mainRenderTarget y el HUD todavía no, así que sólo distorsiona la escena 3D private void applyLsd(CallbackInfo ci) {
@Inject(method = "render", at = @At(value = "INVOKE", shift = At.Shift.AFTER,
target = "Lnet/minecraft/client/renderer/LevelRenderer;doEntityOutline()V"))
private void applyLsd(DeltaTracker deltaTracker, boolean advanceGameTime, CallbackInfo ci) {
if (lsd.isEnabled()) lsd.apply(mainRenderTarget, resourcePool); if (lsd.isEnabled()) lsd.apply(mainRenderTarget, resourcePool);
} }
@Inject(method = "render", at = @At("HEAD"), cancellable = true) @Inject(method = "render", at = @At("HEAD"), cancellable = true)
private void avoidRenderingUnfocusedCpu(DeltaTracker dt, boolean tick, CallbackInfo ci) { private void avoidRenderingUnfocusedCpu(CallbackInfo ci) {
if (ModuleManager.INSTANCE.getModuleByClass(UnfocusedCpu.class).isEnabled() && !mc.isWindowActive()) { if (ModuleManager.INSTANCE.getModuleByClass(UnfocusedCpu.class).isEnabled() && !mc.isWindowActive()) {
ci.cancel(); ci.cancel();
} }
@@ -81,7 +81,7 @@ public abstract class GameRendererMixin {
@Inject(method = "renderItemInHand", at = @At("HEAD"), cancellable = true) @Inject(method = "renderItemInHand", at = @At("HEAD"), cancellable = true)
private void renderHand(CameraRenderState cameraState, float deltaPartialTick, Matrix4fc modelViewMatrix, CallbackInfo ci) { private void renderHand(CameraRenderState cameraState, PlayerRenderState playerRenderState, GpuTextureView texture, CallbackInfo ci) {
if ((zoom.isEnabled() && !zoom.showHands.getValue()) if ((zoom.isEnabled() && !zoom.showHands.getValue())
|| (freecam.isEnabled() && !freecam.renderHands.getValue())) || (freecam.isEnabled() && !freecam.renderHands.getValue()))
ci.cancel(); ci.cancel();
@@ -3,11 +3,12 @@ package me.retucio.sputnik.mixin.mixins.render;
import me.retucio.sputnik.module.ModuleManager; import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.render.GlintPlus; import me.retucio.sputnik.module.modules.render.GlintPlus;
import net.minecraft.client.renderer.feature.ItemFeatureRenderer; import net.minecraft.client.renderer.feature.ItemFeatureRenderer;
import net.minecraft.client.resources.model.geometry.BakedQuad;
import net.minecraft.client.renderer.rendertype.RenderType; import net.minecraft.client.renderer.rendertype.RenderType;
import net.minecraft.client.renderer.rendertype.RenderTypes;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect; import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.sugar.Local;
@Mixin(ItemFeatureRenderer.class) @Mixin(ItemFeatureRenderer.class)
@@ -15,17 +16,15 @@ public abstract class ItemFeatureRendererMixin {
// obtener módulo en cada redirect, ya que tiene un inicializador estático // obtener módulo en cada redirect, ya que tiene un inicializador estático
@Redirect(method = "getFoilBuffer", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/rendertype/RenderTypes;glint()Lnet/minecraft/client/renderer/rendertype/RenderType;")) @ModifyExpressionValue(method = "prepareMainSubmit", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/geometry/BakedQuad$MaterialInfo;itemGlintRenderType()Lnet/minecraft/client/renderer/rendertype/RenderType;"))
private static RenderType redirectGlint() { private RenderType sputnik$colorGlint(RenderType original, @Local BakedQuad.MaterialInfo materialInfo) {
GlintPlus glintPlus = ModuleManager.INSTANCE.getModuleByClass(GlintPlus.class); GlintPlus glintPlus = ModuleManager.INSTANCE.getModuleByClass(GlintPlus.class);
if (glintPlus == null) return RenderTypes.glint(); return glintPlus == null ? original : glintPlus.getGlint(original, materialInfo);
return glintPlus.getGlint();
} }
@Redirect(method = "getFoilBuffer", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/rendertype/RenderTypes;glintTranslucent()Lnet/minecraft/client/renderer/rendertype/RenderType;")) @ModifyExpressionValue(method = "prepareMainSubmit", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/geometry/BakedQuad$MaterialInfo;itemGlintSpecialRenderType()Lnet/minecraft/client/renderer/rendertype/RenderType;"))
private static RenderType redirectGlintTranslucent() { private RenderType sputnik$colorSpecialGlint(RenderType original, @Local BakedQuad.MaterialInfo materialInfo) {
GlintPlus glintPlus = ModuleManager.INSTANCE.getModuleByClass(GlintPlus.class); GlintPlus glintPlus = ModuleManager.INSTANCE.getModuleByClass(GlintPlus.class);
if (glintPlus == null) return RenderTypes.glintTranslucent(); return glintPlus == null ? original : glintPlus.getGlint(original, materialInfo);
return glintPlus.getGlintTranslucent();
} }
} }
@@ -7,7 +7,7 @@ import me.retucio.sputnik.event.render.RenderArmEvent;
import me.retucio.sputnik.module.ModuleManager; import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.render.HandView; import me.retucio.sputnik.module.modules.render.HandView;
import net.minecraft.client.player.AbstractClientPlayer; import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.ItemInHandRenderer; import net.minecraft.client.renderer.FirstPersonHandsAndItemsRenderer;
import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.HumanoidArm; import net.minecraft.world.entity.HumanoidArm;
@@ -23,7 +23,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import static me.retucio.sputnik.Sputnik.*; import static me.retucio.sputnik.Sputnik.*;
@Mixin(ItemInHandRenderer.class) @Mixin(FirstPersonHandsAndItemsRenderer.class)
public abstract class ItemInHandRendererMixin { public abstract class ItemInHandRendererMixin {
@Unique @Unique
@@ -49,12 +49,12 @@ public abstract class ItemInHandRendererMixin {
handView = ModuleManager.INSTANCE.getModuleByClass(HandView.class); handView = ModuleManager.INSTANCE.getModuleByClass(HandView.class);
} }
@Inject(method = "submitArmWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemInHandRenderer;renderItem(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemDisplayContext;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;I)V", shift = At.Shift.BEFORE)) @Inject(method = "submitArmWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/FirstPersonHandsAndItemsRenderer;renderItem(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemDisplayContext;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;I)V", shift = At.Shift.BEFORE))
private void onRenderItem(AbstractClientPlayer player, float frameInterp, float xRot, InteractionHand hand, float attack, ItemStack itemStack, float inverseArmHeight, PoseStack matrices, SubmitNodeCollector submitNodeCollector, int lightCoords, CallbackInfo ci) { private void onRenderItem(AbstractClientPlayer player, float frameInterp, float xRot, InteractionHand hand, float attack, ItemStack itemStack, float inverseArmHeight, PoseStack matrices, SubmitNodeCollector submitNodeCollector, int lightCoords, CallbackInfo ci) {
EVENT_BUS.post(new RenderHeldItemEvent(matrices, hand)); EVENT_BUS.post(new RenderHeldItemEvent(matrices, hand));
} }
@Inject(method = "submitArmWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemInHandRenderer;renderPlayerArm(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;IFFLnet/minecraft/world/entity/HumanoidArm;)V")) @Inject(method = "submitArmWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/FirstPersonHandsAndItemsRenderer;renderPlayerArm(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;IFFLnet/minecraft/world/entity/HumanoidArm;)V"))
private void onRenderArm(AbstractClientPlayer player, float frameInterp, float xRot, InteractionHand hand, float attack, ItemStack itemStack, float inverseArmHeight, PoseStack matrices, SubmitNodeCollector submitNodeCollector, int lightCoords, CallbackInfo ci) { private void onRenderArm(AbstractClientPlayer player, float frameInterp, float xRot, InteractionHand hand, float attack, ItemStack itemStack, float inverseArmHeight, PoseStack matrices, SubmitNodeCollector submitNodeCollector, int lightCoords, CallbackInfo ci) {
EVENT_BUS.post(new RenderArmEvent(matrices, hand)); EVENT_BUS.post(new RenderArmEvent(matrices, hand));
} }
@@ -1,7 +1,6 @@
package me.retucio.sputnik.mixin.mixins.render; package me.retucio.sputnik.mixin.mixins.render;
import com.llamalad7.mixinextras.sugar.Local; import com.mojang.renderpearl.api.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.resource.GraphicsResourceAllocator; import com.mojang.blaze3d.resource.GraphicsResourceAllocator;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis; import com.mojang.math.Axis;
@@ -10,16 +9,25 @@ import me.retucio.sputnik.event.render.Render3DEvent;
import me.retucio.sputnik.event.render.RenderBlockOutlineEvent; import me.retucio.sputnik.event.render.RenderBlockOutlineEvent;
import me.retucio.sputnik.module.ModuleManager; import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.camera.Freecam; import me.retucio.sputnik.module.modules.camera.Freecam;
import me.retucio.sputnik.module.modules.render.BreakingProgress;
import me.retucio.sputnik.util.render.SputnikBuffers; import me.retucio.sputnik.util.render.SputnikBuffers;
import net.minecraft.client.DeltaTracker; import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.ShaderManager;
import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.renderer.state.level.CameraRenderState; import net.minecraft.client.renderer.state.level.CameraRenderState;
import net.minecraft.client.renderer.state.level.LevelRenderState; import net.minecraft.client.renderer.state.level.LevelRenderState;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.resources.model.sprite.AtlasManager;
import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.util.profiling.Profiler;
import org.joml.Matrix4fc; import org.joml.Matrix4fc;
import org.joml.Vector4f; import org.joml.Vector4f;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.*; import org.spongepowered.asm.mixin.injection.*;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.invoke.arg.Args; import org.spongepowered.asm.mixin.injection.invoke.arg.Args;
@@ -31,18 +39,29 @@ import static me.retucio.sputnik.Sputnik.mc;
@Mixin(LevelRenderer.class) @Mixin(LevelRenderer.class)
public abstract class LevelRendererMixin { public abstract class LevelRendererMixin {
@Unique
private BreakingProgress bp;
@Inject(method = "<init>", at = @At("TAIL"))
private void getModules(EntityRenderDispatcher entityRenderDispatcher, BlockEntityRenderDispatcher blockEntityRenderDispatcher, ModelManager modelManager, TextureManager textureManager, AtlasManager atlasManager, ShaderManager shaderManager, GameRenderer gameRenderer, int width, int height, CallbackInfo ci) {
bp = ModuleManager.INSTANCE.getModuleByClass(BreakingProgress.class);
}
@Inject(method = "render", at = @At("RETURN")) @Inject(method = "render", at = @At("RETURN"))
private void render(GraphicsResourceAllocator resourceAllocator, DeltaTracker dt, boolean renderOutline, CameraRenderState cameraState, Matrix4fc modelViewMatrix, GpuBufferSlice terrainFog, Vector4f fogColor, boolean shouldRenderSky, CallbackInfo ci, @Local(name = "profiler") ProfilerFiller profiler) { private void render(GraphicsResourceAllocator resourceAllocator, boolean renderOutline,
CameraRenderState cameraState, GpuBufferSlice terrainFog, Vector4f fogColor,
boolean shouldRenderSky, boolean shouldRenderWeather, CallbackInfo ci) {
if (mc == null || mc.level == null) return; if (mc == null || mc.level == null) return;
ProfilerFiller profiler = Profiler.get();
PoseStack matrices = new PoseStack(); PoseStack matrices = new PoseStack();
matrices.pushPose(); matrices.pushPose();
matrices.mulPose(Axis.XP.rotationDegrees(cameraState.xRot)); matrices.rotate(Axis.XP.rotationDegrees(cameraState.xRot));
matrices.mulPose(Axis.YP.rotationDegrees(cameraState.yRot + 180f)); matrices.rotate(Axis.YP.rotationDegrees(cameraState.yRot + 180f));
profiler.push(Sputnik.MOD_ID + "-3d"); profiler.push(Sputnik.MOD_ID + "-3d");
EVENT_BUS.post(new Render3DEvent(matrices, dt, cameraState)); EVENT_BUS.post(new Render3DEvent(matrices, mc.getDeltaTracker(), cameraState));
SputnikBuffers.flush(); // antes de que empiece el hud SputnikBuffers.flush(); // antes de que empiece el hud
profiler.pop(); profiler.pop();
@@ -55,13 +74,6 @@ public abstract class LevelRendererMixin {
if (freecam.isEnabled() && !freecam.blockOutlines.getValue()) ci.cancel(); if (freecam.isEnabled() && !freecam.blockOutlines.getValue()) ci.cancel();
} }
// @Inject(method = "hasBlindnessOrDarkness(Lnet/minecraft/client/extractRenderState/Camera;)Z", at = @At("HEAD"), cancellable = true)
// private void hasBlindnessOrDarkness(Camera camera, CallbackInfoReturnable<Boolean> cir) {
// NoRender noRender = ModuleManager.INSTANCE.getModuleByClass(NoRender.class);
// if (!noRender.isEnabled()) return;
// if (!noRender.blindnessEffect.getValue() || !noRender.darknessEffect.getValue()) cir.setReturnValue(null);
// }
// puto mojang con sus nombres confusos // puto mojang con sus nombres confusos
@ModifyArgs(method = "submitBlockOutline", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/LevelRenderer;submitHitOutline(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/rendertype/RenderType;Lnet/minecraft/client/renderer/state/level/BlockOutlineRenderState;IFZ)V")) @ModifyArgs(method = "submitBlockOutline", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/LevelRenderer;submitHitOutline(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/rendertype/RenderType;Lnet/minecraft/client/renderer/state/level/BlockOutlineRenderState;IFZ)V"))
private void modifyBlockOutline(Args args) { private void modifyBlockOutline(Args args) {
@@ -72,4 +84,12 @@ public abstract class LevelRendererMixin {
if (event.getLineWidth() != (float) args.get(5)) if (event.getLineWidth() != (float) args.get(5))
args.set(5, event.getLineWidth()); args.set(5, event.getLineWidth());
} }
}
@Inject(method = "submitBlockDestroyAnimation", at = @At("HEAD"), cancellable = true)
private void cancelBreakingAnim(PoseStack poseStack, SubmitNodeCollector submitNodeCollector, LevelRenderState levelRenderState, CallbackInfo ci) {
if (!bp.isEnabled()) return;
if (bp.cancelAnim.getValue()) {
ci.cancel();
}
}
}
@@ -1,7 +1,7 @@
package me.retucio.sputnik.mixin.mixins.render; package me.retucio.sputnik.mixin.mixins.render;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.GpuTexture; import com.mojang.renderpearl.api.textures.GpuTexture;
import me.retucio.sputnik.module.ModuleManager; import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.camera.Fullbright; import me.retucio.sputnik.module.modules.camera.Fullbright;
import net.minecraft.client.renderer.Lightmap; import net.minecraft.client.renderer.Lightmap;
@@ -3,9 +3,9 @@ package me.retucio.sputnik.mixin.mixins.render;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import me.retucio.sputnik.module.ModuleManager; import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.render.NoRender; import me.retucio.sputnik.module.modules.render.NoRender;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ScreenEffectRenderer; import net.minecraft.client.renderer.ScreenEffectRenderer;
import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.state.level.PlayerRenderState;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
@@ -31,7 +31,7 @@ public abstract class ScreenEffectRendererMixin {
} }
@Inject(method = "submitWater", at = @At("HEAD"), cancellable = true) @Inject(method = "submitWater", at = @At("HEAD"), cancellable = true)
private static void noRenderUnderwaterOverlay(Minecraft minecraft, PoseStack matrices, SubmitNodeCollector collector, CallbackInfo ci) { private static void noRenderUnderwaterOverlay(PlayerRenderState.WaterOverlay waterOverlay, PoseStack matrices, SubmitNodeCollector collector, CallbackInfo ci) {
if (noRender.isEnabled() && !noRender.fluidOverlay.getValue()) ci.cancel(); if (noRender.isEnabled() && !noRender.fluidOverlay.getValue()) ci.cancel();
} }
} }
@@ -6,14 +6,23 @@ import net.minecraft.client.renderer.ShaderManager;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.server.packs.resources.PreparableReloadListener;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
@Mixin(ShaderManager.class) @Mixin(ShaderManager.class)
public abstract class ShaderManagerMixin { public abstract class ShaderManagerMixin {
@Inject(method = "apply(Lnet/minecraft/client/renderer/ShaderManager$Configs;Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V", at = @At("TAIL")) @Inject(method = "reload", at = @At("RETURN"))
private void onReload(CallbackInfo ci) { private void onReload(PreparableReloadListener.SharedState state, Executor preparationExecutor,
Pipelines.init(); PreparableReloadListener.PreparationBarrier barrier, Executor applyExecutor,
PostShaders.reload(); CallbackInfoReturnable<CompletableFuture<Void>> cir) {
cir.getReturnValue().thenRun(() -> {
Pipelines.init();
PostShaders.reload();
});
} }
} }
@@ -1,6 +1,7 @@
package me.retucio.sputnik.mixin.mixins.render; package me.retucio.sputnik.mixin.mixins.render;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.renderpearl.api.commands.RenderPass;
import me.retucio.sputnik.module.ModuleManager; import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.render.NoRender; import me.retucio.sputnik.module.modules.render.NoRender;
import me.retucio.sputnik.module.modules.world.TimeChanger; import me.retucio.sputnik.module.modules.world.TimeChanger;
@@ -26,17 +27,17 @@ public abstract class SkyRendererMixin {
} }
@Inject(method = "renderSun", at = @At("HEAD"), cancellable = true) @Inject(method = "renderSun", at = @At("HEAD"), cancellable = true)
private void onRenderSun(float rainBrightness, PoseStack poseStack, CallbackInfo ci) { private void onRenderSun(RenderPass renderPass, float rainBrightness, PoseStack poseStack, CallbackInfo ci) {
if (timeChanger.isEnabled() && !timeChanger.renderSun.getValue()) ci.cancel(); if (timeChanger.isEnabled() && !timeChanger.renderSun.getValue()) ci.cancel();
} }
@Inject(method = "renderMoon", at = @At("HEAD"), cancellable = true) @Inject(method = "renderMoon", at = @At("HEAD"), cancellable = true)
private void onRenderMoon(MoonPhase moonPhase, float rainBrightness, PoseStack poseStack, CallbackInfo ci) { private void onRenderMoon(RenderPass renderPass, MoonPhase moonPhase, float rainBrightness, PoseStack poseStack, CallbackInfo ci) {
if (!timeChanger.isEnabled()) return; if (!timeChanger.isEnabled()) return;
if (!timeChanger.renderMoon.getValue()) ci.cancel(); if (!timeChanger.renderMoon.getValue()) ci.cancel();
} }
@ModifyArg(method = "renderSunMoonAndStars", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/SkyRenderer;renderMoon(Lnet/minecraft/world/level/MoonPhase;FLcom/mojang/blaze3d/vertex/PoseStack;)V")) @ModifyArg(method = "renderSunMoonAndStars", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/SkyRenderer;renderMoon(Lcom/mojang/renderpearl/api/commands/RenderPass;Lnet/minecraft/world/level/MoonPhase;FLcom/mojang/blaze3d/vertex/PoseStack;)V"))
private MoonPhase timeChangerMoonPhase(MoonPhase original) { private MoonPhase timeChangerMoonPhase(MoonPhase original) {
if (!timeChanger.isEnabled() || timeChanger.moonPhase.is(TimeChanger.MoonPhases.DEFAULT)) return original; if (!timeChanger.isEnabled() || timeChanger.moonPhase.is(TimeChanger.MoonPhases.DEFAULT)) return original;
int phase = timeChanger.moonPhase.getIndex(); int phase = timeChanger.moonPhase.getIndex();
@@ -45,12 +46,12 @@ public abstract class SkyRendererMixin {
} }
@Inject(method = "renderStars", at = @At("HEAD"), cancellable = true) @Inject(method = "renderStars", at = @At("HEAD"), cancellable = true)
private void onRenderStars(float starBrightness, PoseStack poseStack, CallbackInfo ci) { private void onRenderStars(RenderPass renderPass, float starBrightness, PoseStack poseStack, CallbackInfo ci) {
if (timeChanger.isEnabled() && !timeChanger.renderStars.getValue()) ci.cancel(); if (timeChanger.isEnabled() && !timeChanger.renderStars.getValue()) ci.cancel();
} }
@Inject(method = "renderEndFlash", at = @At("HEAD"), cancellable = true) @Inject(method = "renderEndFlash", at = @At("HEAD"), cancellable = true)
private void onEndFlash(PoseStack matrices, float intensity, float xAngle, float yAngle, CallbackInfo ci) { private void onEndFlash(RenderPass renderPass, PoseStack poseStack, float intensity, float xAngle, float yAngle, CallbackInfo ci) {
NoRender noRender = ModuleManager.INSTANCE.getModuleByClass(NoRender.class); NoRender noRender = ModuleManager.INSTANCE.getModuleByClass(NoRender.class);
if (noRender.isEnabled() && !noRender.endFlashes.getValue()) ci.cancel(); if (noRender.isEnabled() && !noRender.endFlashes.getValue()) ci.cancel();
} }
@@ -4,7 +4,7 @@ import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.render.NoRender; import me.retucio.sputnik.module.modules.render.NoRender;
import net.minecraft.client.renderer.WeatherEffectRenderer; import net.minecraft.client.renderer.WeatherEffectRenderer;
import net.minecraft.client.renderer.state.level.WeatherRenderState; import net.minecraft.client.renderer.state.level.WeatherRenderState;
import net.minecraft.world.phys.Vec3; import com.mojang.renderpearl.api.commands.RenderPass;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
@@ -24,7 +24,7 @@ public abstract class WeatherEffectRendererMixin {
} }
@Inject(method = "render", at = @At("HEAD")) @Inject(method = "render", at = @At("HEAD"))
private void noRenderRainAndSnow(Vec3 cameraPos, WeatherRenderState renderState, CallbackInfo ci) { private void noRenderRainAndSnow(WeatherRenderState renderState, RenderPass renderPass, CallbackInfo ci) {
if (noRender.isEnabled()) { if (noRender.isEnabled()) {
if (!noRender.rain.getValue()) renderState.rainColumns.clear(); if (!noRender.rain.getValue()) renderState.rainColumns.clear();
if (!noRender.snow.getValue()) renderState.snowColumns.clear(); if (!noRender.snow.getValue()) renderState.snowColumns.clear();
@@ -1,6 +1,7 @@
package me.retucio.sputnik.module; package me.retucio.sputnik.module;
import com.github.retucio.neutrino.EventListener; import com.github.retucio.neutrino.EventListener;
import com.mojang.blaze3d.platform.InputConstants;
import me.retucio.sputnik.Sputnik; import me.retucio.sputnik.Sputnik;
import me.retucio.sputnik.config.ConfigManager; import me.retucio.sputnik.config.ConfigManager;
import me.retucio.sputnik.event.sputnik.ToggleModuleEvent; import me.retucio.sputnik.event.sputnik.ToggleModuleEvent;
@@ -16,7 +17,6 @@ import me.retucio.sputnik.util.Colors;
import me.retucio.sputnik.util.I18nUtil; import me.retucio.sputnik.util.I18nUtil;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import org.lwjgl.glfw.GLFW;
import java.awt.*; import java.awt.*;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -41,7 +41,7 @@ public class Module {
protected KeySetting bind = new KeySetting( protected KeySetting bind = new KeySetting(
"tecla", "tecla",
"tecla asignada al módulo, ESC para desactivar", "tecla asignada al módulo, ESC para desactivar",
GLFW.GLFW_KEY_UNKNOWN InputConstants.UNKNOWN.getValue()
).translationKey("sputnik.setting.common.bind"); ).translationKey("sputnik.setting.common.bind");
// dejar al usuario elegir si el módulo debería apagarse tras soltar su tecla asignada, o si la tecla debería alternar su estado // dejar al usuario elegir si el módulo debería apagarse tras soltar su tecla asignada, o si la tecla debería alternar su estado
@@ -1,6 +1,6 @@
package me.retucio.sputnik.module.modules.camera; package me.retucio.sputnik.module.modules.camera;
import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.renderpearl.api.pipeline.RenderPipeline;
import me.retucio.sputnik.module.Category; import me.retucio.sputnik.module.Category;
import me.retucio.sputnik.module.Module; import me.retucio.sputnik.module.Module;
import me.retucio.sputnik.module.setting.settings.ColorSetting; import me.retucio.sputnik.module.setting.settings.ColorSetting;
@@ -31,7 +31,7 @@ import net.minecraft.network.protocol.game.*;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
/** continúa en: /** continúa en:
* @see CameraMixin * @see CameraMixin
@@ -104,7 +104,7 @@ public class Freecam extends Module {
private final KeySetting scrollKey = sgSpeed.add(new KeySetting( private final KeySetting scrollKey = sgSpeed.add(new KeySetting(
"tecla del scroll", "tecla del scroll",
"tecla a mantener pulsada para cambiar velocidad con el scroll", "tecla a mantener pulsada para cambiar velocidad con el scroll",
GLFW.GLFW_KEY_LEFT_CONTROL InputConstants.KEY_LCONTROL
)); ));
private final NumberSetting scrollSens = sgSpeed.add(new NumberSetting( private final NumberSetting scrollSens = sgSpeed.add(new NumberSetting(
@@ -128,7 +128,7 @@ public class Freecam extends Module {
super("cámara libre", super("cámara libre",
"permite a la cámara moverse independientemente del jugador. útil para explorar alrededores", "permite a la cámara moverse independientemente del jugador. útil para explorar alrededores",
Category.CAMERA, Category.CAMERA,
GLFW.GLFW_KEY_V); InputConstants.KEY_V);
speedSetting.onUpdate(newSpeed -> speed = newSpeed); speedSetting.onUpdate(newSpeed -> speed = newSpeed);
} }
@@ -262,37 +262,36 @@ public class Freecam extends Module {
Packet<?> packet = event.getPacket(); Packet<?> packet = event.getPacket();
if (packet instanceof ServerboundPlayerActionPacket if (packet instanceof ServerboundPlayerActionPacket
|| packet instanceof ServerboundUseItemOnPacket || packet instanceof ServerboundUseItemOnPacket
|| packet instanceof ServerboundUseItemPacket || packet instanceof ServerboundUseItemPacket) {
|| packet instanceof ServerboundSwingPacket) {
event.cancel(); event.cancel();
} }
} }
@EventListener @EventListener
private void onKey(KeyEvent event) { private void onKey(KeyEvent event) {
if (KeyUtil.isKeyDown(GLFW.GLFW_KEY_F3)) return; if (KeyUtil.isKeyDown(InputConstants.KEY_F3)) return;
if (mc.gui.screen() != null) return; if (mc.gui.screen() != null) return;
net.minecraft.client.input.KeyEvent key = new net.minecraft.client.input.KeyEvent(event.getKey(), event.getScancode(), 0); net.minecraft.client.input.KeyEvent key = new net.minecraft.client.input.KeyEvent(event.getKey(), event.getScancode(), 0);
boolean shouldCancel = true; boolean shouldCancel = true;
if (mc.options.keyUp.matches(key)) { if (mc.options.keyUp.matches(key)) {
forward = event.getAction() != GLFW.GLFW_RELEASE; forward = event.getAction() != InputConstants.RELEASE;
mc.options.keyUp.setDown(false); mc.options.keyUp.setDown(false);
} else if (mc.options.keyDown.matches(key)) { } else if (mc.options.keyDown.matches(key)) {
backward = event.getAction() != GLFW.GLFW_RELEASE; backward = event.getAction() != InputConstants.RELEASE;
mc.options.keyDown.setDown(false); mc.options.keyDown.setDown(false);
} else if (mc.options.keyRight.matches(key)) { } else if (mc.options.keyRight.matches(key)) {
right = event.getAction() != GLFW.GLFW_RELEASE; right = event.getAction() != InputConstants.RELEASE;
mc.options.keyRight.setDown(false); mc.options.keyRight.setDown(false);
} else if (mc.options.keyLeft.matches(key)) { } else if (mc.options.keyLeft.matches(key)) {
left = event.getAction() != GLFW.GLFW_RELEASE; left = event.getAction() != InputConstants.RELEASE;
mc.options.keyLeft.setDown(false); mc.options.keyLeft.setDown(false);
} else if (mc.options.keyJump.matches(key)) { } else if (mc.options.keyJump.matches(key)) {
up = event.getAction() != GLFW.GLFW_RELEASE; up = event.getAction() != InputConstants.RELEASE;
mc.options.keyJump.setDown(false); mc.options.keyJump.setDown(false);
} else if (mc.options.keyShift.matches(key)) { } else if (mc.options.keyShift.matches(key)) {
down = event.getAction() != GLFW.GLFW_RELEASE; down = event.getAction() != InputConstants.RELEASE;
mc.options.keyShift.setDown(false); mc.options.keyShift.setDown(false);
} else { } else {
shouldCancel = false; shouldCancel = false;
@@ -303,29 +302,29 @@ public class Freecam extends Module {
@EventListener @EventListener
private void onMouseClick(MouseClickEvent event) { // por si el restrasado del usuario usa el ratón para moverse private void onMouseClick(MouseClickEvent event) { // por si el restrasado del usuario usa el ratón para moverse
if (KeyUtil.isKeyDown(GLFW.GLFW_KEY_F3)) return; if (KeyUtil.isKeyDown(InputConstants.KEY_F3)) return;
if (mc.gui.screen() != null) return; if (mc.gui.screen() != null) return;
MouseButtonEvent click = new MouseButtonEvent(0, 0, new MouseButtonInfo(event.getButton(), 0)); MouseButtonEvent click = new MouseButtonEvent(0, 0, new MouseButtonInfo(event.getButton(), 0));
boolean shouldCancel = true; boolean shouldCancel = true;
if (mc.options.keyUp.matchesMouse(click)) { if (mc.options.keyUp.matchesMouse(click)) {
forward = event.getAction() != GLFW.GLFW_RELEASE; forward = event.getAction() != InputConstants.RELEASE;
mc.options.keyUp.setDown(false); mc.options.keyUp.setDown(false);
} else if (mc.options.keyDown.matchesMouse(click)) { } else if (mc.options.keyDown.matchesMouse(click)) {
backward = event.getAction() != GLFW.GLFW_RELEASE; backward = event.getAction() != InputConstants.RELEASE;
mc.options.keyDown.setDown(false); mc.options.keyDown.setDown(false);
} else if (mc.options.keyRight.matchesMouse(click)) { } else if (mc.options.keyRight.matchesMouse(click)) {
right = event.getAction() != GLFW.GLFW_RELEASE; right = event.getAction() != InputConstants.RELEASE;
mc.options.keyRight.setDown(false); mc.options.keyRight.setDown(false);
} else if (mc.options.keyLeft.matchesMouse(click)) { } else if (mc.options.keyLeft.matchesMouse(click)) {
left = event.getAction() != GLFW.GLFW_RELEASE; left = event.getAction() != InputConstants.RELEASE;
mc.options.keyLeft.setDown(false); mc.options.keyLeft.setDown(false);
} else if (mc.options.keyJump.matchesMouse(click)) { } else if (mc.options.keyJump.matchesMouse(click)) {
up = event.getAction() != GLFW.GLFW_RELEASE; up = event.getAction() != InputConstants.RELEASE;
mc.options.keyJump.setDown(false); mc.options.keyJump.setDown(false);
} else if (mc.options.keyShift.matchesMouse(click)) { } else if (mc.options.keyShift.matchesMouse(click)) {
down = event.getAction() != GLFW.GLFW_RELEASE; down = event.getAction() != InputConstants.RELEASE;
mc.options.keyShift.setDown(false); mc.options.keyShift.setDown(false);
} else { } else {
shouldCancel = false; shouldCancel = false;
@@ -9,7 +9,7 @@ import me.retucio.sputnik.module.setting.settings.NumberSetting;
import me.retucio.sputnik.util.KeyUtil; import me.retucio.sputnik.util.KeyUtil;
import net.minecraft.client.CameraType; import net.minecraft.client.CameraType;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
/** continúa en: /** continúa en:
* @see CameraMixin * @see CameraMixin
@@ -37,7 +37,7 @@ public class Freelook extends Module {
super("perspectiva libre", super("perspectiva libre",
"te permite mover la cámara de la perspectiva sin mover la del jugador, o vice versa", "te permite mover la cámara de la perspectiva sin mover la del jugador, o vice versa",
Category.CAMERA, Category.CAMERA,
GLFW.GLFW_KEY_B); InputConstants.KEY_B);
keyMode.setDefaultValue(KeyMode.HOLD); keyMode.setDefaultValue(KeyMode.HOLD);
keyMode.setValue(KeyMode.HOLD); keyMode.setValue(KeyMode.HOLD);
@@ -75,18 +75,18 @@ public class Freelook extends Module {
for (int i = 0; i < (arrowSens.getValue() * 2); i++) { for (int i = 0; i < (arrowSens.getValue() * 2); i++) {
switch (mode.getValue()) { switch (mode.getValue()) {
case PLAYER -> { case PLAYER -> {
if (KeyUtil.isKeyDown(GLFW.GLFW_KEY_LEFT)) yaw -= 0.5f; if (KeyUtil.isKeyDown(InputConstants.KEY_LEFT)) yaw -= 0.5f;
if (KeyUtil.isKeyDown(GLFW.GLFW_KEY_RIGHT)) yaw += 0.5f; if (KeyUtil.isKeyDown(InputConstants.KEY_RIGHT)) yaw += 0.5f;
if (KeyUtil.isKeyDown(GLFW.GLFW_KEY_UP)) pitch -= 0.5f; if (KeyUtil.isKeyDown(InputConstants.KEY_UP)) pitch -= 0.5f;
if (KeyUtil.isKeyDown(GLFW.GLFW_KEY_DOWN)) pitch += 0.5f; if (KeyUtil.isKeyDown(InputConstants.KEY_DOWN)) pitch += 0.5f;
} case CAMERA -> { } case CAMERA -> {
float yaw = mc.player.getYRot(); float yaw = mc.player.getYRot();
float pitch = mc.player.getXRot(); float pitch = mc.player.getXRot();
if (KeyUtil.isKeyDown(GLFW.GLFW_KEY_LEFT)) yaw -= 0.5f; if (KeyUtil.isKeyDown(InputConstants.KEY_LEFT)) yaw -= 0.5f;
if (KeyUtil.isKeyDown(GLFW.GLFW_KEY_RIGHT)) yaw += 0.5f; if (KeyUtil.isKeyDown(InputConstants.KEY_RIGHT)) yaw += 0.5f;
if (KeyUtil.isKeyDown(GLFW.GLFW_KEY_UP)) pitch -= 0.5f; if (KeyUtil.isKeyDown(InputConstants.KEY_UP)) pitch -= 0.5f;
if (KeyUtil.isKeyDown(GLFW.GLFW_KEY_DOWN)) pitch += 0.5f; if (KeyUtil.isKeyDown(InputConstants.KEY_DOWN)) pitch += 0.5f;
mc.player.setYRot(yaw); mc.player.setYRot(yaw);
mc.player.setXRot(pitch); mc.player.setXRot(pitch);
@@ -9,7 +9,7 @@ import me.retucio.sputnik.module.setting.settings.EnumSetting;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects; import net.minecraft.world.effect.MobEffects;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.awt.*; import java.awt.*;
@@ -39,7 +39,7 @@ public class Fullbright extends Module {
super("brilli brilli", super("brilli brilli",
"deshabilita la oscuridad (y aplica colores a los shaders)", "deshabilita la oscuridad (y aplica colores a los shaders)",
Category.CAMERA, Category.CAMERA,
GLFW.GLFW_KEY_K); InputConstants.KEY_K);
mode.onUpdate(mode -> { if (mode != Modes.POTION) disableNightVision(); }); mode.onUpdate(mode -> { if (mode != Modes.POTION) disableNightVision(); });
} }
@@ -10,7 +10,7 @@ import me.retucio.sputnik.module.setting.settings.BooleanSetting;
import me.retucio.sputnik.module.setting.settings.KeySetting; import me.retucio.sputnik.module.setting.settings.KeySetting;
import me.retucio.sputnik.module.setting.settings.NumberSetting; import me.retucio.sputnik.module.setting.settings.NumberSetting;
import net.minecraft.client.CameraType; import net.minecraft.client.CameraType;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
/** continúa en: /** continúa en:
@@ -36,7 +36,7 @@ public class PerspectivePlus extends Module {
1, 0, 8, 0.1)); 1, 0, 8, 0.1));
private final KeySetting scrollKey = sgScroll.add(new KeySetting("tecla del scroll", "qué tecla mantener para usar la rueda del ratón", private final KeySetting scrollKey = sgScroll.add(new KeySetting("tecla del scroll", "qué tecla mantener para usar la rueda del ratón",
GLFW.GLFW_KEY_LEFT_ALT)); InputConstants.KEY_LALT));
private double distance; private double distance;
@@ -9,7 +9,7 @@ import me.retucio.sputnik.module.setting.SettingGroup;
import me.retucio.sputnik.module.setting.settings.BooleanSetting; import me.retucio.sputnik.module.setting.settings.BooleanSetting;
import me.retucio.sputnik.module.setting.settings.KeySetting; import me.retucio.sputnik.module.setting.settings.KeySetting;
import me.retucio.sputnik.module.setting.settings.NumberSetting; import me.retucio.sputnik.module.setting.settings.NumberSetting;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
/** continúa en: /** continúa en:
@@ -33,7 +33,7 @@ public class Zoom extends Module {
private final NumberSetting scrollSens = sgScroll.add(new NumberSetting("sensibilidad del scroll", "sensibilidad de la rueda del ratón (0 para desactivar)", private final NumberSetting scrollSens = sgScroll.add(new NumberSetting("sensibilidad del scroll", "sensibilidad de la rueda del ratón (0 para desactivar)",
0.4, 0, 8, 0.1)); 0.4, 0, 8, 0.1));
private final KeySetting scrollKey = sgScroll.add(new KeySetting("tecla del scroll", "qué tecla mantener para usar la rueda del ratón", private final KeySetting scrollKey = sgScroll.add(new KeySetting("tecla del scroll", "qué tecla mantener para usar la rueda del ratón",
GLFW.GLFW_KEY_LEFT_CONTROL)); InputConstants.KEY_LCONTROL));
private final NumberSetting mouseSensMultiplier = sgCam.add(new NumberSetting("sensibilidad", "multiplicador de la sensibilidad del ratón", private final NumberSetting mouseSensMultiplier = sgCam.add(new NumberSetting("sensibilidad", "multiplicador de la sensibilidad del ratón",
0.4, 0, 1, 0.05)); 0.4, 0, 1, 0.05));
@@ -49,7 +49,7 @@ public class Zoom extends Module {
super("zoom", super("zoom",
"lupa", "lupa",
Category.CAMERA, Category.CAMERA,
GLFW.GLFW_KEY_F); InputConstants.KEY_F);
keyMode.setDefaultValue(KeyMode.HOLD); keyMode.setDefaultValue(KeyMode.HOLD);
keyMode.setValue(KeyMode.HOLD); keyMode.setValue(KeyMode.HOLD);
@@ -103,7 +103,7 @@ public class Zoom extends Module {
@EventListener @EventListener
private void onMouseScroll(MouseScrollEvent event) { private void onMouseScroll(MouseScrollEvent event) {
boolean key = scrollKey.getValue() == GLFW.GLFW_KEY_UNKNOWN || scrollKey.isDown(); boolean key = scrollKey.getValue() == InputConstants.UNKNOWN.getValue() || scrollKey.isDown();
if (isEnabled() && scrollSens.getValue() > 0 && key) { if (isEnabled() && scrollSens.getValue() > 0 && key) {
value += event.getVertical() * 0.25 * (scrollSens.getValue() * value); value += event.getVertical() * 0.25 * (scrollSens.getValue() * value);
if (value < 1) value = 1; if (value < 1) value = 1;
@@ -1,6 +1,7 @@
package me.retucio.sputnik.module.modules.client; package me.retucio.sputnik.module.modules.client;
import com.github.retucio.neutrino.EventListener; import com.github.retucio.neutrino.EventListener;
import com.mojang.blaze3d.platform.InputConstants;
import me.retucio.sputnik.Sputnik; import me.retucio.sputnik.Sputnik;
import me.retucio.sputnik.command.CommandManager; import me.retucio.sputnik.command.CommandManager;
import me.retucio.sputnik.event.TickEvent; import me.retucio.sputnik.event.TickEvent;
@@ -17,7 +18,6 @@ import me.retucio.sputnik.module.setting.settings.NumberSetting;
import me.retucio.sputnik.module.setting.settings.StringSetting; import me.retucio.sputnik.module.setting.settings.StringSetting;
import me.retucio.sputnik.util.ChatUtil; import me.retucio.sputnik.util.ChatUtil;
import me.retucio.sputnik.util.Colors; import me.retucio.sputnik.util.Colors;
import org.lwjgl.glfw.GLFW;
import java.awt.*; import java.awt.*;
@@ -130,7 +130,7 @@ public class ClientSettingsModule extends Module {
super("interfaz", super("interfaz",
"ajustes de la interfaz, y otros misceláneos", "ajustes de la interfaz, y otros misceláneos",
Category.CLIENT, Category.CLIENT,
GLFW.GLFW_KEY_RIGHT_SHIFT); InputConstants.KEY_RSHIFT);
Sputnik.EVENT_BUS.subscribe(this); Sputnik.EVENT_BUS.subscribe(this);
@@ -11,7 +11,7 @@ import me.retucio.sputnik.util.ChatUtil;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
public class Friends extends Module { public class Friends extends Module {
@@ -34,8 +34,8 @@ public class Friends extends Module {
@EventListener @EventListener
public void onMouseClick(MouseClickEvent event) { public void onMouseClick(MouseClickEvent event) {
if (event.getButton() == GLFW.GLFW_MOUSE_BUTTON_MIDDLE if (event.getButton() == InputConstants.MOUSE_BUTTON_MIDDLE
&& event.getAction() == GLFW.GLFW_PRESS && event.getAction() == InputConstants.PRESS
&& middleClick.getValue()) && middleClick.getValue())
{ {
Entity target = mc.crosshairPickEntity; Entity target = mc.crosshairPickEntity;
@@ -9,7 +9,7 @@ import me.retucio.sputnik.ui.hud.HudRenderer;
import me.retucio.sputnik.ui.hud.HudEditorScreen; import me.retucio.sputnik.ui.hud.HudEditorScreen;
import me.retucio.sputnik.ui.hud.elements.CustomImageElement; import me.retucio.sputnik.ui.hud.elements.CustomImageElement;
import me.retucio.sputnik.ui.hud.elements.DynoElement; import me.retucio.sputnik.ui.hud.elements.DynoElement;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.awt.*; import java.awt.*;
@@ -32,7 +32,7 @@ public class Hud extends Module {
public KeySetting editorKey = sgEditor.add(new KeySetting( public KeySetting editorKey = sgEditor.add(new KeySetting(
"tecla del editor", "tecla del editor",
"tecla asignada al editor de elementos del hud", "tecla asignada al editor de elementos del hud",
GLFW.GLFW_KEY_INSERT InputConstants.KEY_INSERT
)); ));
public BooleanSetting axialMovement = sgEditor.add(new BooleanSetting( public BooleanSetting axialMovement = sgEditor.add(new BooleanSetting(
@@ -144,7 +144,7 @@ public class Hud extends Module {
super("HUD", super("HUD",
"superposición de la pantalla con info. adicional", "superposición de la pantalla con info. adicional",
Category.CLIENT, Category.CLIENT,
GLFW.GLFW_KEY_F12 InputConstants.KEY_F12
); );
dyno.onUpdate(v -> { dyno.onUpdate(v -> {
@@ -93,7 +93,7 @@ public class KillAura extends Module {
if (!mc.level.isTickingEntity(entity)) return; if (!mc.level.isTickingEntity(entity)) return;
if (swingHand.getValue()) { if (swingHand.getValue()) {
mc.player.swing(InteractionHand.MAIN_HAND); mc.player.swing(InteractionHand.MAIN_HAND, net.minecraft.world.item.component.SwingAnimation.DEFAULT, false);
} }
mc.gameMode.attack(mc.player, entity); mc.gameMode.attack(mc.player, entity);
@@ -15,7 +15,7 @@ import net.minecraft.world.Container;
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import org.jspecify.annotations.NonNull; import org.jspecify.annotations.NonNull;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.util.List; import java.util.List;
@@ -31,19 +31,19 @@ public class Burglar extends Module {
private final KeySetting triggerKey = sgKeys.add(new KeySetting( private final KeySetting triggerKey = sgKeys.add(new KeySetting(
"tecla activadora", "tecla activadora",
"tecla a mantener para que las otras teclas funcionen", "tecla a mantener para que las otras teclas funcionen",
GLFW.GLFW_KEY_LEFT_CONTROL InputConstants.KEY_LCONTROL
)); ));
private final KeySetting stealKey = sgKeys.add(new KeySetting( private final KeySetting stealKey = sgKeys.add(new KeySetting(
"robar", "robar",
"tecla para robar todo", "tecla para robar todo",
GLFW.GLFW_KEY_S InputConstants.KEY_S
)); ));
private final KeySetting dumpKey = sgKeys.add(new KeySetting( private final KeySetting dumpKey = sgKeys.add(new KeySetting(
"dejar", "dejar",
"tecla para dejar todo", "tecla para dejar todo",
GLFW.GLFW_KEY_D InputConstants.KEY_D
)); ));
@@ -67,7 +67,7 @@ public class Burglar extends Module {
@EventListener @EventListener
private void onKey(KeyEvent event) { private void onKey(KeyEvent event) {
if (!triggerKey.isDown() || event.getAction() != GLFW.GLFW_PRESS if (!triggerKey.isDown() || event.getAction() != InputConstants.PRESS
|| !(mc.gui.screen() instanceof AbstractContainerScreen<?> container)) return; || !(mc.gui.screen() instanceof AbstractContainerScreen<?> container)) return;
if (event.getKey() == stealKey.getValue()) steal(container); if (event.getKey() == stealKey.getValue()) steal(container);
if (event.getKey() == dumpKey.getValue()) dump(container); if (event.getKey() == dumpKey.getValue()) dump(container);
@@ -12,7 +12,7 @@ import me.retucio.sputnik.util.InventoryUtil;
import me.retucio.sputnik.util.KeyUtil; import me.retucio.sputnik.util.KeyUtil;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.world.inventory.Slot; import net.minecraft.world.inventory.Slot;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
/** /**
@@ -21,9 +21,9 @@ import org.lwjgl.glfw.GLFW;
public class InventoryPlus extends Module { public class InventoryPlus extends Module {
private final KeySetting row1key = sgGeneral.add(new KeySetting("fila 1", "tecla para mover items a la primera fila", GLFW.GLFW_KEY_A)); private final KeySetting row1key = sgGeneral.add(new KeySetting("fila 1", "tecla para mover items a la primera fila", InputConstants.KEY_A));
private final KeySetting row2key = sgGeneral.add(new KeySetting("fila 2", "tecla para mover items a la segunda fila", GLFW.GLFW_KEY_S)); private final KeySetting row2key = sgGeneral.add(new KeySetting("fila 2", "tecla para mover items a la segunda fila", InputConstants.KEY_S));
private final KeySetting row3key = sgGeneral.add(new KeySetting("fila 3", "tecla para mover items a la tercera fila", GLFW.GLFW_KEY_D)); private final KeySetting row3key = sgGeneral.add(new KeySetting("fila 3", "tecla para mover items a la tercera fila", InputConstants.KEY_D));
public InventoryPlus() { public InventoryPlus() {
super("inventario plus", super("inventario plus",
@@ -33,13 +33,13 @@ public class InventoryPlus extends Module {
@EventListener @EventListener
private void onKey(KeyEvent event) { private void onKey(KeyEvent event) {
if (event.getAction() == GLFW.GLFW_RELEASE) return; if (event.getAction() == InputConstants.RELEASE) return;
processInput(event.getKey(), event); processInput(event.getKey(), event);
} }
@EventListener @EventListener
private void onMouseButton(MouseClickEvent event) { private void onMouseButton(MouseClickEvent event) {
if (event.getAction() == GLFW.GLFW_RELEASE) return; if (event.getAction() == InputConstants.RELEASE) return;
processInput(event.getButton(), event); processInput(event.getButton(), event);
} }
@@ -22,7 +22,7 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items; import net.minecraft.world.item.Items;
import net.minecraft.world.item.component.ItemContainerContents; import net.minecraft.world.item.component.ItemContainerContents;
import net.minecraft.world.level.block.ShulkerBoxBlock; import net.minecraft.world.level.block.ShulkerBoxBlock;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.awt.*; import java.awt.*;
import java.util.HashMap; import java.util.HashMap;
@@ -30,7 +30,7 @@ import java.util.HashMap;
public class ShulkerPeek extends Module { public class ShulkerPeek extends Module {
public final KeySetting previewKey = sgGeneral.add(new KeySetting("tecla de previsualización", "tecla a mantener para previsualizar", GLFW.GLFW_KEY_LEFT_ALT)); public final KeySetting previewKey = sgGeneral.add(new KeySetting("tecla de previsualización", "tecla a mantener para previsualizar", InputConstants.KEY_LALT));
public final BooleanSetting showTooltips = sgGeneral.add(new BooleanSetting("mostrar tooltips", "añadir texto a los tooltips (cajas de texto) de los shulkers", true)); public final BooleanSetting showTooltips = sgGeneral.add(new BooleanSetting("mostrar tooltips", "añadir texto a los tooltips (cajas de texto) de los shulkers", true));
public static final HashMap<Item, Color> SHULKER_COLORS = new HashMap<>(); public static final HashMap<Item, Color> SHULKER_COLORS = new HashMap<>();
@@ -65,12 +65,12 @@ public class ShulkerPeek extends Module {
if (mc.player == null) return; if (mc.player == null) return;
if (event.getKey() != previewKey.getValue()) return; if (event.getKey() != previewKey.getValue()) return;
if (event.getAction() == GLFW.GLFW_PRESS) { if (event.getAction() == InputConstants.PRESS) {
openPreviewScreen(); openPreviewScreen();
return; return;
} }
if (event.getAction() == GLFW.GLFW_REPEAT) { if (event.getAction() == InputConstants.REPEAT) {
if (mc.gui.screen() instanceof PreviewScreen preview) { if (mc.gui.screen() instanceof PreviewScreen preview) {
if (preview.getType() != PreviewScreen.PreviewType.SHULKER) if (preview.getType() != PreviewScreen.PreviewType.SHULKER)
openPreviewScreen(); openPreviewScreen();
@@ -78,7 +78,7 @@ public class ShulkerPeek extends Module {
return; return;
} }
if (event.getAction() == GLFW.GLFW_RELEASE) { if (event.getAction() == InputConstants.RELEASE) {
if (mc.gui.screen() instanceof PreviewScreen preview) if (mc.gui.screen() instanceof PreviewScreen preview)
preview.onClose(); preview.onClose();
} }
@@ -117,6 +117,6 @@ public class ShulkerPeek extends Module {
if (container == null) return true; if (container == null) return true;
// .stream()? // .stream()?
return container.allItemsCopyStream().allMatch(ItemStack::isEmpty); return container.nonEmptyItemCopyStream().allMatch(ItemStack::isEmpty);
} }
} }
@@ -14,8 +14,12 @@ import java.util.UUID;
public class FakePlayer extends Module { public class FakePlayer extends Module {
private final StringSetting name = sgGeneral.add(new StringSetting("nombre", "qué nombre asignarle al jugador", "apio boy", 22)); private final StringSetting name = sgGeneral.add(new StringSetting(
"nombre", "qué nombre asignarle al jugador",
"apio boy", 22
));
private static int nextFakeId = -2;
private RemotePlayer player = null; private RemotePlayer player = null;
public FakePlayer() { public FakePlayer() {
@@ -27,7 +31,7 @@ public class FakePlayer extends Module {
@Override @Override
public void onEnable() { public void onEnable() {
if (mc.level == null) return; if (mc.level == null) return;
addPlayer(mc.player, name.getValue()); player = addPlayer(mc.player, name.getValue());
super.onEnable(); super.onEnable();
} }
@@ -40,20 +44,23 @@ public class FakePlayer extends Module {
// intento miserable de hacer que no colisione con jugadores // intento miserable de hacer que no colisione con jugadores
public RemotePlayer addPlayer(Player playerToCopy, String dummyName) { public RemotePlayer addPlayer(Player playerToCopy, String dummyName) {
player = new RemotePlayer(mc.level, new GameProfile(UUID.randomUUID(), dummyName)) { RemotePlayer fake = new RemotePlayer(mc.level, new GameProfile(UUID.randomUUID(), dummyName)) {
@Override public void playerTouch(@NonNull Player player) {} @Override public void playerTouch(@NonNull Player p) {}
}; };
player.restoreFrom(playerToCopy); fake.restoreFrom(playerToCopy);
player.setCustomNameVisible(true); fake.setCustomNameVisible(true);
player.noPhysics = true; fake.noPhysics = true;
player.horizontalCollision = false; fake.horizontalCollision = false;
player.verticalCollision = false; fake.verticalCollision = false;
mc.level.addEntity(player);
return player; fake.setId(nextFakeId--);
mc.level.addEntity(fake);
return fake;
} }
public void removePlayer() { public void removePlayer() {
if (player == null) return;
player.setRemoved(Entity.RemovalReason.KILLED); player.setRemoved(Entity.RemovalReason.KILLED);
player.onClientRemoval(); player.onClientRemoval();
player = null; player = null;
@@ -257,12 +257,16 @@ public class LogoutSpots extends Module {
if (outlines.getValue()) { if (outlines.getValue()) {
RenderUtil.drawBlockFaceOutlines(matrices, RenderUtil.drawBlockFaceOutlines(matrices,
BlockPos.containing(x + halfWidth, y, z + halfWidth), BlockPos.containing(x + halfWidth, y, z + halfWidth),
Direction.UP, outlineColor.getValue(), lineWidth.getFloatValue(), true); Direction.UP, outlineColor.getValue(), lineWidth.getFloatValue(),
true
);
} }
if (filling.getValue()) { if (filling.getValue()) {
RenderUtil.drawBlockFaceFilled(matrices, RenderUtil.drawBlockFaceFilled(matrices,
BlockPos.containing(x + halfWidth, y, z + halfWidth), BlockPos.containing(x + halfWidth, y, z + halfWidth),
Direction.UP, fillingColor.getValue(), 0.001f, true); Direction.UP, fillingColor.getValue(), 0.001f,
true
);
} }
} }
} }
@@ -20,7 +20,7 @@ import net.minecraft.world.item.BlockItem;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
public class AirPlace extends Module { public class AirPlace extends Module {
@@ -52,7 +52,7 @@ public class AirPlace extends Module {
private final KeySetting scrollKey = sgScroll.add(new KeySetting( private final KeySetting scrollKey = sgScroll.add(new KeySetting(
"tecla del scroll", "tecla del scroll",
"tecla a mantener para que el scroll funcione", "tecla a mantener para que el scroll funcione",
GLFW.GLFW_KEY_LEFT_CONTROL InputConstants.KEY_LCONTROL
)); ));
private final NumberSetting scrollSens = sgScroll.add(new NumberSetting( private final NumberSetting scrollSens = sgScroll.add(new NumberSetting(
@@ -138,7 +138,7 @@ public class AirPlace extends Module {
@EventListener @EventListener
private void onKey(KeyEvent event) { private void onKey(KeyEvent event) {
if (event.getKey() == scrollKey.getValue() && event.getAction() == GLFW.GLFW_RELEASE) { if (event.getKey() == scrollKey.getValue() && event.getAction() == InputConstants.RELEASE) {
rangeValue = (int) Math.clamp(rangeValue, range.getMin(), range.getMax()); rangeValue = (int) Math.clamp(rangeValue, range.getMin(), range.getMax());
} }
} }
@@ -7,7 +7,7 @@ import me.retucio.sputnik.module.setting.settings.NumberSetting;
import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
public class FastUse extends Module { public class FastUse extends Module {
@@ -61,7 +61,7 @@ public class FastUse extends Module {
super("precoz", super("precoz",
"hace cosas como usar items o colocar bloques más rápido", "hace cosas como usar items o colocar bloques más rápido",
Category.PLAYER, Category.PLAYER,
GLFW.GLFW_KEY_F6); InputConstants.KEY_F6);
items.onUpdate(itemCooldown::visibility); items.onUpdate(itemCooldown::visibility);
blocks.onUpdate(blockCooldown::visibility); blocks.onUpdate(blockCooldown::visibility);
@@ -26,6 +26,12 @@ public class BreakingProgress extends Module {
private final EnumSetting<BreakMode> breakMode = sgGeneral.add(new EnumSetting<>("modo de minado", "elige si el cubo se encoge o se dilata", private final EnumSetting<BreakMode> breakMode = sgGeneral.add(new EnumSetting<>("modo de minado", "elige si el cubo se encoge o se dilata",
BreakMode.class, BreakMode.INWARDS)); BreakMode.class, BreakMode.INWARDS));
public final BooleanSetting cancelAnim = sgGeneral.add(new BooleanSetting(
"cancelar animación",
"no renderizar la anim. original",
true
));
private final BooleanSetting outlines = sgOutlines.add(new BooleanSetting("contorno", "renderizar contorno", true)); private final BooleanSetting outlines = sgOutlines.add(new BooleanSetting("contorno", "renderizar contorno", true));
private final ColorSetting outlineColor = sgOutlines.add(new ColorSetting("color del contorno", "color del contorno", private final ColorSetting outlineColor = sgOutlines.add(new ColorSetting("color del contorno", "color del contorno",
new Color(0, 255, 0, 200), false)); new Color(0, 255, 0, 200), false));
@@ -8,9 +8,11 @@ import me.retucio.sputnik.module.Module;
import me.retucio.sputnik.module.setting.settings.BooleanSetting; import me.retucio.sputnik.module.setting.settings.BooleanSetting;
import me.retucio.sputnik.module.setting.settings.EnumSetting; import me.retucio.sputnik.module.setting.settings.EnumSetting;
import me.retucio.sputnik.util.render.GlintRenderType; import me.retucio.sputnik.util.render.GlintRenderType;
import net.minecraft.client.resources.model.geometry.BakedQuad;
import net.minecraft.client.renderer.rendertype.RenderType; import net.minecraft.client.renderer.rendertype.RenderType;
import net.minecraft.client.renderer.rendertype.RenderTypes; import net.minecraft.client.renderer.rendertype.RenderTypes;
import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.DyeColor;
import net.minecraft.resources.Identifier;
/** continúa en: /** continúa en:
* @see RenderBuffersMixin * @see RenderBuffersMixin
@@ -45,28 +47,22 @@ public class GlintPlus extends Module {
Category.RENDER); Category.RENDER);
} }
public RenderType getGlint() { public RenderType getGlint(RenderType vanilla, BakedQuad.MaterialInfo materialInfo) {
int color = getGlintColor(); if (!isEnabled() || !items.getValue()) return vanilla;
if (!isEnabled() || !items.getValue()) return RenderTypes.glint(); return GlintRenderType.itemGlint(glintColor.getValue().getRealName(), vanilla,
return GlintRenderType.glintColor.get(color); materialInfo.sprite().atlasLocation());
}
public RenderType getGlintTranslucent() {
int color = getGlintColor();
if (!isEnabled() || !items.getValue()) return RenderTypes.glintTranslucent();
return GlintRenderType.glintTranslucentColor.get(color);
} }
public RenderType getEntityGlint() { public RenderType getEntityGlint() {
int color = getGlintColor(); int color = getGlintColor();
if (!isEnabled() || !items.getValue()) return RenderTypes.entityGlint(); if (!isEnabled() || !items.getValue()) return RenderTypes.entitySolidGlint(net.minecraft.client.renderer.texture.TextureAtlas.LOCATION_BLOCKS);
return GlintRenderType.entityGlintColor.get(color); return GlintRenderType.entityGlintColor.get(color);
} }
public RenderType getArmorEntityGlint() { public RenderType getArmorEntityGlint(Identifier armorTexture) {
int color = getGlintColor(); int color = getGlintColor();
if (!isEnabled() || !armor.getValue()) return RenderTypes.armorEntityGlint(); if (!isEnabled() || !armor.getValue()) return RenderTypes.armorCutoutNoCullGlint(armorTexture);
return GlintRenderType.armorEntityGlintColor.get(color); return GlintRenderType.armorEntityGlint(glintColor.getValue().getRealName(), armorTexture);
} }
public int getGlintColor() { public int getGlintColor() {
@@ -128,9 +128,9 @@ public class HandView extends Module {
} }
private void rotate(PoseStack matrix, Vec3 rotation) { private void rotate(PoseStack matrix, Vec3 rotation) {
matrix.mulPose(Axis.XP.rotationDegrees((float) rotation.x)); matrix.rotate(Axis.XP.rotationDegrees((float) rotation.x));
matrix.mulPose(Axis.YP.rotationDegrees((float) rotation.y)); matrix.rotate(Axis.YP.rotationDegrees((float) rotation.y));
matrix.mulPose(Axis.ZP.rotationDegrees((float) rotation.z)); matrix.rotate(Axis.ZP.rotationDegrees((float) rotation.z));
} }
private void scale(PoseStack matrix, Vec3 scale) { private void scale(PoseStack matrix, Vec3 scale) {
@@ -50,7 +50,7 @@ public class ItemPhysics extends Module {
var accessor = (ItemStackRenderStateAccessor) event.renderState.item; var accessor = (ItemStackRenderStateAccessor) event.renderState.item;
for (int i = 0; i < accessor.getActiveLayerCount(); i++) { for (int i = 0; i < accessor.getActiveLayerCount(); i++) {
ItemStackRenderState.LayerRenderState layer = accessor.getLayers()[i]; ItemStackRenderState.LayerRenderState layer = accessor.getLayers()[i];
ModelInfo info = getInfo(layer.prepareQuadList()); ModelInfo info = getInfo(((LayerRenderStateAccessor) layer).sputnik$getQuads().all());
matrices.pushPose(); matrices.pushPose();
applyTransformation(matrices, ((LayerRenderStateAccessor) layer).sputnik$getTransform()); applyTransformation(matrices, ((LayerRenderStateAccessor) layer).sputnik$getTransform());
@@ -58,7 +58,7 @@ public class ItemPhysics extends Module {
offsetInWater(matrices, event.itemEntity); offsetInWater(matrices, event.itemEntity);
if (info.flat) { if (info.flat) {
matrices.mulPose(Axis.XP.rotationDegrees(90)); matrices.rotate(Axis.XP.rotationDegrees(90));
matrices.translate(0, 0, info.offsetZ); matrices.translate(0, 0, info.offsetZ);
} }
@@ -73,7 +73,7 @@ public class ItemPhysics extends Module {
float degrees = (random.nextFloat() * 2 - 1) * 90; float degrees = (random.nextFloat() * 2 - 1) * 90;
matrices.translate(x, y, z); matrices.translate(x, y, z);
matrices.mulPose(axis.rotationDegrees(degrees)); matrices.rotate(axis.rotationDegrees(degrees));
matrices.translate(-x, -y, -z); matrices.translate(-x, -y, -z);
} }
@@ -7,6 +7,7 @@ import com.mojang.blaze3d.resource.GraphicsResourceAllocator;
import me.retucio.sputnik.Sputnik; import me.retucio.sputnik.Sputnik;
import me.retucio.sputnik.module.Category; import me.retucio.sputnik.module.Category;
import me.retucio.sputnik.module.Module; import me.retucio.sputnik.module.Module;
import me.retucio.sputnik.module.setting.settings.EnumSetting;
import me.retucio.sputnik.module.setting.settings.NumberSetting; import me.retucio.sputnik.module.setting.settings.NumberSetting;
import me.retucio.sputnik.util.render.PostShader; import me.retucio.sputnik.util.render.PostShader;
@@ -43,10 +44,11 @@ public class Lsd extends Module {
1, 0, 10, 0.1 1, 0, 10, 0.1
)); ));
private final NumberSetting seed = sgGeneral.add(new NumberSetting( private final EnumSetting<ColorMode> color = sgGeneral.add(new EnumSetting<>(
"tono", "color",
"desplazamiento de tono que se aplica sobre la imagen", "elige el color del efecto",
0.3, 0, 1, 0.01 ColorMode.class,
ColorMode.RAINBOW
)); ));
private final NumberSetting speed = sgGeneral.add(new NumberSetting( private final NumberSetting speed = sgGeneral.add(new NumberSetting(
@@ -71,7 +73,7 @@ public class Lsd extends Module {
public void apply(RenderTarget target, GraphicsResourceAllocator pool) { public void apply(RenderTarget target, GraphicsResourceAllocator pool) {
SHADER.render(target, pool, b -> b SHADER.render(target, pool, b -> b
.putFloat(strength.getFloatValue()) .putFloat(strength.getFloatValue())
.putFloat(seed.getFloatValue()) .putFloat(color.getValue().hue)
.putFloat(rotations.getFloatValue()) .putFloat(rotations.getFloatValue())
.putFloat(getTime())); .putFloat(getTime()));
} }
@@ -82,4 +84,28 @@ public class Lsd extends Module {
double elapsed = (System.nanoTime() - startNanos) / 1_000_000_000.0; double elapsed = (System.nanoTime() - startNanos) / 1_000_000_000.0;
return (float) ((elapsed * speed.getValue()) % 100_000.0); return (float) ((elapsed * speed.getValue()) % 100_000.0);
} }
public enum ColorMode {
RAINBOW("gay", -1.0F),
RED("psoe", 0.0F),
ORANGE("ciudadanos", 0.08F),
YELLOW("d21", 0.16F),
GREEN("vox", 0.33F),
CYAN("eh bildu", 0.5F),
BLUE("pp", 0.66F),
PURPLE("podemos", 0.78F),
PINK("sumar", 0.92F);
private final String name;
private final float hue;
ColorMode(String name, float hue) {
this.name = name; this.hue = hue;
}
@Override
public String toString() {
return name;
}
}
} }
@@ -12,7 +12,7 @@ import me.retucio.sputnik.module.setting.settings.KeySetting;
import me.retucio.sputnik.module.setting.settings.NumberSetting; import me.retucio.sputnik.module.setting.settings.NumberSetting;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import org.joml.Quaternionf; import org.joml.Quaternionf;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -22,7 +22,7 @@ public class Stylish extends Module {
private final KeySetting key = sgGeneral.add(new KeySetting( private final KeySetting key = sgGeneral.add(new KeySetting(
"tecla", "tecla a pulsar para hacer el truco", "tecla", "tecla a pulsar para hacer el truco",
GLFW.GLFW_KEY_Y InputConstants.KEY_Y
)); ));
private final EnumSetting<TrickType> trick = sgGeneral.add(new EnumSetting<>( private final EnumSetting<TrickType> trick = sgGeneral.add(new EnumSetting<>(
@@ -87,7 +87,7 @@ public class Stylish extends Module {
@EventListener @EventListener
private void onKey(KeyEvent event) { private void onKey(KeyEvent event) {
if (event.getKey() != key.getValue()) return; if (event.getKey() != key.getValue()) return;
if (event.getAction() != GLFW.GLFW_PRESS) return; if (event.getAction() != InputConstants.PRESS) return;
if (spinning) return; if (spinning) return;
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
@@ -175,41 +175,41 @@ public class Stylish extends Module {
float angleRad = (float) Math.toRadians(degrees * directionSign); float angleRad = (float) Math.toRadians(degrees * directionSign);
switch (type) { switch (type) {
case SPIN -> matrices.mulPose(new Quaternionf().rotationZ(angleRad)); case SPIN -> matrices.rotate(new Quaternionf().rotationZ(angleRad));
case FLIP -> matrices.mulPose(new Quaternionf().rotationX(angleRad)); case FLIP -> matrices.rotate(new Quaternionf().rotationX(angleRad));
case ROLL -> matrices.mulPose(new Quaternionf().rotationY(angleRad)); case ROLL -> matrices.rotate(new Quaternionf().rotationY(angleRad));
case TWIRL -> { case TWIRL -> {
// combina spin + flip para un giro más aparatoso // combina spin + flip para un giro más aparatoso
matrices.mulPose(new Quaternionf().rotationZ(angleRad)); matrices.rotate(new Quaternionf().rotationZ(angleRad));
matrices.mulPose(new Quaternionf().rotationX(angleRad * 0.5f)); matrices.rotate(new Quaternionf().rotationX(angleRad * 0.5f));
} }
case WAVE -> { case WAVE -> {
// bamboleo tipo saludo, sin vuelta completa // bamboleo tipo saludo, sin vuelta completa
float waveAngle = (float) Math.sin(fraction * Math.PI * spins.getIntValue()) * 25f; float waveAngle = (float) Math.sin(fraction * Math.PI * spins.getIntValue()) * 25f;
matrices.mulPose(new Quaternionf().rotationZ((float) Math.toRadians(waveAngle * directionSign))); matrices.rotate(new Quaternionf().rotationZ((float) Math.toRadians(waveAngle * directionSign)));
} }
case POP -> { case POP -> {
// pequeño pulso de escala, como si el ítem "respirara" // pequeño pulso de escala, como si el ítem "respirara"
float scalePulse = 1f + (float) Math.sin(fraction * Math.PI) * 0.25f; float scalePulse = 1f + (float) Math.sin(fraction * Math.PI) * 0.25f;
matrices.scale(scalePulse, scalePulse, scalePulse); matrices.scale(scalePulse, scalePulse, scalePulse);
matrices.mulPose(new Quaternionf().rotationZ(angleRad * 0.3f)); matrices.rotate(new Quaternionf().rotationZ(angleRad * 0.3f));
} }
case THROW_CATCH -> { case THROW_CATCH -> {
// el ítem "sube", gira en el aire y "cae" de vuelta // el ítem "sube", gira en el aire y "cae" de vuelta
float height = (float) Math.sin(fraction * Math.PI) * 0.35f; float height = (float) Math.sin(fraction * Math.PI) * 0.35f;
matrices.translate(0f, height, 0f); matrices.translate(0f, height, 0f);
matrices.mulPose(new Quaternionf().rotationX(angleRad * 2f)); matrices.rotate(new Quaternionf().rotationX(angleRad * 2f));
} }
case RANDOM -> { case RANDOM -> {
// no debería llegar aquí, resolveTrick lo reemplaza antes // no debería llegar aquí, resolveTrick lo reemplaza antes
matrices.mulPose(new Quaternionf().rotationZ(angleRad)); matrices.rotate(new Quaternionf().rotationZ(angleRad));
} }
} }
} }
@@ -34,7 +34,7 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.phys.shapes.VoxelShape;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.awt.*; import java.awt.*;
import java.util.ArrayDeque; import java.util.ArrayDeque;
@@ -204,8 +204,8 @@ public class AutoMine extends Module {
private void onClick(MouseClickEvent event) { private void onClick(MouseClickEvent event) {
if (mc.gui.screen() != null) return; if (mc.gui.screen() != null) return;
if (mc.level == null || mc.hitResult == null) return; if (mc.level == null || mc.hitResult == null) return;
if (event.getAction() != GLFW.GLFW_PRESS) return; if (event.getAction() != InputConstants.PRESS) return;
if (event.getButton() != GLFW.GLFW_MOUSE_BUTTON_1) return; if (event.getButton() != InputConstants.MOUSE_BUTTON_LEFT) return;
BlockHitResult bhr; BlockHitResult bhr;
if (mc.hitResult.getType() == HitResult.Type.BLOCK) { if (mc.hitResult.getType() == HitResult.Type.BLOCK) {
bhr = (BlockHitResult) mc.hitResult; bhr = (BlockHitResult) mc.hitResult;
@@ -12,6 +12,10 @@ import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ServerboundSignUpdatePacket; import net.minecraft.network.protocol.game.ServerboundSignUpdatePacket;
import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity;
import net.minecraft.world.level.block.entity.SignTextSlot;
import me.retucio.sputnik.util.NetworkUtil;
import java.util.List;
public class AutoSign extends Module { public class AutoSign extends Module {
@@ -41,21 +45,24 @@ public class AutoSign extends Module {
if (event.getScreen() instanceof AbstractSignEditScreen screen && text != null && mc != null && mc.player != null) { if (event.getScreen() instanceof AbstractSignEditScreen screen && text != null && mc != null && mc.player != null) {
event.cancel(); event.cancel();
SignBlockEntity sign = ((AbstractSignEditScreenAccessor) screen).getBlockEntity(); SignBlockEntity sign = ((AbstractSignEditScreenAccessor) screen).getBlockEntity();
fillText(sign.getBlockPos(), sign.isFacingFrontText(mc.player), text); fillText(sign.getBlockPos(), sign.getSlotPlayerIsFacing(mc.player), text);
} }
} }
@EventListener @EventListener
private void onSendPacket(PacketEvent.Send event) { private void onSendPacket(PacketEvent.Send event) {
if (event.getPacket() instanceof ServerboundSignUpdatePacket packet) { if (event.getPacket() instanceof ServerboundSignUpdatePacket packet) {
if (text == null) text = packet.getLines().clone(); if (text == null) {
else System.arraycopy(text, 0, packet.getLines(), 0, 4); text = packet.lines().toArray(String[]::new);
} else {
event.cancel();
NetworkUtil.sendPacketNoEvent(new ServerboundSignUpdatePacket(
packet.pos(), List.of(text), packet.slot()));
}
} }
} }
private void fillText(BlockPos blockPos, boolean front, String[] text) { private void fillText(BlockPos blockPos, SignTextSlot slot, String[] text) {
mc.getConnection().send(new ServerboundSignUpdatePacket( mc.getConnection().send(new ServerboundSignUpdatePacket(blockPos, List.of(text), slot));
blockPos, front, text[0], text[1], text[2], text[3]
));
} }
} }
@@ -19,7 +19,7 @@ import net.minecraft.world.item.component.Tool;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -96,7 +96,7 @@ public class AutoTool extends Module {
if (mc.gui.screen() != null) return; if (mc.gui.screen() != null) return;
if (mode.is(AutoToolMode.ON_TICK) && mc.options.keyAttack.isDown()) { if (mode.is(AutoToolMode.ON_TICK) && mc.options.keyAttack.isDown()) {
handle(KeyUtil.getKey(mc.options.keyAttack), GLFW.GLFW_PRESS); handle(KeyUtil.getKey(mc.options.keyAttack), InputConstants.PRESS);
} }
if (startedMining && delaySetting.getIntValue() > 0) { if (startedMining && delaySetting.getIntValue() > 0) {
@@ -132,9 +132,9 @@ public class AutoTool extends Module {
if (mc.player == null) return; if (mc.player == null) return;
if (key != KeyUtil.getKey(mc.options.keyAttack)) return; if (key != KeyUtil.getKey(mc.options.keyAttack)) return;
if (action == GLFW.GLFW_PRESS) { if (action == InputConstants.PRESS) {
onStartMining(); onStartMining();
} else if (action == GLFW.GLFW_RELEASE) { } else if (action == InputConstants.RELEASE) {
onFinishMining(); onFinishMining();
} }
} }
@@ -20,7 +20,7 @@ import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
@@ -31,7 +31,7 @@ public class BlockInfo extends Module {
private final KeySetting key = sgGeneral.add(new KeySetting( private final KeySetting key = sgGeneral.add(new KeySetting(
"tecla", "tecla",
"tecla a pulsar para obtener la info.", "tecla a pulsar para obtener la info.",
GLFW.GLFW_KEY_CAPS_LOCK InputConstants.KEY_CAPSLOCK
)); ));
private final EnumSetting<CopyMode> copy = sgGeneral.add(new EnumSetting<>( private final EnumSetting<CopyMode> copy = sgGeneral.add(new EnumSetting<>(
@@ -56,7 +56,7 @@ public class BlockInfo extends Module {
@EventListener @EventListener
private void onKey(KeyEvent event) { private void onKey(KeyEvent event) {
if (mc.player == null || mc.level == null) return; if (mc.player == null || mc.level == null) return;
if (event.getKey() != key.getValue() || event.getAction() != GLFW.GLFW_PRESS) return; if (event.getKey() != key.getValue() || event.getAction() != InputConstants.PRESS) return;
HitResult result = mc.player.pick( HitResult result = mc.player.pick(
mc.player.blockInteractionRange(), mc.player.blockInteractionRange(),
@@ -6,6 +6,9 @@ import me.retucio.sputnik.module.Category;
import me.retucio.sputnik.module.Module; import me.retucio.sputnik.module.Module;
import me.retucio.sputnik.module.setting.settings.StringSetting; import me.retucio.sputnik.module.setting.settings.StringSetting;
import net.minecraft.network.protocol.game.ServerboundSignUpdatePacket; import net.minecraft.network.protocol.game.ServerboundSignUpdatePacket;
import me.retucio.sputnik.util.NetworkUtil;
import java.util.ArrayList;
public class ColoredSigns extends Module { public class ColoredSigns extends Module {
@@ -26,9 +29,11 @@ public class ColoredSigns extends Module {
@EventListener @EventListener
private void onSendPacket(PacketEvent.Send event) { private void onSendPacket(PacketEvent.Send event) {
if (event.getPacket() instanceof ServerboundSignUpdatePacket packet) { if (event.getPacket() instanceof ServerboundSignUpdatePacket packet) {
for (int i = 0; i < 4; i++) { event.cancel();
packet.getLines()[i] = packet.getLines()[i].replace(symbol.getValue(), "\247" + "\247a"); NetworkUtil.sendPacketNoEvent(new ServerboundSignUpdatePacket(
} packet.pos(), packet.lines().stream()
.map(line -> line.replace(symbol.getValue(), "\247" + "\247a"))
.toList(), packet.slot()));
} }
} }
} }
@@ -5,7 +5,7 @@ import me.retucio.sputnik.module.Module;
import me.retucio.sputnik.util.EntityUtil; import me.retucio.sputnik.util.EntityUtil;
import me.retucio.sputnik.util.RotationUtil; import me.retucio.sputnik.util.RotationUtil;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.monster.EnderMan; import net.minecraft.world.entity.monster.Enderman;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -14,7 +14,7 @@ import java.util.List;
public class Racist extends Module { public class Racist extends Module {
private int lookTimer; private int lookTimer;
private final List<EnderMan> lookedEndermen = new ArrayList<>(); private final List<Enderman> lookedEndermen = new ArrayList<>();
public Racist() { public Racist() {
super("racismo", super("racismo",
@@ -33,7 +33,7 @@ public class Racist extends Module {
if (mc.level == null || mc.player == null) return; if (mc.level == null || mc.player == null) return;
for (Entity entity : mc.level.getEntities().getAll()) { for (Entity entity : mc.level.getEntities().getAll()) {
if (!(entity instanceof EnderMan enderman)) continue; if (!(entity instanceof Enderman enderman)) continue;
if (shouldLookAt(enderman)) { if (shouldLookAt(enderman)) {
lookAtEnderman(enderman); lookAtEnderman(enderman);
@@ -47,12 +47,12 @@ public class Racist extends Module {
lookTimer++; lookTimer++;
} }
private boolean shouldLookAt(EnderMan enderman) { private boolean shouldLookAt(Enderman enderman) {
return !(lookedEndermen.contains(enderman)) && lookTimer >= 10 return !(lookedEndermen.contains(enderman)) && lookTimer >= 10
&& EntityUtil.hasLineOfSight(mc.player, enderman); && EntityUtil.hasLineOfSight(mc.player, enderman);
} }
private void lookAtEnderman(EnderMan enderman) { private void lookAtEnderman(Enderman enderman) {
RotationUtil.lookAt(RotationUtil.LOW, enderman, EntityUtil.Target.HEAD, 0, RotationUtil.Mode.CLIENT); RotationUtil.lookAt(RotationUtil.LOW, enderman, EntityUtil.Target.HEAD, 0, RotationUtil.Mode.CLIENT);
} }
} }
@@ -1,5 +1,6 @@
package me.retucio.sputnik.module.setting.settings; package me.retucio.sputnik.module.setting.settings;
import com.mojang.blaze3d.platform.InputConstants;
import me.retucio.sputnik.config.ConfigManager; import me.retucio.sputnik.config.ConfigManager;
import me.retucio.sputnik.module.Module; import me.retucio.sputnik.module.Module;
import me.retucio.sputnik.module.ModuleManager; import me.retucio.sputnik.module.ModuleManager;
@@ -8,7 +9,7 @@ import me.retucio.sputnik.ui.widgets.panels.settings.ClientSettingsPanel;
import me.retucio.sputnik.util.ChatUtil; import me.retucio.sputnik.util.ChatUtil;
import me.retucio.sputnik.util.KeyUtil; import me.retucio.sputnik.util.KeyUtil;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import org.lwjgl.glfw.GLFW;
public class KeySetting extends Setting<Integer> { public class KeySetting extends Setting<Integer> {
@@ -22,32 +23,19 @@ public class KeySetting extends Setting<Integer> {
public void setValue(Integer value) { public void setValue(Integer value) {
if (this.value.equals(value)) return; if (this.value.equals(value)) return;
if (value == GLFW.GLFW_KEY_ESCAPE) { if (value == InputConstants.KEY_ESCAPE) {
this.value = GLFW.GLFW_KEY_UNKNOWN; // asignar la tecla ESC a deshabilitar la tecla this.value = InputConstants.UNKNOWN.getValue(); // asignar la tecla ESC a deshabilitar la tecla
fireUpdateEvent(); fireUpdateEvent();
// this.value y no value: lo que se ha guardado es UNKNOWN, no ESC. si no, al
// listener se le decía que la tecla era ESC
if (updateListener != null) updateListener.accept(this.value); if (updateListener != null) updateListener.accept(this.value);
return; return;
} }
// con "teclas multimódulo" puesto se permite repetir tecla, que es justo lo que if (ModuleManager.INSTANCE != null && !ConfigManager.INSTANCE.isApplying()
// dice el ajuste. antes se le quitaba la tecla al otro módulo igualmente, así que && !ClientSettingsPanel.clientSettings.multipleKeybinds.getValue()
// el ajuste sólo servía para las teclas de vanilla. ) {
//
// mientras se carga la config. no se toca nada: son las teclas que el usuario ya
// tenía, y quitárselas aquí se las machacaba (y encima guardaba el -1).
//
// clientSettings puede ser null: el módulo de ajustes se construye en el
// inicializador estático de ClientSettingsPanel, y su propia tecla por defecto pasa
// por aquí antes de que el campo esté asignado
if (ModuleManager.INSTANCE != null
&& ClientSettingsPanel.clientSettings != null
&& !ConfigManager.INSTANCE.isApplying()
&& !ClientSettingsPanel.clientSettings.multipleKeybinds.getValue()) {
for (Module module : ModuleManager.INSTANCE.getModules()) for (Module module : ModuleManager.INSTANCE.getModules())
if (module.getKey() == value && value != -1) { if (module.getKey() == value && value != InputConstants.UNKNOWN.getValue()) {
module.setKey(-1); module.setKey(InputConstants.UNKNOWN.getValue());
ChatUtil.info(Component.translatable("sputnik.setting.key.reset", module.getDisplayName())); ChatUtil.info(Component.translatable("sputnik.setting.key.reset", module.getDisplayName()));
} }
} }
@@ -9,7 +9,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -120,11 +120,11 @@ public class HudEditor {
int offset = hud.arrowOffset.getIntValue(); int offset = hud.arrowOffset.getIntValue();
switch (key) { switch (key) {
case GLFW.GLFW_KEY_UP -> selected.setY(Math.max(1, selected.getY() - offset)); case InputConstants.KEY_UP -> selected.setY(Math.max(1, selected.getY() - offset));
case GLFW.GLFW_KEY_DOWN -> selected.setY(Math.min( case InputConstants.KEY_DOWN -> selected.setY(Math.min(
mc.getWindow().getGuiScaledHeight() - selected.getH() + 1, selected.getY() + offset)); mc.getWindow().getGuiScaledHeight() - selected.getH() + 1, selected.getY() + offset));
case GLFW.GLFW_KEY_LEFT -> selected.setX(Math.max(1, selected.getX() - offset)); case InputConstants.KEY_LEFT -> selected.setX(Math.max(1, selected.getX() - offset));
case GLFW.GLFW_KEY_RIGHT -> selected.setX(Math.min( case InputConstants.KEY_RIGHT -> selected.setX(Math.min(
mc.getWindow().getGuiScaledWidth() - selected.getW() + 1, selected.getX() + offset)); mc.getWindow().getGuiScaledWidth() - selected.getW() + 1, selected.getX() + offset));
} }
} }
@@ -11,7 +11,7 @@ import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.client.input.MouseButtonEvent;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import org.jspecify.annotations.NonNull; import org.jspecify.annotations.NonNull;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
public class HudEditorScreen extends Screen { public class HudEditorScreen extends Screen {
@@ -61,10 +61,10 @@ public class HudEditorScreen extends Screen {
@EventListener @EventListener
public void onKey(KeyEvent event) { public void onKey(KeyEvent event) {
if (mc.gui.screen() != INSTANCE) return; if (mc.gui.screen() != INSTANCE) return;
if (event.getAction() == GLFW.GLFW_RELEASE) return; if (event.getAction() == InputConstants.RELEASE) return;
event.cancel(); event.cancel();
if (event.getKey() == GLFW.GLFW_KEY_ESCAPE) { if (event.getKey() == InputConstants.KEY_ESCAPE) {
HudEditor.INSTANCE.saveAll(); HudEditor.INSTANCE.saveAll();
HudEditor.INSTANCE.unselect(); HudEditor.INSTANCE.unselect();
mc.gui.setScreen(null); mc.gui.setScreen(null);
@@ -12,11 +12,10 @@ import me.retucio.sputnik.module.Category;
import me.retucio.sputnik.module.Module; import me.retucio.sputnik.module.Module;
import me.retucio.sputnik.module.setting.Setting; import me.retucio.sputnik.module.setting.Setting;
import me.retucio.sputnik.module.setting.settings.ColorSetting; import me.retucio.sputnik.module.setting.settings.ColorSetting;
import me.retucio.sputnik.ui.widgets.buttons.FriendButton; import me.retucio.sputnik.ui.screen.tabs.FriendsTab;
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.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;
import me.retucio.sputnik.ui.widgets.panels.ModulePanel; import me.retucio.sputnik.ui.widgets.panels.ModulePanel;
@@ -31,7 +30,6 @@ import me.retucio.sputnik.ui.widgets.misc.ScrollBarWidget;
import me.retucio.sputnik.ui.widgets.misc.SearchBarWidget; import me.retucio.sputnik.ui.widgets.misc.SearchBarWidget;
import me.retucio.sputnik.ui.widgets.misc.TabBarWidget; import me.retucio.sputnik.ui.widgets.misc.TabBarWidget;
import me.retucio.sputnik.util.Colors; import me.retucio.sputnik.util.Colors;
import me.retucio.sputnik.ui.widgets.panels.settings.FriendSettingsPanel;
import me.retucio.sputnik.util.KeyUtil; import me.retucio.sputnik.util.KeyUtil;
import me.retucio.sputnik.util.MiscUtil; import me.retucio.sputnik.util.MiscUtil;
@@ -44,7 +42,7 @@ import net.minecraft.network.chat.Component;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NonNull; import org.jspecify.annotations.NonNull;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -69,7 +67,6 @@ public class ClickGui extends Screen {
private final List<ModulePanel> modulePanels = new ArrayList<>(); private final List<ModulePanel> modulePanels = new ArrayList<>();
private final List<SettingsPanel> settingsPanels = new ArrayList<>(); private final List<SettingsPanel> settingsPanels = new ArrayList<>();
private final ClientSettingsPanel clientSettingsPanel = new ClientSettingsPanel(620, 280, 100, 20); private final ClientSettingsPanel clientSettingsPanel = new ClientSettingsPanel(620, 280, 100, 20);
private final FriendsPanel friendsPanel = new FriendsPanel(40, 280, 100, 20);
private final ScrollBarWidget scrollBar = new ScrollBarWidget(); private final ScrollBarWidget scrollBar = new ScrollBarWidget();
private final SearchBarWidget searchBar = new SearchBarWidget(320, 10, 320, 20); private final SearchBarWidget searchBar = new SearchBarWidget(320, 10, 320, 20);
@@ -78,6 +75,7 @@ public class ClickGui extends Screen {
private final TabBarWidget tabBar = new TabBarWidget(this::onTabLeft); private final TabBarWidget tabBar = new TabBarWidget(this::onTabLeft);
private final ProfilesTab profilesTab = new ProfilesTab(); private final ProfilesTab profilesTab = new ProfilesTab();
private final MacrosTab macrosTab = new MacrosTab(); private final MacrosTab macrosTab = new MacrosTab();
private final FriendsTab friendsTab = new FriendsTab();
private static final int PLACEMENT_SEARCH_STEP = 8; private static final int PLACEMENT_SEARCH_STEP = 8;
@@ -96,9 +94,11 @@ public class ClickGui extends Screen {
public void extractRenderState(@NonNull GuiGraphicsExtractor gui, int mouseX, int mouseY, float delta) { public void extractRenderState(@NonNull GuiGraphicsExtractor gui, int mouseX, int mouseY, float delta) {
switch (tabBar.getSelected()) { switch (tabBar.getSelected()) {
case MODULES -> renderModules(gui, mouseX, mouseY, delta); case MODULES -> renderModules(gui, mouseX, mouseY, delta);
case CLIENT_SETTINGS -> renderClientSettings(gui, mouseX, mouseY, delta);
case HUD -> renderHud(gui, mouseX, mouseY); case HUD -> renderHud(gui, mouseX, mouseY);
case PROFILES -> profilesTab.render(gui, mouseX, mouseY, delta); case PROFILES -> profilesTab.render(gui, mouseX, mouseY, delta);
case MACROS -> macrosTab.render(gui, mouseX, mouseY, delta); case MACROS -> macrosTab.render(gui, mouseX, mouseY, delta);
case FRIENDS -> friendsTab.render(gui, mouseX, mouseY, delta);
} }
tabBar.render(gui, mouseX, mouseY, delta); tabBar.render(gui, mouseX, mouseY, delta);
@@ -114,6 +114,11 @@ public class ClickGui extends Screen {
HudEditor.INSTANCE.render(gui, mouseX, mouseY); HudEditor.INSTANCE.render(gui, mouseX, mouseY);
} }
private void renderClientSettings(GuiGraphicsExtractor gui, int mouseX, int mouseY, float delta) {
clientSettingsPanel.render(gui, mouseX, mouseY, delta);
clientSettingsPanel.drawTooltips(gui, mouseX, mouseY);
}
private void renderModules(@NonNull GuiGraphicsExtractor gui, int mouseX, int mouseY, float delta) { private void renderModules(@NonNull GuiGraphicsExtractor gui, int mouseX, int mouseY, float delta) {
scrollBar.setWindowHeight(mc.getWindow().getGuiScaledHeight()); scrollBar.setWindowHeight(mc.getWindow().getGuiScaledHeight());
scrollBar.setContentHeight(calculateContentHeight()); scrollBar.setContentHeight(calculateContentHeight());
@@ -126,7 +131,6 @@ public class ClickGui extends Screen {
searchBar.updatePosition(mouseX, mouseY); searchBar.updatePosition(mouseX, mouseY);
// actualizar la posición de renderizado vertical de los paneles cada tick // actualizar la posición de renderizado vertical de los paneles cada tick
friendsPanel.updateRenderY(scrollOffset);
clientSettingsPanel.updateRenderY(scrollOffset); clientSettingsPanel.updateRenderY(scrollOffset);
for (ModulePanel mp : modulePanels) { for (ModulePanel mp : modulePanels) {
mp.updateRenderY(scrollOffset); mp.updateRenderY(scrollOffset);
@@ -151,12 +155,6 @@ public class ClickGui extends Screen {
sp.drawTooltips(gui, mouseX, mouseY); sp.drawTooltips(gui, mouseX, mouseY);
} }
friendsPanel.render(gui, mouseX, mouseY, delta);
friendsPanel.updatePosition(mouseX, mouseY);
clientSettingsPanel.render(gui, mouseX, mouseY, delta);
clientSettingsPanel.updatePosition(mouseX, mouseY);
filterSearchResults(); filterSearchResults();
renderBottomGradient(gui, scrollOffset); renderBottomGradient(gui, scrollOffset);
@@ -193,14 +191,6 @@ public class ClickGui extends Screen {
bottom = Math.max(bottom, sp.getY() + sp.getH() + sp.getTotalHeight()); bottom = Math.max(bottom, sp.getY() + sp.getH() + sp.getTotalHeight());
} }
int friendsBottom = friendsPanel.getY() + friendsPanel.getH()
+ (friendsPanel.isExtended() ? friendsPanel.getTotalHeight() : 0);
bottom = Math.max(bottom, friendsBottom);
int clientBottom = clientSettingsPanel.getY() + clientSettingsPanel.getH()
+ (clientSettingsPanel.isExtended() ? clientSettingsPanel.getTotalHeight() : 0);
bottom = Math.max(bottom, clientBottom);
return bottom + 20; // padding return bottom + 20; // padding
} }
@@ -235,11 +225,7 @@ public class ClickGui extends Screen {
if (rectsOverlap(x, y, w, h, sp.getX(), sp.getY(), sp.getW(), spHeight)) return true; if (rectsOverlap(x, y, w, h, sp.getX(), sp.getY(), sp.getW(), spHeight)) return true;
} }
int friendsHeight = friendsPanel.getH() + (friendsPanel.isExtended() ? friendsPanel.getTotalHeight() : 0); return false;
if (rectsOverlap(x, y, w, h, friendsPanel.getX(), friendsPanel.getY(), friendsPanel.getW(), friendsHeight)) return true;
int clientHeight = clientSettingsPanel.getH() + (clientSettingsPanel.isExtended() ? clientSettingsPanel.getTotalHeight() : 0);
return rectsOverlap(x, y, w, h, clientSettingsPanel.getX(), clientSettingsPanel.getY(), clientSettingsPanel.getW(), clientHeight);
} }
private boolean rectsOverlap(int ax, int ay, int aw, int ah, int bx, int by, int bw, int bh) { private boolean rectsOverlap(int ax, int ay, int aw, int ah, int bx, int by, int bw, int bh) {
@@ -251,25 +237,29 @@ public class ClickGui extends Screen {
public boolean mouseClicked(MouseButtonEvent click, boolean doubled) { public boolean mouseClicked(MouseButtonEvent click, boolean doubled) {
int x = (int) click.x(); int x = (int) click.x();
int y = (int) click.y(); int y = (int) click.y();
int button = KeyUtil.toLegacyMouseButton(click.button());
if (tabBar.handleClick(x, y, click.button())) return super.mouseClicked(click, doubled); if (tabBar.handleClick(x, y, button)) return super.mouseClicked(click, doubled);
switch (tabBar.getSelected()) { switch (tabBar.getSelected()) {
case MODULES -> { case MODULES -> {
miscWidgets.forEach(w -> w.mouseClicked(x, y, click.button())); miscWidgets.forEach(w -> w.mouseClicked(x, y, button));
friendsPanel.mouseClicked(x, y, click.button());
clientSettingsPanel.mouseClicked(x, y, click.button());
for (ModulePanel mp : modulePanels.reversed()) { for (ModulePanel mp : modulePanels.reversed()) {
mp.mouseClicked(x, y, click.button()); mp.mouseClicked(x, y, button);
} }
for (SettingsPanel sp : new ArrayList<>(settingsPanels)) { for (SettingsPanel sp : new ArrayList<>(settingsPanels)) {
sp.mouseClicked(x, y, click.button()); sp.mouseClicked(x, y, button);
} }
} }
case HUD -> HudEditor.INSTANCE.mouseClicked(x, y, click.button()); case CLIENT_SETTINGS -> {
case PROFILES -> profilesTab.mouseClicked(x, y, click.button()); if (!clientSettingsPanel.mouseClickedGroupTab(x, y, button)) {
case MACROS -> macrosTab.mouseClicked(x, y, click.button()); clientSettingsPanel.mouseClicked(x, y, button);
}
}
case HUD -> HudEditor.INSTANCE.mouseClicked(x, y, button);
case PROFILES -> profilesTab.mouseClicked(x, y, button);
case MACROS -> macrosTab.mouseClicked(x, y, button);
case FRIENDS -> friendsTab.mouseClicked(x, y, button);
} }
return super.mouseClicked(click, doubled); return super.mouseClicked(click, doubled);
@@ -279,25 +269,29 @@ public class ClickGui extends Screen {
public boolean mouseReleased(MouseButtonEvent click) { public boolean mouseReleased(MouseButtonEvent click) {
int x = (int) click.x(); int x = (int) click.x();
int y = (int) click.y(); int y = (int) click.y();
int button = KeyUtil.toLegacyMouseButton(click.button());
if (tabBar.getSelected() == Tab.HUD) { if (tabBar.getSelected() == Tab.HUD) {
HudEditor.INSTANCE.mouseReleased(click.button()); HudEditor.INSTANCE.mouseReleased(button);
return super.mouseReleased(click);
}
if (tabBar.getSelected() == Tab.CLIENT_SETTINGS) {
clientSettingsPanel.mouseReleased(x, y, button);
return super.mouseReleased(click); return super.mouseReleased(click);
} }
if (tabBar.getSelected() != Tab.MODULES) return super.mouseReleased(click); if (tabBar.getSelected() != Tab.MODULES) return super.mouseReleased(click);
miscWidgets.forEach(w -> w.mouseReleased( miscWidgets.forEach(w -> w.mouseReleased(
x, y, click.button())); x, y, button));
// registrar cuándo se suelta el clic, en cada panel respectivamente // registrar cuándo se suelta el clic, en cada panel respectivamente
friendsPanel.mouseReleased(x, y, click.button());
clientSettingsPanel.mouseReleased(x, y, click.button());
for (ModulePanel mp : modulePanels.reversed()) { for (ModulePanel mp : modulePanels.reversed()) {
mp.mouseReleased(x, y, click.button()); mp.mouseReleased(x, y, button);
} }
for (SettingsPanel sp : new ArrayList<>(settingsPanels)) { for (SettingsPanel sp : new ArrayList<>(settingsPanels)) {
sp.mouseReleased(x, y, click.button()); sp.mouseReleased(x, y, button);
} }
return super.mouseReleased(click); return super.mouseReleased(click);
@@ -305,8 +299,14 @@ public class ClickGui extends Screen {
@Override @Override
public boolean mouseDragged(@NonNull MouseButtonEvent click, double deltaX, double deltaY) { public boolean mouseDragged(@NonNull MouseButtonEvent click, double deltaX, double deltaY) {
int button = KeyUtil.toLegacyMouseButton(click.button());
if (tabBar.getSelected() == Tab.HUD) { if (tabBar.getSelected() == Tab.HUD) {
HudEditor.INSTANCE.mouseDragged((int) click.x(), (int) click.y(), click.button()); HudEditor.INSTANCE.mouseDragged((int) click.x(), (int) click.y(), button);
return super.mouseDragged(click, deltaX, deltaY);
}
if (tabBar.getSelected() == Tab.CLIENT_SETTINGS) {
clientSettingsPanel.mouseDragged((int) click.x(), (int) click.y());
return super.mouseDragged(click, deltaX, deltaY); return super.mouseDragged(click, deltaX, deltaY);
} }
@@ -330,11 +330,13 @@ public class ClickGui extends Screen {
switch (tabBar.getSelected()) { switch (tabBar.getSelected()) {
case MODULES -> searchBar.onKey(event.getKey(), event.getAction()); case MODULES -> searchBar.onKey(event.getKey(), event.getAction());
case CLIENT_SETTINGS -> clientSettingsPanel.onKey(event.getKey(), event.getAction());
case HUD -> { case HUD -> {
if (event.getAction() != GLFW.GLFW_RELEASE) HudEditor.INSTANCE.onKey(event.getKey()); if (event.getAction() != InputConstants.RELEASE) HudEditor.INSTANCE.onKey(event.getKey());
} }
case PROFILES -> profilesTab.onKey(event.getKey(), event.getAction()); case PROFILES -> profilesTab.onKey(event.getKey(), event.getAction());
case MACROS -> macrosTab.onKey(event.getKey(), event.getAction()); case MACROS -> macrosTab.onKey(event.getKey(), event.getAction());
case FRIENDS -> friendsTab.onKey(event.getKey(), event.getAction());
} }
} }
@@ -348,7 +350,7 @@ public class ClickGui extends Screen {
@EventListener @EventListener
public void onMouseMiddleButton(MouseClickEvent event) { public void onMouseMiddleButton(MouseClickEvent event) {
// mover todos los paneles a un punto visible al presionar shift + la rueda del ratón // mover todos los paneles a un punto visible al presionar shift + la rueda del ratón
if (Sputnik.mc.gui.screen() != this || event.getButton() != 2 || !KeyUtil.isKeyDown(GLFW.GLFW_KEY_LEFT_SHIFT)) return; if (Sputnik.mc.gui.screen() != this || event.getButton() != 2 || !KeyUtil.isKeyDown(InputConstants.KEY_LSHIFT)) return;
int h = Sputnik.mc.getWindow().getGuiScaledHeight(); int h = Sputnik.mc.getWindow().getGuiScaledHeight();
int minY = Math.min(modulePanels.stream().mapToInt(Panel::getY).min().getAsInt(), settingsPanels.stream().mapToInt(Panel::getY).min().getAsInt()); int minY = Math.min(modulePanels.stream().mapToInt(Panel::getY).min().getAsInt(), settingsPanels.stream().mapToInt(Panel::getY).min().getAsInt());
@@ -358,7 +360,6 @@ public class ClickGui extends Screen {
if (correction != 0) { if (correction != 0) {
modulePanels.forEach(mp -> mp.setY(mp.getY() + correction)); modulePanels.forEach(mp -> mp.setY(mp.getY() + correction));
settingsPanels.forEach(sp -> sp.setY(sp.getY() + correction)); settingsPanels.forEach(sp -> sp.setY(sp.getY() + correction));
friendsPanel.setY(friendsPanel.getY() + correction);
clientSettingsPanel.setY(clientSettingsPanel.getY() + correction); clientSettingsPanel.setY(clientSettingsPanel.getY() + correction);
} }
} }
@@ -427,26 +428,6 @@ public class ClickGui extends Screen {
} }
} }
for (Button b : friendsPanel.getButtons()) {
if (!(b instanceof FriendButton fb)) continue;
Friend friend = fb.getFriend();
if (searchInput.isEmpty()) {
friend.setSearchMatch(true);
continue;
}
String name = MiscUtil.removeAccentMarks(friend.getName());
String uuid = MiscUtil.removeAccentMarks(friend.getUuid().toString());
if (!clientSettings.matchCase.getValue()) {
name = name.toLowerCase();
uuid = uuid.toLowerCase();
}
friend.setSearchMatch(name.contains(searchInput) || uuid.contains(searchInput));
}
for (Button b : clientSettingsPanel.getButtons()) { for (Button b : clientSettingsPanel.getButtons()) {
if (!(b instanceof SettingButton<?> sb)) continue; if (!(b instanceof SettingButton<?> sb)) continue;
Setting<?> setting = sb.getSetting(); Setting<?> setting = sb.getSetting();
@@ -550,33 +531,6 @@ public class ClickGui extends Screen {
} }
} }
public boolean isFriendSettingsPanelOpen(Friend friend) {
for (SettingsPanel sp : getSettingsPanels()) {
if (sp instanceof FriendSettingsPanel fsp) {
if (fsp.getFriend().getUuid().equals(friend.getUuid())) return true;
}
}
return false;
}
public void openFriendSettingsPanel(Friend friend, int x, int y) {
FriendSettingsPanel panel = new FriendSettingsPanel(friend, x + 80, y + 5, 153, 20);
if (isFriendSettingsPanelOpen(friend)) {
closeFriendSettingsPanel(friend);
return;
}
settingsPanels.add(panel);
}
public void closeFriendSettingsPanel(Friend friend) {
for (SettingsPanel sp : getSettingsPanels()) {
if (sp instanceof FriendSettingsPanel fsp && fsp.getFriend().getUuid().equals(friend.getUuid())) {
settingsPanels.remove(fsp);
break;
}
}
}
public void refreshListButtons() { public void refreshListButtons() {
for (SettingsPanel panel : settingsPanels) for (SettingsPanel panel : settingsPanels)
for (Button button : panel.getButtons()) for (Button button : panel.getButtons())
@@ -597,7 +551,8 @@ public class ClickGui extends Screen {
// lo miran Sputnik#onInput y el editor del hud para no tratar las teclas que se están // lo miran Sputnik#onInput y el editor del hud para no tratar las teclas que se están
// escribiendo como atajos de módulos // escribiendo como atajos de módulos
public boolean isCapturingInput() { public boolean isCapturingInput() {
return searchBar.isFocused() || profilesTab.isCapturingInput() || macrosTab.isCapturingInput(); return searchBar.isFocused() || profilesTab.isCapturingInput()
|| macrosTab.isCapturingInput() || friendsTab.isCapturingInput();
} }
public boolean isOnHudTab() { public boolean isOnHudTab() {
@@ -650,7 +605,6 @@ public class ClickGui extends Screen {
public List<ModulePanel> getModulePanels() { return modulePanels; } public List<ModulePanel> getModulePanels() { return modulePanels; }
public List<SettingsPanel> getSettingsPanels() { return settingsPanels; } public List<SettingsPanel> getSettingsPanels() { return settingsPanels; }
public ClientSettingsPanel getClientSettingsPanel() { return clientSettingsPanel; } public ClientSettingsPanel getClientSettingsPanel() { return clientSettingsPanel; }
public FriendsPanel getFriendsPanel() { return friendsPanel; }
public SearchBarWidget getSearchBar() { return searchBar; } public SearchBarWidget getSearchBar() { return searchBar; }
public TabBarWidget getTabBar() { return tabBar; } public TabBarWidget getTabBar() { return tabBar; }
public ScrollBarWidget getScrollBar() { return scrollBar; } public ScrollBarWidget getScrollBar() { return scrollBar; }
@@ -40,7 +40,7 @@ public class PreviewScreen extends Screen {
super(Component.translatable("sputnik.ui.preview.shulker")); super(Component.translatable("sputnik.ui.preview.shulker"));
this.color = ShulkerPeek.SHULKER_COLORS.get(shulker.getItem()); this.color = ShulkerPeek.SHULKER_COLORS.get(shulker.getItem());
this.title = shulker.getHoverName(); this.title = shulker.getHoverName();
this.inventory = shulker.get(DataComponents.CONTAINER).allItemsCopyStream().toList(); this.inventory = shulker.get(DataComponents.CONTAINER).nonEmptyItemCopyStream().toList();
this.parent = parent; this.parent = parent;
this.type = PreviewType.SHULKER; this.type = PreviewType.SHULKER;
} }
@@ -6,9 +6,11 @@ import me.retucio.sputnik.util.I18nUtil;
public enum Tab { public enum Tab {
MODULES("módulos"), MODULES("módulos"),
CLIENT_SETTINGS("ajustes"),
HUD("hud"), HUD("hud"),
PROFILES("perfiles"), PROFILES("perfiles"),
MACROS("macros"); MACROS("macros"),
FRIENDS("amigos");
private final String name; private final String name;
@@ -0,0 +1,101 @@
package me.retucio.sputnik.ui.screen.tabs;
import me.retucio.sputnik.friend.Friend;
import me.retucio.sputnik.friend.FriendManager;
import me.retucio.sputnik.ui.hud.HudRenderer;
import me.retucio.sputnik.ui.widgets.misc.FriendWidget;
import me.retucio.sputnik.util.Colors;
import me.retucio.sputnik.util.I18nUtil;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.network.chat.Component;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class FriendsTab {
private static final Minecraft mc = Minecraft.getInstance();
private static final int COLUMNS = 3;
private static final int CARD_HEIGHT = 60;
private static final int MARGIN = 6;
private static final int TOP = 40;
// uno por amigo, persistente entre frames para no perder el foco del campo de apodo mientras se edita
private final Map<UUID, FriendWidget> widgets = new LinkedHashMap<>();
public void render(GuiGraphicsExtractor gui, int mouseX, int mouseY, float delta) {
List<Friend> friends = FriendManager.INSTANCE.getFriends();
syncWidgets(friends);
int screenWidth = mc.getWindow().getGuiScaledWidth();
int cardWidth = screenWidth / COLUMNS;
gui.centeredText(mc.font, Component.translatable("sputnik.ui.friends.title"),
screenWidth / 2, TOP - 14, Colors.mainColor.getRGB());
if (friends.isEmpty()) {
gui.centeredText(mc.font, Component.translatable("sputnik.ui.friends.empty"),
screenWidth / 2, TOP + 20, Colors.instructionsTextColor.getRGB());
return;
}
int col = 0;
int row = 0;
for (Friend friend : friends) {
FriendWidget widget = widgets.get(friend.getUuid());
int cx = col * cardWidth + MARGIN;
int cy = TOP + row * (CARD_HEIGHT + MARGIN);
int cw = cardWidth - MARGIN * 2;
widget.updateBounds(cx, cy, cw, CARD_HEIGHT);
widget.render(gui, mouseX, mouseY, delta);
col++;
if (col >= COLUMNS) {
col = 0;
row++;
}
}
}
// añade widgets para amigos nuevos y elimina los de quienes ya no lo son
private void syncWidgets(List<Friend> friends) {
widgets.keySet().removeIf(uuid -> friends.stream().noneMatch(f -> f.getUuid().equals(uuid)));
for (Friend friend : friends) {
widgets.computeIfAbsent(friend.getUuid(),
uuid -> new FriendWidget(friend, 0, 0, 0, CARD_HEIGHT, this::remove));
}
}
private void remove(Friend friend) {
FriendManager.INSTANCE.remove(friend);
HudRenderer.INSTANCE.pushNotification(
I18nUtil.orElse("sputnik.ui.friends.title", "amigos"),
I18nUtil.orElse("sputnik.ui.friends.removed", "sputnik.ui.friends.removed", friend.getName()));
}
public void mouseClicked(int mouseX, int mouseY, int button) {
for (FriendWidget widget : widgets.values()) {
if (widget.isHovered(mouseX, mouseY) || widget.isCapturingInput()) {
widget.mouseClicked(mouseX, mouseY, button);
}
}
}
public void onKey(int key, int action) {
for (FriendWidget widget : widgets.values()) {
if (widget.isCapturingInput()) widget.onKey(key, action);
}
}
public boolean isCapturingInput() {
return widgets.values().stream().anyMatch(FriendWidget::isCapturingInput);
}
}
@@ -10,7 +10,7 @@ import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.util.FormattedCharSequence; import net.minecraft.util.FormattedCharSequence;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -27,7 +27,7 @@ public class MacrosTab {
private static final int TOP = 46; private static final int TOP = 46;
private final TextFieldWidget nameField = new TextFieldWidget( private final TextFieldWidget nameField = new TextFieldWidget(
() -> "sputnik.ui.macros.nameplaceholder", 0, 0, LIST_WIDTH - 24, ROW_HEIGHT) () -> "sputnik.ui.macros.nameplaceholder", 0, 0, LIST_WIDTH - 44, ROW_HEIGHT)
.maxLength(32) .maxLength(32)
.onSubmit(this::create); .onSubmit(this::create);
@@ -52,10 +52,8 @@ public class MacrosTab {
nameField.setY(TOP); nameField.setY(TOP);
nameField.render(gui, mouseX, mouseY, delta); nameField.render(gui, mouseX, mouseY, delta);
int addX = listX + LIST_WIDTH - 20; drawAddButton(gui, listX + LIST_WIDTH - 40, "C", isAddChatHovered(mouseX, mouseY));
gui.fill(addX, TOP, addX + 20, TOP + ROW_HEIGHT, drawAddButton(gui, listX + LIST_WIDTH - 20, "K", isAddKeybindHovered(mouseX, mouseY));
isAddHovered(mouseX, mouseY) ? Colors.buttonColor.brighter().getRGB() : Colors.buttonColor.getRGB());
gui.text(mc.font, "+", addX + 8, TOP + ROW_HEIGHT / 2 - mc.font.lineHeight / 2, -1, true);
drawHint(gui, Component.translatable("sputnik.ui.macros.instructions"), listX, LIST_WIDTH); drawHint(gui, Component.translatable("sputnik.ui.macros.instructions"), listX, LIST_WIDTH);
@@ -85,12 +83,13 @@ public class MacrosTab {
renderLines(gui, mouseX, mouseY, delta); renderLines(gui, mouseX, mouseY, delta);
} }
// el panel de líneas solo aplica a macros de chat; las Keybind no tienen líneas que editar
private void renderLines(GuiGraphicsExtractor gui, int mouseX, int mouseY, float delta) { private void renderLines(GuiGraphicsExtractor gui, int mouseX, int mouseY, float delta) {
if (selected == null) return; if (!(selected instanceof Macro.Chat chat)) return;
int x = linesX(); int x = linesX();
gui.text(mc.font, selected.getName(), x, TOP - 14, Colors.mainColor.getRGB(), true); gui.text(mc.font, chat.getName(), x, TOP - 14, Colors.mainColor.getRGB(), true);
lineField.setX(x); lineField.setX(x);
lineField.setY(TOP); lineField.setY(TOP);
@@ -104,7 +103,7 @@ public class MacrosTab {
drawHint(gui, Component.translatable("sputnik.ui.macros.lineinstructions"), x, LINES_WIDTH); drawHint(gui, Component.translatable("sputnik.ui.macros.lineinstructions"), x, LINES_WIDTH);
int rowY = listTop(); int rowY = listTop();
for (String line : selected.getLines()) { for (String line : chat.getLines()) {
boolean hovered = isHovered(x, rowY, LINES_WIDTH, mouseX, mouseY); boolean hovered = isHovered(x, rowY, LINES_WIDTH, mouseX, mouseY);
gui.fill(x, rowY, x + LINES_WIDTH, rowY + ROW_HEIGHT, gui.fill(x, rowY, x + LINES_WIDTH, rowY + ROW_HEIGHT,
hovered ? Colors.buttonColor.brighter().getRGB() : Colors.buttonColor.getRGB()); hovered ? Colors.buttonColor.brighter().getRGB() : Colors.buttonColor.getRGB());
@@ -124,7 +123,13 @@ public class MacrosTab {
return; return;
} }
if (button == 0 && selected != null && isAddLineHovered(mouseX, mouseY)) { if (button == 0 && isAddKeybindHovered(mouseX, mouseY)) {
createKeybind(nameField.getText().trim());
nameField.clear();
return;
}
if (button == 0 && selected instanceof Macro.Chat && isAddLineHovered(mouseX, mouseY)) {
addLine(lineField.getText().trim()); addLine(lineField.getText().trim());
lineField.clear(); lineField.clear();
return; return;
@@ -139,13 +144,13 @@ public class MacrosTab {
rowY += ROW_HEIGHT + 2; rowY += ROW_HEIGHT + 2;
} }
if (selected == null) return; if (!(selected instanceof Macro.Chat chat)) return;
rowY = listTop(); rowY = listTop();
for (String line : new ArrayList<>(selected.getLines())) { for (String line : new ArrayList<>(chat.getLines())) {
if (isHovered(linesX(), rowY, LINES_WIDTH, mouseX, mouseY)) { if (isHovered(linesX(), rowY, LINES_WIDTH, mouseX, mouseY)) {
if (button == 1 && KeyUtil.isShiftDown()) { if (button == 1 && KeyUtil.isShiftDown()) {
selected.getLines().remove(line); chat.getLines().remove(line);
MacroManager.INSTANCE.save(); MacroManager.INSTANCE.save();
} }
return; return;
@@ -172,19 +177,25 @@ public class MacrosTab {
private void create(String name) { private void create(String name) {
if (name.isEmpty()) return; if (name.isEmpty()) return;
Macro macro = new Macro(name); Macro macro = new Macro.Chat(name);
if (MacroManager.INSTANCE.add(macro)) selected = macro;
}
private void createKeybind(String name) {
if (name.isEmpty()) return;
Macro macro = new Macro.Keybind(name);
if (MacroManager.INSTANCE.add(macro)) selected = macro; if (MacroManager.INSTANCE.add(macro)) selected = macro;
} }
private void addLine(String line) { private void addLine(String line) {
if (selected == null || line.isEmpty()) return; if (!(selected instanceof Macro.Chat chat) || line.isEmpty()) return;
selected.getLines().add(line); chat.getLines().add(line);
MacroManager.INSTANCE.save(); MacroManager.INSTANCE.save();
} }
public void onKey(int key, int action) { public void onKey(int key, int action) {
if (listening != null && action != GLFW.GLFW_RELEASE) { if (listening != null && action != InputConstants.RELEASE) {
listening.setKey(key == GLFW.GLFW_KEY_ESCAPE ? GLFW.GLFW_KEY_UNKNOWN : key); listening.setKey(key == InputConstants.KEY_ESCAPE ? InputConstants.UNKNOWN.getValue() : key);
listening = null; listening = null;
MacroManager.INSTANCE.save(); MacroManager.INSTANCE.save();
return; return;
@@ -236,10 +247,26 @@ public class MacrosTab {
} }
private static boolean isAddHovered(int mouseX, int mouseY) { private static boolean isAddHovered(int mouseX, int mouseY) {
return isAddChatHovered(mouseX, mouseY);
}
private static boolean isAddChatHovered(int mouseX, int mouseY) {
int addX = listX() + LIST_WIDTH - 40;
return mouseX >= addX && mouseX < addX + 20 && mouseY >= TOP && mouseY < TOP + ROW_HEIGHT;
}
private static boolean isAddKeybindHovered(int mouseX, int mouseY) {
int addX = listX() + LIST_WIDTH - 20; int addX = listX() + LIST_WIDTH - 20;
return mouseX >= addX && mouseX < addX + 20 && mouseY >= TOP && mouseY < TOP + ROW_HEIGHT; return mouseX >= addX && mouseX < addX + 20 && mouseY >= TOP && mouseY < TOP + ROW_HEIGHT;
} }
private static void drawAddButton(GuiGraphicsExtractor gui, int x, String label, boolean hovered) {
gui.fill(x, TOP, x + 20, TOP + ROW_HEIGHT,
hovered ? Colors.buttonColor.brighter().getRGB() : Colors.buttonColor.getRGB());
gui.text(mc.font, label, x + (20 - mc.font.width(label)) / 2,
TOP + ROW_HEIGHT / 2 - mc.font.lineHeight / 2, -1, true);
}
private static boolean isAddLineHovered(int mouseX, int mouseY) { private static boolean isAddLineHovered(int mouseX, int mouseY) {
int addX = linesX() + LINES_WIDTH - 20; int addX = linesX() + LINES_WIDTH - 20;
return mouseX >= addX && mouseX < addX + 20 && mouseY >= TOP && mouseY < TOP + ROW_HEIGHT; return mouseX >= addX && mouseX < addX + 20 && mouseY >= TOP && mouseY < TOP + ROW_HEIGHT;
@@ -1,75 +0,0 @@
package me.retucio.sputnik.ui.widgets.buttons;
import me.retucio.sputnik.friend.Friend;
import me.retucio.sputnik.module.Module;
import me.retucio.sputnik.ui.screen.ClickGui;
import me.retucio.sputnik.ui.widgets.panels.FriendsPanel;
import me.retucio.sputnik.ui.widgets.panels.ModulePanel;
import me.retucio.sputnik.ui.widgets.Button;
import me.retucio.sputnik.util.Colors;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.network.chat.Component;
// clase para el botón para cada módulo
public class FriendButton extends Button {
private final Friend friend;
public final int height = 18;
public FriendButton(Friend friend, FriendsPanel parent, int offset) {
super(parent, offset);
this.friend = friend;
}
@Override
public void render(GuiGraphicsExtractor gui, int mouseX, int mouseY, float delta) {
gui.fill( // dibujar el contorno del botón
parent.getX() + 2, parent.getRenderY() + offset + 3,
parent.getX() + parent.getW() - 2 , parent.getRenderY() + height + offset,
determineColor(mouseX, mouseY));
gui.text( // dibujar el nombre del amigo
mc.font, friend.getName(),
parent.getX() + 5, parent.getRenderY() + offset + (height / 2) - (mc.font.lineHeight / 2) + 2,
-1, true);
// dibujar "tooltips" (cajas de texto) al pasar el puntero encima del botón, para mostrar su UUID
if (isHovered(mouseX, mouseY)) {
drawTooltip(gui, mouseX, mouseY);
}
}
@Override
public void drawTooltip(GuiGraphicsExtractor gui, int mouseX, int mouseY) {
gui.setTooltipForNextFrame(Component.literal(friend.getUuid().toString()), mouseX, mouseY + 20);
}
@Override
public void mouseClicked(int mouseX, int mouseY, int button) {
if (isHovered(mouseX, mouseY) && ClickGui.INSTANCE.trySelect(this)) {
ClickGui.INSTANCE.openFriendSettingsPanel(friend, mouseX, mouseY);
}
}
// verifica si el puntero del ratón se encuentra sobre el botón
@Override
public boolean isHovered(int mouseX, int mouseY) {
return ClickGui.INSTANCE.canSelect(this)
&& mouseX > parent.getX()
&& mouseX < parent.getX() + parent.getW()
&& mouseY > parent.getRenderY() + offset
&& mouseY < parent.getRenderY() + height + offset;
}
public int determineColor(double mouseX, double mouseY) {
// determina el color del botón, dependiendo de si está el puntero encima
return isHovered((int) mouseX, (int) mouseY)
? Colors.buttonColor.brighter().getRGB()
: Colors.buttonColor.getRGB();
}
public Friend getFriend() {
return friend;
}
}
@@ -12,9 +12,11 @@ import net.minecraft.ChatFormatting;
import net.minecraft.client.KeyMapping; import net.minecraft.client.KeyMapping;
import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.input.KeyEvent; import net.minecraft.client.input.KeyEvent;
import net.minecraft.client.input.MouseButtonEvent;
import net.minecraft.client.input.MouseButtonInfo;
import net.minecraft.client.resources.language.I18n; import net.minecraft.client.resources.language.I18n;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -49,12 +51,13 @@ public class BindButton extends SettingButton<KeySetting> {
if (hovered && ClickGui.INSTANCE.trySelect(this)) { if (hovered && ClickGui.INSTANCE.trySelect(this)) {
if (listening) { if (listening) {
int key = KeyUtil.fromLegacyGlfwKey(button);
List<KeyMapping> keys = new ArrayList<>(List.of(mc.options.keyMappings)); List<KeyMapping> keys = new ArrayList<>(List.of(mc.options.keyMappings));
keys.removeAll(List.of(mc.options.debugKeys)); keys.removeAll(List.of(mc.options.debugKeys));
boolean allowMultiple = ClientSettingsPanel.clientSettings.multipleKeybinds.getValue(); boolean allowMultiple = ClientSettingsPanel.clientSettings.multipleKeybinds.getValue();
for (KeyMapping bind : keys) { for (KeyMapping bind : keys) {
if (bind.matches(new KeyEvent(button, 0, 0))) { if (bind.matches(new KeyEvent(key, 0, 0))) {
if (!allowMultiple) { if (!allowMultiple) {
ChatUtil.warn(Component.translatable("sputnik.commands.bind.keytaken", ChatUtil.warn(Component.translatable("sputnik.commands.bind.keytaken",
ChatFormatting.GREEN + "\"" + I18n.get(bind.getName()) + "\"")); ChatFormatting.GREEN + "\"" + I18n.get(bind.getName()) + "\""));
@@ -64,7 +67,7 @@ public class BindButton extends SettingButton<KeySetting> {
} }
} }
setting.setValue(button); setting.setValue(key);
listening = false; listening = false;
} else { } else {
if (button == 0) { if (button == 0) {
@@ -81,10 +84,10 @@ public class BindButton extends SettingButton<KeySetting> {
} }
public void onKey(int key, int action) { public void onKey(int key, int action) {
if (!listening || action != GLFW.GLFW_PRESS) return; if (!listening || action != InputConstants.PRESS) return;
if (key == GLFW.GLFW_KEY_ESCAPE) { if (key == InputConstants.KEY_ESCAPE) {
setting.setValue(GLFW.GLFW_KEY_UNKNOWN); setting.setValue(InputConstants.UNKNOWN.getValue());
} else { } else {
List<KeyMapping> keys = new ArrayList<>(List.of(mc.options.keyMappings)); List<KeyMapping> keys = new ArrayList<>(List.of(mc.options.keyMappings));
keys.removeAll(List.of(mc.options.debugKeys)); keys.removeAll(List.of(mc.options.debugKeys));
@@ -106,7 +109,28 @@ public class BindButton extends SettingButton<KeySetting> {
listening = false; listening = false;
} }
public void onMouse(int button, int action) {
if (!listening || action != InputConstants.PRESS) return;
List<KeyMapping> keys = new ArrayList<>(List.of(mc.options.keyMappings));
keys.removeAll(List.of(mc.options.debugKeys));
boolean allowMultiple = ClientSettingsPanel.clientSettings.multipleKeybinds.getValue();
MouseButtonEvent mouseEvent = new MouseButtonEvent(0, 0, new MouseButtonInfo(button, 0));
for (KeyMapping bind : keys) {
if (bind.matchesMouse(mouseEvent) && !allowMultiple) {
ChatUtil.warn(Component.translatable("sputnik.commands.bind.keytaken",
ChatFormatting.GREEN + "\"" + I18n.get(bind.getName()) + "\""));
listening = false;
return;
}
}
setting.setValue(KeyUtil.encodeMouseButton(button));
listening = false;
}
public boolean isFocused() { public boolean isFocused() {
return listening; return listening;
} }
} }
@@ -13,8 +13,9 @@ import net.minecraft.client.resources.language.I18n;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import org.lwjgl.util.tinyfd.TinyFileDialogs; import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.*; import java.awt.*;
import java.nio.file.Path; import java.nio.file.Path;
@@ -75,23 +76,23 @@ public class FileButton extends SettingButton<FileSetting> {
@Override @Override
public void onKey(int key, int action) { public void onKey(int key, int action) {
if (!typing || action == GLFW.GLFW_RELEASE) return; if (!typing || action == InputConstants.RELEASE) return;
// pegar con ctrl + v // pegar con ctrl + v
if (key == GLFW.GLFW_KEY_V && KeyUtil.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL)) { if (key == InputConstants.KEY_V && KeyUtil.isKeyDown(InputConstants.KEY_LCONTROL)) {
paste(); paste();
return; return;
} }
switch (key) { // casos para teclas especiales como enter, escape o borrar switch (key) { // casos para teclas especiales como enter, escape o borrar
case GLFW.GLFW_KEY_ENTER -> { case InputConstants.KEY_RETURN -> {
setting.setValue(buffer.toString()); setting.setValue(buffer.toString());
typing = false; typing = false;
} case GLFW.GLFW_KEY_BACKSPACE -> { } case InputConstants.KEY_BACKSPACE -> {
onBackspace(); onBackspace();
} case GLFW.GLFW_KEY_ESCAPE -> { } case InputConstants.KEY_ESCAPE -> {
typing = false; typing = false;
} case GLFW.GLFW_KEY_SPACE -> { } case InputConstants.KEY_SPACE -> {
charTyped(' '); charTyped(' ');
} default -> { } default -> {
String c = KeyUtil.getKeyName(key); String c = KeyUtil.getKeyName(key);
@@ -139,14 +140,14 @@ public class FileButton extends SettingButton<FileSetting> {
@Nullable @Nullable
public Path pickFile() { public Path pickFile() {
String result = TinyFileDialogs.tinyfd_openFileDialog( FileDialog dialog = new FileDialog((Frame) null,
I18n.get("sputnik.filesetting.choose"), I18n.get("sputnik.filesetting.choose"), FileDialog.LOAD);
setting.isDirectory() String initial = setting.isDirectory()
? setting.getValue() ? setting.getValue()
: setting.getPath().getParent().toString(), : setting.getPath().getParent().toString();
null, dialog.setDirectory(initial);
I18n.get("sputnik.filesetting.supportedfiles"), dialog.setVisible(true);
false); String file = dialog.getFile();
return result == null ? null : Path.of(result); return file == null ? null : Path.of(dialog.getDirectory(), file);
} }
} }
@@ -8,7 +8,7 @@ import me.retucio.sputnik.ui.widgets.panels.settings.ClientSettingsPanel;
import me.retucio.sputnik.util.Colors; import me.retucio.sputnik.util.Colors;
import me.retucio.sputnik.util.KeyUtil; import me.retucio.sputnik.util.KeyUtil;
import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.GuiGraphicsExtractor;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.awt.*; import java.awt.*;
import java.text.DecimalFormat; import java.text.DecimalFormat;
@@ -60,7 +60,7 @@ public class SliderButton extends SettingButton<NumberSetting> {
public void onKey(int key, int action) { public void onKey(int key, int action) {
// de no ser de esto, si se cierra la interfaz sin haber soltado el ratón mientras se arrastraba el valor, // de no ser de esto, si se cierra la interfaz sin haber soltado el ratón mientras se arrastraba el valor,
// al reabrir la interfaz se seguía arrastrando, aun habiendo soltado ya el clic // al reabrir la interfaz se seguía arrastrando, aun habiendo soltado ya el clic
if (key == GLFW.GLFW_KEY_ESCAPE if (key == InputConstants.KEY_ESCAPE
|| key == ClientSettingsPanel.clientSettings.getKey()) || key == ClientSettingsPanel.clientSettings.getKey())
dragging = false; dragging = false;
} }
@@ -8,7 +8,7 @@ import me.retucio.sputnik.util.Colors;
import me.retucio.sputnik.util.KeyUtil; import me.retucio.sputnik.util.KeyUtil;
import me.retucio.sputnik.util.MiscUtil; import me.retucio.sputnik.util.MiscUtil;
import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.GuiGraphicsExtractor;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
// botón para los ajustes que requieran introducir texto // botón para los ajustes que requieran introducir texto
@@ -55,23 +55,23 @@ public class TextButton extends SettingButton<StringSetting> {
@Override @Override
public void onKey(int key, int action) { public void onKey(int key, int action) {
if (!typing || action == GLFW.GLFW_RELEASE) return; if (!typing || action == InputConstants.RELEASE) return;
// pegar con ctrl + v // pegar con ctrl + v
if (key == GLFW.GLFW_KEY_V && KeyUtil.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL)) { if (key == InputConstants.KEY_V && KeyUtil.isKeyDown(InputConstants.KEY_LCONTROL)) {
paste(); paste();
return; return;
} }
switch (key) { // casos para teclas especiales como enter, escape o borrar switch (key) { // casos para teclas especiales como enter, escape o borrar
case GLFW.GLFW_KEY_ENTER -> { case InputConstants.KEY_RETURN -> {
setting.setValue(buffer.toString()); setting.setValue(buffer.toString());
typing = false; typing = false;
} case GLFW.GLFW_KEY_BACKSPACE -> { } case InputConstants.KEY_BACKSPACE -> {
onBackspace(); onBackspace();
} case GLFW.GLFW_KEY_ESCAPE -> { } case InputConstants.KEY_ESCAPE -> {
typing = false; typing = false;
} case GLFW.GLFW_KEY_SPACE -> { } case InputConstants.KEY_SPACE -> {
charTyped(' '); charTyped(' ');
} default -> { } default -> {
String c = KeyUtil.getKeyName(key); String c = KeyUtil.getKeyName(key);
@@ -0,0 +1,156 @@
package me.retucio.sputnik.ui.widgets.misc;
import me.retucio.sputnik.friend.Friend;
import me.retucio.sputnik.friend.FriendManager;
import me.retucio.sputnik.ui.widgets.Widget;
import me.retucio.sputnik.util.Colors;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.components.PlayerFaceExtractor;
import net.minecraft.client.multiplayer.PlayerInfo;
import net.minecraft.network.chat.Component;
import java.awt.Color;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.function.Consumer;
public class FriendWidget extends Widget {
private static final int PADDING = 6;
private static final int HEAD_SIZE = 28;
private static final int REMOVE_SIZE = 14;
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd/MM/yyyy");
private final Friend friend;
private final Consumer<Friend> onRemove;
private final TextFieldWidget nickField;
public FriendWidget(Friend friend, int x, int y, int w, int h, Consumer<Friend> onRemove) {
super(x, y, w, h);
this.friend = friend;
this.onRemove = onRemove;
this.nickField = new TextFieldWidget(() -> "sputnik.ui.friends.nickplaceholder", 0, 0, 0, 14)
.maxLength(32)
.onSubmit(nick -> FriendManager.INSTANCE.rename(friend, nick));
}
// recalcula la posición/tamaño cada frame, para que la rejilla se adapte al ancho de pantalla
public void updateBounds(int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
@Override
public void render(GuiGraphicsExtractor gui, int mouseX, int mouseY, float delta) {
boolean hovered = isHovered(mouseX, mouseY);
gui.fill(x, y, x + w, y + h, hovered ? Colors.buttonColor.brighter().getRGB() : Colors.buttonColor.getRGB());
int headX = x + PADDING;
int headY = y + (h - HEAD_SIZE) / 2;
drawHead(gui, headX, headY);
int textX = headX + HEAD_SIZE + 8;
int textW = x + w - REMOVE_SIZE - 10 - textX;
gui.text(mc.font, friend.getName(), textX, y + 6, -1, true);
int nickY = y + 6 + mc.font.lineHeight + 2;
if (nickField.isFocused()) {
nickField.setX(textX);
nickField.setY(nickY);
nickField.setW(textW);
nickField.render(gui, mouseX, mouseY, delta);
} else {
gui.text(mc.font, friend.getDisplayName(), textX, nickY, Colors.mainColor.getRGB(), true);
}
String date = DATE_FORMAT.format(new Date(friend.getBefriendedAt()));
gui.text(mc.font, Component.translatable("sputnik.ui.friends.befriendedon", date),
textX, y + h - mc.font.lineHeight - 5, Colors.instructionsTextColor.getRGB(), true
);
String uuid = friend.getUuid().toString();
gui.text(mc.font, Component.translatable("sputnik.ui.friends.uuid", uuid),
textX, y + 24 + mc.font.lineHeight, Colors.instructionsTextColor.getRGB(), true
);
drawRemoveButton(gui, mouseX, mouseY);
}
private void drawHead(GuiGraphicsExtractor gui, int hx, int hy) {
PlayerInfo info = friend.getPlayerInfo();
if (info != null) {
PlayerFaceExtractor.extractRenderState(gui, info.getSkin(), hx, hy, HEAD_SIZE, -1);
} else {
// sin conexión al jugador (offline / no en el mismo server): placeholder gris
gui.fill(hx, hy, hx + HEAD_SIZE, hy + HEAD_SIZE, Colors.panelBgColor.getRGB());
}
}
private void drawRemoveButton(GuiGraphicsExtractor gui, int mouseX, int mouseY) {
int rx = x + w - REMOVE_SIZE - 5;
int ry = y + 5;
boolean hovered = isRemoveHovered(mouseX, mouseY);
gui.fill(rx, ry, rx + REMOVE_SIZE, ry + REMOVE_SIZE,
hovered ? new Color(200, 60, 60).brighter().getRGB() : new Color(150, 40, 40).getRGB());
gui.text(mc.font, "x", rx + REMOVE_SIZE / 2 - 2, ry + REMOVE_SIZE / 2 - mc.font.lineHeight / 2, -1, true);
}
@Override
public void mouseClicked(int mouseX, int mouseY, int button) {
if (button == 0 && isRemoveHovered(mouseX, mouseY)) {
onRemove.accept(friend);
return;
}
if (nickField.isFocused()) {
nickField.mouseClicked(mouseX, mouseY, button);
return;
}
if (button == 0 && isNickHovered(mouseX, mouseY)) {
nickField.setText(friend.getDisplayName());
nickField.setFocused(true);
}
}
@Override
public void mouseReleased(int mouseX, int mouseY, int button) {
nickField.mouseReleased(mouseX, mouseY, button);
}
public void onKey(int key, int action) {
if (nickField.isFocused()) nickField.onKey(key, action);
}
public boolean isCapturingInput() {
return nickField.isFocused();
}
private boolean isNickHovered(int mouseX, int mouseY) {
int textX = x + PADDING + HEAD_SIZE + 8;
int nickY = y + 6 + mc.font.lineHeight + 2;
return mouseX >= textX && mouseX < x + w - REMOVE_SIZE - 10
&& mouseY >= nickY && mouseY < nickY + 14;
}
private boolean isRemoveHovered(int mouseX, int mouseY) {
int rx = x + w - REMOVE_SIZE - 5;
int ry = y + 5;
return mouseX >= rx && mouseX < rx + REMOVE_SIZE && mouseY >= ry && mouseY < ry + REMOVE_SIZE;
}
@Override
public boolean isHovered(int mouseX, int mouseY) {
return mouseX >= x && mouseX < x + w && mouseY >= y && mouseY < y + h;
}
public Friend getFriend() {
return friend;
}
}
@@ -17,7 +17,7 @@ import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.awt.Color; import java.awt.Color;
import java.util.List; import java.util.List;
@@ -99,25 +99,25 @@ public class SearchBarWidget extends Widget {
@Override @Override
public void onKey(int key, int action) { public void onKey(int key, int action) {
if (!ClientSettingsPanel.clientSettings.searchBar.getValue()) return; if (!ClientSettingsPanel.clientSettings.searchBar.getValue()) return;
if (!focused || action == GLFW.GLFW_RELEASE) return; if (!focused || action == InputConstants.RELEASE) return;
if (key == GLFW.GLFW_KEY_V && KeyUtil.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL)) { if (key == InputConstants.KEY_V && KeyUtil.isKeyDown(InputConstants.KEY_LCONTROL)) {
paste(); paste();
return; return;
} }
switch (key) { switch (key) {
case GLFW.GLFW_KEY_ENTER -> focused = false; case InputConstants.KEY_RETURN -> focused = false;
case GLFW.GLFW_KEY_ESCAPE -> { case InputConstants.KEY_ESCAPE -> {
buffer.setLength(0); buffer.setLength(0);
focused = false; focused = false;
} }
case GLFW.GLFW_KEY_SPACE -> charTyped(' '); case InputConstants.KEY_SPACE -> charTyped(' ');
case GLFW.GLFW_KEY_BACKSPACE -> onBackspace(); case InputConstants.KEY_BACKSPACE -> onBackspace();
default -> { default -> {
String c = KeyUtil.getKeyName(key); String c = KeyUtil.getKeyName(key);
if (c.length() == 1) { if (c.length() == 1) {
if (KeyUtil.isKeyDown(GLFW.GLFW_KEY_LEFT_SHIFT) || KeyUtil.isKeyDown(GLFW.GLFW_KEY_RIGHT_SHIFT)) if (KeyUtil.isKeyDown(InputConstants.KEY_LSHIFT) || KeyUtil.isKeyDown(InputConstants.KEY_RSHIFT))
charTyped(KeyUtil.shiftKey(c).charAt(0)); charTyped(KeyUtil.shiftKey(c).charAt(0));
else else
charTyped(c.toLowerCase().charAt(0)); charTyped(c.toLowerCase().charAt(0));
@@ -7,7 +7,7 @@ import me.retucio.sputnik.util.MiscUtil;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.awt.Color; import java.awt.Color;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -69,21 +69,21 @@ public class TextFieldWidget extends Widget {
@Override @Override
public void onKey(int key, int action) { public void onKey(int key, int action) {
if (!focused || action == GLFW.GLFW_RELEASE) return; if (!focused || action == InputConstants.RELEASE) return;
if (key == GLFW.GLFW_KEY_V && KeyUtil.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL)) { if (key == InputConstants.KEY_V && KeyUtil.isKeyDown(InputConstants.KEY_LCONTROL)) {
buffer.append(MiscUtil.getPasteContent(maxLength - buffer.length())); buffer.append(MiscUtil.getPasteContent(maxLength - buffer.length()));
return; return;
} }
switch (key) { switch (key) {
case GLFW.GLFW_KEY_ENTER -> submit(); case InputConstants.KEY_RETURN -> submit();
case GLFW.GLFW_KEY_ESCAPE -> { case InputConstants.KEY_ESCAPE -> {
buffer.setLength(0); buffer.setLength(0);
focused = false; focused = false;
} }
case GLFW.GLFW_KEY_BACKSPACE -> MiscUtil.backspace(buffer); case InputConstants.KEY_BACKSPACE -> MiscUtil.backspace(buffer);
case GLFW.GLFW_KEY_SPACE -> charTyped(' '); case InputConstants.KEY_SPACE -> charTyped(' ');
default -> { default -> {
String c = KeyUtil.getKeyName(key); String c = KeyUtil.getKeyName(key);
if (c.length() == 1) if (c.length() == 1)
@@ -111,6 +111,11 @@ public class TextFieldWidget extends Widget {
} }
public String getText() { return buffer.toString(); } public String getText() { return buffer.toString(); }
public void setText(String text) {
buffer.setLength(0);
buffer.append(text.length() > maxLength ? text.substring(0, maxLength) : text);
}
public void clear() { buffer.setLength(0); } public void clear() { buffer.setLength(0); }
public boolean isFocused() { return focused; } public boolean isFocused() { return focused; }
@@ -1,143 +0,0 @@
package me.retucio.sputnik.ui.widgets.panels;
import com.github.retucio.neutrino.EventListener;
import me.retucio.sputnik.Sputnik;
import me.retucio.sputnik.event.sputnik.FriendEvent;
import me.retucio.sputnik.event.sputnik.FriendPanelEvent;
import me.retucio.sputnik.friend.Friend;
import me.retucio.sputnik.friend.FriendManager;
import me.retucio.sputnik.ui.screen.ClickGui;
import me.retucio.sputnik.ui.widgets.buttons.FriendButton;
import me.retucio.sputnik.util.Colors;
import me.retucio.sputnik.util.I18nUtil;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.network.chat.Component;
import java.util.List;
public class FriendsPanel extends ExtendablePanel<FriendButton> {
private int offset;
public FriendsPanel(int x, int y, int w, int h) {
super(() -> I18nUtil.orElse("sputnik.ui.friends.title", "amigos"), x, y, w, h);
dragging = false;
Sputnik.EVENT_BUS.subscribe(this);
offset = h;
for (Friend friend : FriendManager.INSTANCE.getFriends()) {
buttons.add(new FriendButton(friend, this, offset));
offset += h;
}
}
@Override
protected void updateWidth() {
int maxWidth = mc.font.width(getTitle()) + mc.font.width(" +");
for (FriendButton button : buttons) {
int textWidth = mc.font.width(button.getFriend().getName());
maxWidth = Math.max(maxWidth, textWidth);
}
this.w = maxWidth + 22;
}
@Override
public void render(GuiGraphicsExtractor gui, int mouseX, int mouseY, float delta) {
updateWidth();
gui.fill(x, renderY, x + w, renderY + h, Colors.mainColor.getRGB());
gui.text(mc.font, Component.literal(getTitle()),
x + 8,
renderY + (h / 2) - (mc.font.lineHeight / 2),
-1, true);
drawExpandCollapse(gui, mouseX, mouseY);
List<FriendButton> visibleButtons = buttons.stream()
.filter(fb -> fb.getFriend().isSearchMatch())
.toList();
if (extended) {
totalHeight = visibleButtons.size() * h + 3;
gui.fill(x, renderY + h + 1, x + w, renderY + h + totalHeight, Colors.panelBgColor.getRGB());
int buttonY = renderY + h + 1;
for (FriendButton friendButton : visibleButtons) {
friendButton.setOffset(buttonY - renderY);
friendButton.render(gui, mouseX, mouseY, delta);
buttonY += h;
}
} else {
totalHeight = 0;
}
}
@Override
public void mouseClicked(int mouseX, int mouseY, int button) {
if (isHovered(mouseX, mouseY) && ClickGui.INSTANCE.trySelect(this)) {
if (button == 0) {
dragging = true;
dragX = mouseX - x;
dragY = mouseY - y;
} else if (button == 1) {
toggleExtended();
Sputnik.EVENT_BUS.post(new FriendPanelEvent.Extend());
}
}
if (!extended) return;
List<FriendButton> visibleFriendButtons = buttons.stream()
.filter(fb -> fb.getFriend().isSearchMatch())
.toList();
for (FriendButton friendButton : visibleFriendButtons) {
friendButton.mouseClicked(mouseX, mouseY, button);
}
}
@Override
public void mouseReleased(int mouseX, int mouseY, int button) {
ClickGui.INSTANCE.unselect(this);
if (button == 0 && dragging) dragging = false;
List<FriendButton> visibleFriendButtons = buttons.stream()
.filter(fb -> fb.getFriend().isSearchMatch())
.toList();
for (FriendButton friendButton : visibleFriendButtons) {
if (friendButton.isHovered(mouseX, mouseY))
friendButton.mouseReleased(mouseX, mouseY, button);
}
if (isHovered(mouseX, mouseY))
Sputnik.EVENT_BUS.post(new FriendPanelEvent.Move());
}
public void updatePosition(double mouseX, double mouseY) {
if (dragging) {
x = (int) (mouseX - dragX);
y = (int) (mouseY - dragY);
}
}
@EventListener
private void onAddFriend(FriendEvent.Add event) {
buttons.add(new FriendButton(event.getFriend(), this, offset));
}
@EventListener
private void onRemoveFriend(FriendEvent.Remove event) {
buttons.remove(getButtonOfFriend(event.getFriend()));
}
public FriendButton getButtonOfFriend(Friend friend) {
for (FriendButton button : buttons) {
if (button.getFriend().getUuid().equals(friend.getUuid()))
return button;
}
return null;
}
}
@@ -1,107 +1,128 @@
package me.retucio.sputnik.ui.widgets.panels.settings; package me.retucio.sputnik.ui.widgets.panels.settings;
import me.retucio.sputnik.Sputnik;
import me.retucio.sputnik.event.sputnik.ClientSettingsPanelEvent;
import me.retucio.sputnik.module.modules.client.ClientSettingsModule; import me.retucio.sputnik.module.modules.client.ClientSettingsModule;
import me.retucio.sputnik.ui.screen.ClickGui;
import me.retucio.sputnik.ui.widgets.panels.SettingsPanel; import me.retucio.sputnik.ui.widgets.panels.SettingsPanel;
import me.retucio.sputnik.ui.widgets.buttons.SettingButton;
import me.retucio.sputnik.util.Colors; import me.retucio.sputnik.util.Colors;
import me.retucio.sputnik.util.I18nUtil; import me.retucio.sputnik.util.I18nUtil;
import me.retucio.sputnik.module.setting.SettingGroup;
import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.GuiGraphicsExtractor;
import java.util.List;
public class ClientSettingsPanel extends SettingsPanel { public class ClientSettingsPanel extends SettingsPanel {
public static final ClientSettingsModule clientSettings = new ClientSettingsModule(); public static final ClientSettingsModule clientSettings = new ClientSettingsModule();
private boolean extended = false; private final List<SettingGroup> allGroups;
private SettingGroup selectedGroup;
private static final int SIDEBAR_WIDTH = 190;
private static final int CONTENT_TOP = 62;
private static final int GROUP_HEIGHT = 28;
public ClientSettingsPanel(int x, int y, int w, int h) { public ClientSettingsPanel(int x, int y, int w, int h) {
super(clientSettings, x, y, w, h); super(clientSettings, SIDEBAR_WIDTH, 28, 0, 24);
allGroups = clientSettings.getSgs().stream().filter(group -> !group.getSettings().isEmpty()).toList();
selectedGroup = allGroups.getFirst();
setSettingGroups(List.of(selectedGroup));
selectedGroup.setExtended(true);
setTitle(() -> I18nUtil.orElse("sputnik.ui.clientsettings.title", "ajustes del mod")); setTitle(() -> I18nUtil.orElse("sputnik.ui.clientsettings.title", "ajustes del mod"));
this.drawHeader = false; // disable the original header this.drawHeader = false;
} }
@Override @Override
public void render(GuiGraphicsExtractor gui, int mouseX, int mouseY, float delta) { public void render(GuiGraphicsExtractor gui, int mouseX, int mouseY, float delta) {
updateWidth(); int screenWidth = mc.getWindow().getGuiScaledWidth();
int screenHeight = mc.getWindow().getGuiScaledHeight();
x = SIDEBAR_WIDTH;
y = 28;
renderY = y;
w = screenWidth - SIDEBAR_WIDTH;
h = 24;
// Draw our own custom header (no close button, with +/- gui.fill(0, 20, screenWidth, screenHeight, Colors.panelBgColor.getRGB());
gui.fill(x, renderY, x + w, renderY + h, Colors.mainColor.getRGB()); gui.fill(0, 20, SIDEBAR_WIDTH, screenHeight, Colors.buttonColor.getRGB());
gui.text(mc.font, getTitle(), gui.text(mc.font, getTitle(), 14, 28, Colors.mainColor.getRGB(), true);
x + 8,
renderY + (h / 2) - (mc.font.lineHeight / 2),
-1, true);
String symbol = extended ? "-" : "+"; int tabY = 52;
int textWidth = mc.font.width(symbol); for (SettingGroup group : allGroups) {
gui.text(mc.font, symbol, boolean hovered = mouseX >= 8 && mouseX < SIDEBAR_WIDTH - 8
x + w - textWidth - 8, && mouseY >= tabY && mouseY < tabY + GROUP_HEIGHT;
renderY + (h / 2) - (mc.font.lineHeight / 2), int color = group == selectedGroup ? Colors.mainColor.getRGB()
-1, true); : hovered ? Colors.buttonColor.brighter().getRGB() : Colors.buttonColor.getRGB();
gui.fill(8, tabY, SIDEBAR_WIDTH - 8, tabY + GROUP_HEIGHT, color);
// Only draw the rest of the panel (content) if extended gui.text(mc.font, group.getName(), 18,
if (extended) { tabY + (GROUP_HEIGHT - mc.font.lineHeight) / 2, -1, true);
// Call super.render() – but since drawHeader=false, it will only draw the content tabY += GROUP_HEIGHT + 4;
super.render(gui, mouseX, mouseY, delta);
} }
gui.text(mc.font, selectedGroup.getName(), x + 12, y,
Colors.mainColor.getRGB(), true);
visibleButtons = buttons.stream()
.filter(button -> button.getSetting().getSg() == selectedGroup
&& button.getSetting().isVisible() && button.getSetting().isSearchMatch())
.toList();
int settingY = CONTENT_TOP;
for (SettingButton<?> button : visibleButtons) {
button.setX(x + 12);
button.setY(settingY);
button.setW(w - 24);
button.setH(24);
button.render(gui, mouseX, mouseY, delta);
settingY += 30;
}
}
public boolean mouseClickedGroupTab(int mouseX, int mouseY, int button) {
if (button != 0) return false;
int tabY = 52;
for (SettingGroup group : allGroups) {
if (mouseX >= 8 && mouseX < SIDEBAR_WIDTH - 8
&& mouseY >= tabY && mouseY < tabY + GROUP_HEIGHT) {
selectedGroup = group;
setSettingGroups(List.of(group));
group.setExtended(true);
updateVisibleButtonsForGroup(group);
return true;
}
tabY += GROUP_HEIGHT + 4;
}
return false;
} }
@Override @Override
public void mouseClicked(int mouseX, int mouseY, int button) { public void mouseClicked(int mouseX, int mouseY, int button) {
if (isHovered(mouseX, mouseY) && ClickGui.INSTANCE.trySelect(this)) { for (SettingButton<?> settingButton : visibleButtons)
if (button == 0) { settingButton.mouseClicked(mouseX, mouseY, button);
dragging = true;
dragX = mouseX - x;
dragY = mouseY - y;
} else if (button == 1) {
extended = !extended;
Sputnik.EVENT_BUS.post(new ClientSettingsPanelEvent.Extend());
return;
}
}
if (extended) {
super.mouseClicked(mouseX, mouseY, button);
}
} }
@Override @Override
public void mouseReleased(int mouseX, int mouseY, int button) { public void mouseReleased(int mouseX, int mouseY, int button) {
ClickGui.INSTANCE.unselect(this); for (SettingButton<?> settingButton : visibleButtons)
if (button == 0 && dragging) { settingButton.mouseReleased(mouseX, mouseY, button);
dragging = false;
Sputnik.EVENT_BUS.post(new ClientSettingsPanelEvent.Move());
}
if (extended) {
super.mouseReleased(mouseX, mouseY, button);
}
} }
@Override @Override
public void mouseDragged(int mouseX, int mouseY) { public void mouseDragged(int mouseX, int mouseY) {
if (extended) { for (SettingButton<?> settingButton : visibleButtons)
super.mouseDragged(mouseX, mouseY); settingButton.mouseDragged(mouseX, mouseY);
}
} }
@Override @Override
public void mouseScrolled(double amount) { public void mouseScrolled(double amount) {
if (extended) { super.mouseScrolled(amount);
super.mouseScrolled(amount);
}
} }
@Override @Override
public void onKey(int key, int action) { public void onKey(int key, int action) {
if (extended) { super.onKey(key, action);
super.onKey(key, action);
}
} }
public boolean isExtended() { public boolean isExtended() {
return extended; return true;
} }
public void setExtended(boolean extended) { public void setExtended(boolean extended) {
this.extended = extended; // La pestaña siempre muestra sus ajustes.
} }
} }
@@ -1,102 +0,0 @@
package me.retucio.sputnik.ui.widgets.panels.settings;
import me.retucio.sputnik.config.ConfigManager;
import me.retucio.sputnik.friend.Friend;
import me.retucio.sputnik.friend.FriendManager;
import me.retucio.sputnik.module.Category;
import me.retucio.sputnik.module.Module;
import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.client.Friends;
import me.retucio.sputnik.module.setting.settings.StringSetting;
import me.retucio.sputnik.ui.screen.ClickGui;
import me.retucio.sputnik.ui.widgets.buttons.settings.TextButton;
import me.retucio.sputnik.ui.widgets.panels.SettingsPanel;
import me.retucio.sputnik.util.Colors;
import me.retucio.sputnik.util.I18nUtil;
import net.minecraft.client.gui.GuiGraphicsExtractor;
public class FriendSettingsPanel extends SettingsPanel {
private final Friend friend;
private final StringSetting nickname;
public final Module dummyModule;
private int removeButtonY;
public FriendSettingsPanel(Friend friend, int x, int y, int w, int h) {
super(ModuleManager.INSTANCE.getModuleByClass(Friends.class), x, y, w, h);
this.friend = friend;
dummyModule = new Module(friend.getName(),
I18nUtil.orElse("sputnik.ui.friend.manage", "gestiona a " + friend.getName(), friend.getName()),
Category.CLIENT) {
@Override public void onEnable() {}
@Override public void onDisable() {}
};
dummyModule.getSettings().forEach(s -> s.visibility(false));
dummyModule.shouldSaveSettings(false);
setModule(dummyModule);
// clave a mano: el módulo es un dummy con el nombre del jugador, así que la clave
// derivada dependería de él y no existiría nunca en el lang
nickname = new StringSetting("nombre", "con qué nombre guardar al amigo", friend.getName(), 40)
.translationKey("sputnik.setting.friend.nickname");
dummyModule.getSgGeneral().add(nickname);
nickname.onUpdate(name -> {
friend.setName(name);
ConfigManager.INSTANCE.getConfig().friends.put(friend.getUuid().toString(), name);
ConfigManager.INSTANCE.save();
});
buttons.clear();
addButton(new TextButton(nickname, this, h));
setSettingGroups(dummyModule.getSgs());
}
@Override
public void render(GuiGraphicsExtractor gui, int mx, int my, float delta) {
super.render(gui, mx, my, delta);
removeButtonY = renderY + h + totalHeight + PADDING;
int buttonH = h - h / 4;
gui.fill(x, removeButtonY, x + w, removeButtonY + buttonH + PADDING, Colors.panelBgColor.getRGB());
int color = isRemoveButtonHovered(mx, my)
? Colors.disabledToggleButtonColor.brighter().getRGB()
: Colors.disabledToggleButtonColor.getRGB();
gui.fill(x + PADDING, removeButtonY, x + w - PADDING, removeButtonY + buttonH, color);
String label = I18nUtil.orElse("sputnik.ui.friend.remove", "eliminar amigo");
gui.text(mc.font, label,
x + w / 2 - mc.font.width(label) / 2,
removeButtonY + (buttonH - mc.font.lineHeight) / 2,
-1, true);
}
@Override
public void mouseClicked(int mouseX, int mouseY, int button) {
super.mouseClicked(mouseX, mouseY, button);
if (button == 0 && isRemoveButtonHovered(mouseX, mouseY)) {
FriendManager.INSTANCE.remove(friend);
ClickGui.INSTANCE.closeSettingsPanel(dummyModule);
}
}
private boolean isRemoveButtonHovered(int mouseX, int mouseY) {
int buttonH = h - h / 4;
return mouseX > x + PADDING && mouseX < x + w - PADDING
&& mouseY > removeButtonY && mouseY < removeButtonY + buttonH;
}
public Friend getFriend() {
return friend;
}
}
@@ -3,10 +3,12 @@ package me.retucio.sputnik.util;
import me.retucio.sputnik.mixin.accessors.KeyBindingAccessor; import me.retucio.sputnik.mixin.accessors.KeyBindingAccessor;
import net.minecraft.client.KeyMapping; import net.minecraft.client.KeyMapping;
import net.minecraft.client.input.KeyEvent; import net.minecraft.client.input.KeyEvent;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.awt.*; import java.awt.*;
import java.awt.im.InputContext; import java.awt.im.InputContext;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Locale; import java.util.Locale;
import static me.retucio.sputnik.Sputnik.mc; import static me.retucio.sputnik.Sputnik.mc;
@@ -14,8 +16,103 @@ import static me.retucio.sputnik.Sputnik.mc;
// cosas útiles relacionadas con las teclas // cosas útiles relacionadas con las teclas
public class KeyUtil { public class KeyUtil {
private static final int MOUSE_BIND_BASE = -1000;
private static final Set<Integer> PRESSED_MOUSE_BUTTONS = ConcurrentHashMap.newKeySet();
public static int encodeMouseButton(int button) {
return MOUSE_BIND_BASE - button;
}
public static boolean isMouseBinding(int key) {
return key < MOUSE_BIND_BASE;
}
private static int decodeMouseButton(int key) {
return MOUSE_BIND_BASE - key;
}
public static void setMouseButtonDown(int button, boolean down) {
if (down) PRESSED_MOUSE_BUTTONS.add(button);
else PRESSED_MOUSE_BUTTONS.remove(button);
}
/** Converts a pre-26.3 GLFW key or mouse button code to the SDL scancode used by 26.3. */
public static int fromLegacyGlfwKey(int key) {
if (key >= 65 && key <= 90) return key - 61; // A-Z -> SDL scancodes 4-29
if (key >= 48 && key <= 57) return key - 18; // 0-9 -> SDL scancodes 30-39
if (key >= 290 && key <= 301) return key - 232; // F1-F12 -> 58-69
if (key >= 302 && key <= 313) return key - 198; // F13-F24 -> 104-115
if (key == 320) return InputConstants.KEY_NUMPAD0;
if (key >= 321 && key <= 329) return key - 232; // keypad 1-9
if (key >= 3 && key <= 7) return encodeMouseButton(key + 1); // GLFW mouse 3-7 -> SDL 4-8
return switch (key) {
case 0 -> encodeMouseButton(InputConstants.MOUSE_BUTTON_LEFT);
case 1 -> encodeMouseButton(InputConstants.MOUSE_BUTTON_RIGHT);
case 2 -> encodeMouseButton(InputConstants.MOUSE_BUTTON_MIDDLE);
case 32 -> InputConstants.KEY_SPACE;
case 39 -> InputConstants.KEY_APOSTROPHE;
case 44 -> InputConstants.KEY_COMMA;
case 45 -> InputConstants.KEY_MINUS;
case 46 -> InputConstants.KEY_PERIOD;
case 47 -> InputConstants.KEY_SLASH;
case 59 -> InputConstants.KEY_SEMICOLON;
case 61 -> InputConstants.KEY_EQUALS;
case 91 -> InputConstants.KEY_LBRACKET;
case 92 -> InputConstants.KEY_BACKSLASH;
case 93 -> InputConstants.KEY_RBRACKET;
case 96 -> InputConstants.KEY_GRAVE;
case 256 -> InputConstants.KEY_ESCAPE;
case 257, 335 -> key == 257 ? InputConstants.KEY_RETURN : InputConstants.KEY_NUMPADENTER;
case 258 -> InputConstants.KEY_TAB;
case 259 -> InputConstants.KEY_BACKSPACE;
case 260 -> InputConstants.KEY_INSERT;
case 261 -> InputConstants.KEY_DELETE;
case 262 -> InputConstants.KEY_RIGHT;
case 263 -> InputConstants.KEY_LEFT;
case 264 -> InputConstants.KEY_DOWN;
case 265 -> InputConstants.KEY_UP;
case 266 -> InputConstants.KEY_PAGEUP;
case 267 -> InputConstants.KEY_PAGEDOWN;
case 268 -> InputConstants.KEY_HOME;
case 269 -> InputConstants.KEY_END;
case 280 -> InputConstants.KEY_CAPSLOCK;
case 281 -> InputConstants.KEY_SCROLLLOCK;
case 282 -> InputConstants.KEY_NUMLOCK;
case 283 -> InputConstants.KEY_PRINTSCREEN;
case 284 -> InputConstants.KEY_PAUSE;
case 330 -> 99; // SDL_NUMPAD_DECIMAL
case 331 -> 84; // SDL_NUMPAD_DIVIDE
case 332 -> InputConstants.KEY_MULTIPLY;
case 333 -> 86; // SDL_NUMPAD_SUBTRACT
case 334 -> InputConstants.KEY_ADD;
case 336 -> InputConstants.KEY_NUMPADEQUALS;
case 340 -> InputConstants.KEY_LSHIFT;
case 341 -> InputConstants.KEY_LCONTROL;
case 342 -> InputConstants.KEY_LALT;
case 343 -> InputConstants.KEY_LGUI;
case 344 -> InputConstants.KEY_RSHIFT;
case 345 -> InputConstants.KEY_RCONTROL;
case 346 -> InputConstants.KEY_RALT;
case -1 -> InputConstants.UNKNOWN.getValue();
default -> key;
};
}
/** Converts 26.3 SDL mouse button numbers to the 0-based values used by our UI widgets. */
public static int toLegacyMouseButton(int button) {
return switch (button) {
case InputConstants.MOUSE_BUTTON_LEFT -> 0;
case InputConstants.MOUSE_BUTTON_RIGHT -> 1;
case InputConstants.MOUSE_BUTTON_MIDDLE -> 2;
default -> button >= InputConstants.MOUSE_BUTTON_4 && button <= InputConstants.MOUSE_BUTTON_8
? button - 1 : button;
};
}
public static int getKeyAction(int key) { public static int getKeyAction(int key) {
return GLFW.glfwGetKey(mc.getWindow().handle(), key); return InputConstants.isKeyDown(key) ? InputConstants.PRESS : InputConstants.RELEASE;
} }
public static boolean isKeyDown(KeyMapping key) { public static boolean isKeyDown(KeyMapping key) {
@@ -23,14 +120,13 @@ public class KeyUtil {
} }
public static boolean isKeyDown(int key) { public static boolean isKeyDown(int key) {
return GLFW.glfwGetKey( if (isMouseBinding(key)) return PRESSED_MOUSE_BUTTONS.contains(decodeMouseButton(key));
mc.getWindow().handle(), return InputConstants.isKeyDown(key);
key) != GLFW.GLFW_RELEASE;
} }
public static boolean isShiftDown() { public static boolean isShiftDown() {
return isKeyDown(GLFW.GLFW_KEY_LEFT_SHIFT) return isKeyDown(InputConstants.KEY_LSHIFT)
|| isKeyDown(GLFW.GLFW_KEY_RIGHT_SHIFT); || isKeyDown(InputConstants.KEY_RSHIFT);
} }
public static int getKey(KeyMapping kb) { public static int getKey(KeyMapping kb) {
@@ -58,39 +154,48 @@ public class KeyUtil {
} }
public static String getKeyName(int key) { public static String getKeyName(int key) {
if (key == GLFW.GLFW_KEY_UNKNOWN) return I18nUtil.orElse("sputnik.key.none", "ninguna"); if (key == InputConstants.UNKNOWN.getValue()) return I18nUtil.orElse("sputnik.key.none", "ninguna");
if (isMouseBinding(key)) {
int button = decodeMouseButton(key);
return switch (button) {
case InputConstants.MOUSE_BUTTON_LEFT -> I18nUtil.orElse("sputnik.key.leftclick", "clic izquierdo");
case InputConstants.MOUSE_BUTTON_RIGHT -> I18nUtil.orElse("sputnik.key.rightclick", "clic derecho");
case InputConstants.MOUSE_BUTTON_MIDDLE -> I18nUtil.orElse("sputnik.key.middleclick", "ruedita");
default -> I18nUtil.orElse("sputnik.key.mousebutton", "botón del ratón " + button, button);
};
}
String name = GLFW.glfwGetKeyName(key, 0); String name = InputConstants.getKey(new net.minecraft.client.input.KeyEvent(key, 0, 0)).getDisplayName().getString();
if (name != null) return name.toUpperCase(); if (name != null) return name.toUpperCase();
// para teclas especiales // para teclas especiales
return switch (key) { return switch (key) {
case GLFW.GLFW_MOUSE_BUTTON_1 -> I18nUtil.orElse("sputnik.key.leftclick", "clic izquierdo"); case InputConstants.MOUSE_BUTTON_LEFT -> I18nUtil.orElse("sputnik.key.leftclick", "clic izquierdo");
case GLFW.GLFW_MOUSE_BUTTON_2 -> I18nUtil.orElse("sputnik.key.rightclick", "clic derecho"); case InputConstants.MOUSE_BUTTON_RIGHT -> I18nUtil.orElse("sputnik.key.rightclick", "clic derecho");
case GLFW.GLFW_MOUSE_BUTTON_3 -> I18nUtil.orElse("sputnik.key.middleclick", "ruedita"); case InputConstants.MOUSE_BUTTON_MIDDLE -> I18nUtil.orElse("sputnik.key.middleclick", "ruedita");
case GLFW.GLFW_KEY_SPACE -> I18nUtil.orElse("sputnik.key.space", "espacio"); case InputConstants.KEY_SPACE -> I18nUtil.orElse("sputnik.key.space", "espacio");
case GLFW.GLFW_KEY_LEFT_SHIFT -> I18nUtil.orElse("sputnik.key.leftshift", "shift izquierdo"); case InputConstants.KEY_LSHIFT -> I18nUtil.orElse("sputnik.key.leftshift", "shift izquierdo");
case GLFW.GLFW_KEY_RIGHT_SHIFT -> I18nUtil.orElse("sputnik.key.rightshift", "shift derecho"); case InputConstants.KEY_RSHIFT -> I18nUtil.orElse("sputnik.key.rightshift", "shift derecho");
case GLFW.GLFW_KEY_LEFT_CONTROL -> I18nUtil.orElse("sputnik.key.leftctrl", "ctrl izquierdo"); case InputConstants.KEY_LCONTROL -> I18nUtil.orElse("sputnik.key.leftctrl", "ctrl izquierdo");
case GLFW.GLFW_KEY_RIGHT_CONTROL -> I18nUtil.orElse("sputnik.key.rightctrl", "ctrl derecho"); case InputConstants.KEY_RCONTROL -> I18nUtil.orElse("sputnik.key.rightctrl", "ctrl derecho");
case GLFW.GLFW_KEY_LEFT_ALT -> I18nUtil.orElse("sputnik.key.leftalt", "alt izquierdo"); case InputConstants.KEY_LALT -> I18nUtil.orElse("sputnik.key.leftalt", "alt izquierdo");
case GLFW.GLFW_KEY_RIGHT_ALT -> I18nUtil.orElse("sputnik.key.altgr", "alt gr"); case InputConstants.KEY_RALT -> I18nUtil.orElse("sputnik.key.altgr", "alt gr");
case GLFW.GLFW_KEY_TAB -> I18nUtil.orElse("sputnik.key.tab", "tab"); case InputConstants.KEY_TAB -> I18nUtil.orElse("sputnik.key.tab", "tab");
case GLFW.GLFW_KEY_ENTER -> I18nUtil.orElse("sputnik.key.enter", "enter"); case InputConstants.KEY_RETURN -> I18nUtil.orElse("sputnik.key.enter", "enter");
case GLFW.GLFW_KEY_BACKSPACE -> I18nUtil.orElse("sputnik.key.backspace", "borrar"); case InputConstants.KEY_BACKSPACE -> I18nUtil.orElse("sputnik.key.backspace", "borrar");
case GLFW.GLFW_KEY_DELETE -> I18nUtil.orElse("sputnik.key.delete", "suprimir"); case InputConstants.KEY_DELETE -> I18nUtil.orElse("sputnik.key.delete", "suprimir");
case GLFW.GLFW_KEY_UP -> I18nUtil.orElse("sputnik.key.up", "arriba"); case InputConstants.KEY_UP -> I18nUtil.orElse("sputnik.key.up", "arriba");
case GLFW.GLFW_KEY_DOWN -> I18nUtil.orElse("sputnik.key.down", "abajo"); case InputConstants.KEY_DOWN -> I18nUtil.orElse("sputnik.key.down", "abajo");
case GLFW.GLFW_KEY_LEFT -> I18nUtil.orElse("sputnik.key.left", "izquierda"); case InputConstants.KEY_LEFT -> I18nUtil.orElse("sputnik.key.left", "izquierda");
case GLFW.GLFW_KEY_RIGHT -> I18nUtil.orElse("sputnik.key.right", "derecha"); case InputConstants.KEY_RIGHT -> I18nUtil.orElse("sputnik.key.right", "derecha");
case GLFW.GLFW_KEY_PAGE_UP -> I18nUtil.orElse("sputnik.key.pageup", "pág. arriba"); case InputConstants.KEY_PAGEUP -> I18nUtil.orElse("sputnik.key.pageup", "pág. arriba");
case GLFW.GLFW_KEY_PAGE_DOWN -> I18nUtil.orElse("sputnik.key.pagedown", "pág. abajo"); case InputConstants.KEY_PAGEDOWN -> I18nUtil.orElse("sputnik.key.pagedown", "pág. abajo");
case GLFW.GLFW_KEY_CAPS_LOCK -> I18nUtil.orElse("sputnik.key.capslock", "bloq. mayús."); case InputConstants.KEY_CAPSLOCK -> I18nUtil.orElse("sputnik.key.capslock", "bloq. mayús.");
case GLFW.GLFW_KEY_INSERT -> I18nUtil.orElse("sputnik.key.insert", "insertar"); case InputConstants.KEY_INSERT -> I18nUtil.orElse("sputnik.key.insert", "insertar");
default -> { default -> {
if (key >= GLFW.GLFW_KEY_F1 && key <= GLFW.GLFW_KEY_F25) { if (key >= InputConstants.KEY_F1 && key <= InputConstants.KEY_F24) {
yield "F" + (key - GLFW.GLFW_KEY_F1 + 1); // F1–F25 yield "F" + (key - InputConstants.KEY_F1 + 1); // F1–F25
} else if (key >= GLFW.GLFW_MOUSE_BUTTON_4 && key <= GLFW.GLFW_MOUSE_BUTTON_8) { } else if (key >= InputConstants.MOUSE_BUTTON_4 && key <= InputConstants.MOUSE_BUTTON_8) {
// botones del ratón // botones del ratón
yield I18nUtil.orElse("sputnik.key.mousebutton", yield I18nUtil.orElse("sputnik.key.mousebutton",
"botón del ratón " + (key + 1), key + 1); "botón del ratón " + (key + 1), key + 1);
@@ -12,7 +12,7 @@ import net.minecraft.world.phys.Vec3;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3f; import org.joml.Vector3f;
import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants;
import java.io.*; import java.io.*;
import java.time.Instant; import java.time.Instant;
@@ -100,7 +100,7 @@ public class MiscUtil {
} }
public static void backspace(StringBuilder buffer) { public static void backspace(StringBuilder buffer) {
if (KeyUtil.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL)) { if (KeyUtil.isKeyDown(InputConstants.KEY_LCONTROL)) {
for (int i = buffer.length() - 1; i >= 0; i--) { for (int i = buffer.length() - 1; i >= 0; i--) {
char c = buffer.charAt(i); char c = buffer.charAt(i);
buffer.deleteCharAt(i); buffer.deleteCharAt(i);
@@ -11,18 +11,17 @@ import net.minecraft.network.PacketListener;
import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientboundSetTimePacket; import net.minecraft.network.protocol.game.ClientboundSetTimePacket;
import net.minecraft.network.protocol.game.ServerboundSetCarriedItemPacket; import net.minecraft.network.protocol.game.ServerboundSetCarriedItemPacket;
import net.minecraft.network.protocol.game.ServerboundSwingPacket;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.SwingAnimation;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -100,8 +99,7 @@ public class NetworkUtil {
InteractionResult result = mc.gameMode.useItemOn(mc.player, hand, blockHitResult); InteractionResult result = mc.gameMode.useItemOn(mc.player, hand, blockHitResult);
if (result.consumesAction()) { if (result.consumesAction()) {
if (swing) mc.player.swing(hand); mc.player.swing(hand, SwingAnimation.DEFAULT, false);
else mc.getConnection().send(new ServerboundSwingPacket(hand));
} }
mc.player.setShiftKeyDown(wasSneaking); mc.player.setShiftKeyDown(wasSneaking);
@@ -4,12 +4,15 @@ import me.retucio.sputnik.Sputnik;
import me.retucio.sputnik.module.modules.render.GlintPlus; import me.retucio.sputnik.module.modules.render.GlintPlus;
import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.client.renderer.rendertype.*; import net.minecraft.client.renderer.rendertype.*;
import net.minecraft.client.renderer.oit.OitPipelineSet;
import net.minecraft.resources.Identifier; import net.minecraft.resources.Identifier;
import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.DyeColor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/** utilidad para crear RenderTypes de glint con color personalizado /** utilidad para crear RenderTypes de glint con color personalizado
@@ -22,7 +25,6 @@ public class GlintRenderType {
public static final List<RenderType> glintColor = newRenderList(GlintRenderType::buildGlintRenderType); public static final List<RenderType> glintColor = newRenderList(GlintRenderType::buildGlintRenderType);
public static final List<RenderType> entityGlintColor = newRenderList(GlintRenderType::buildEntityGlintRenderType); public static final List<RenderType> entityGlintColor = newRenderList(GlintRenderType::buildEntityGlintRenderType);
public static final List<RenderType> armorEntityGlintColor = newRenderList(GlintRenderType::buildArmorEntityGlintRenderType);
public static final List<RenderType> glintTranslucentColor = newRenderList(GlintRenderType::buildGlintTranslucentRenderType); public static final List<RenderType> glintTranslucentColor = newRenderList(GlintRenderType::buildGlintTranslucentRenderType);
private static List<RenderType> newRenderList(Function<String, RenderType> func) { private static List<RenderType> newRenderList(Function<String, RenderType> func) {
@@ -55,7 +57,6 @@ public class GlintRenderType {
RenderSetup.builder(RenderPipelines.GLINT) RenderSetup.builder(RenderPipelines.GLINT)
.withTexture("Sampler0", res) .withTexture("Sampler0", res)
.setTextureTransform(TextureTransform.GLINT_TEXTURING) .setTextureTransform(TextureTransform.GLINT_TEXTURING)
.setOutputTarget(OutputTarget.ITEM_ENTITY_TARGET)
.createRenderSetup() .createRenderSetup()
); );
} }
@@ -71,15 +72,57 @@ public class GlintRenderType {
); );
} }
private static RenderType buildArmorEntityGlintRenderType(String name) { private static final Map<String, RenderType> ARMOR_GLINT_TYPES = new ConcurrentHashMap<>();
private static final Map<ItemGlintKey, RenderType> ITEM_GLINT_TYPES = new ConcurrentHashMap<>();
public static RenderType itemGlint(String name, RenderType original, Identifier itemAtlas) {
return ITEM_GLINT_TYPES.computeIfAbsent(new ItemGlintKey(name, original.pipeline(), itemAtlas), key -> {
Identifier glintTexture = Identifier.fromNamespaceAndPath(
Sputnik.MOD_ID, "textures/misc/glint_" + name.toLowerCase() + ".png");
RenderSetup.RenderSetupBuilder setup = RenderSetup.builder(original.pipeline())
.withTexture("Sampler0", itemAtlas)
.withTexture("GlintSampler", glintTexture)
.setTextureTransform(TextureTransform.GLINT_TEXTURING)
.useLightmap()
.useOverlay()
.affectsCrumbling()
.setOutline(RenderSetup.OutlineProperty.AFFECTS_OUTLINE);
if (original.pipeline() == RenderPipelines.ITEM_TRANSLUCENT_GLINT
|| original.pipeline() == RenderPipelines.ITEM_TRANSLUCENT_GLINT_SPECIAL) {
OitPipelineSet oit = original.pipeline() == RenderPipelines.ITEM_TRANSLUCENT_GLINT_SPECIAL
? RenderPipelines.OIT_ITEM_GLINT_SPECIAL : RenderPipelines.OIT_ITEM_GLINT;
setup.setOitPipelines(oit).sortOnUpload();
} else if (original.pipeline() == RenderPipelines.ITEM_CUTOUT_GLINT_SPECIAL) {
setup.setOitPipelines(RenderPipelines.OIT_ITEM_GLINT_SPECIAL);
}
return RenderType.create("sputnik_item_glint_" + name, setup.createRenderSetup());
});
}
private record ItemGlintKey(String color, com.mojang.renderpearl.api.pipeline.RenderPipeline pipeline,
Identifier atlas) { }
public static RenderType armorEntityGlint(String name, Identifier armorTexture) {
return ARMOR_GLINT_TYPES.computeIfAbsent(name + ":" + armorTexture, key ->
buildArmorEntityGlintRenderType(name, armorTexture));
}
private static RenderType buildArmorEntityGlintRenderType(String name, Identifier armorTexture) {
final Identifier res = Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "textures/misc/glint_" + name.toLowerCase() + ".png"); final Identifier res = Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "textures/misc/glint_" + name.toLowerCase() + ".png");
return RenderType.create( return RenderType.create(
"armor_glint_" + name, "armor_glint_" + name,
RenderSetup.builder(RenderPipelines.GLINT) RenderSetup.builder(RenderPipelines.ARMOR_CUTOUT_NO_CULL_GLINT)
.withTexture("Sampler0", res) .withTexture("Sampler0", armorTexture)
.withTexture("GlintSampler", res)
.setTextureTransform(TextureTransform.ARMOR_ENTITY_GLINT_TEXTURING) .setTextureTransform(TextureTransform.ARMOR_ENTITY_GLINT_TEXTURING)
.useLightmap()
.useOverlay()
.setLayeringTransform(LayeringTransform.VIEW_OFFSET_Z_LAYERING) .setLayeringTransform(LayeringTransform.VIEW_OFFSET_Z_LAYERING)
.affectsCrumbling()
.setOutline(RenderSetup.OutlineProperty.AFFECTS_OUTLINE)
.createRenderSetup() .createRenderSetup()
); );
} }
} }
@@ -1,13 +1,14 @@
package me.retucio.sputnik.util.render; package me.retucio.sputnik.util.render;
import com.mojang.blaze3d.PrimitiveTopology; import com.mojang.renderpearl.api.pipeline.PrimitiveTopology;
import com.mojang.blaze3d.pipeline.DepthStencilState; import com.mojang.renderpearl.api.pipeline.DepthStencilState;
import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.renderpearl.api.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.CompareOp; import com.mojang.renderpearl.api.pipeline.CompareOp;
import com.mojang.blaze3d.systems.GpuDevice; import com.mojang.renderpearl.api.pipeline.ShaderType;
import com.mojang.renderpearl.api.device.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.renderpearl.api.vertex.VertexFormat;
import me.retucio.sputnik.Sputnik; import me.retucio.sputnik.Sputnik;
@@ -34,56 +35,46 @@ public class Pipelines {
private static final DepthStencilState NO_DEPTH = new DepthStencilState(CompareOp.ALWAYS_PASS, false); private static final DepthStencilState NO_DEPTH = new DepthStencilState(CompareOp.ALWAYS_PASS, false);
private static final DepthStencilState DEPTH = new DepthStencilState(CompareOp.GREATER_THAN_OR_EQUAL, false); private static final DepthStencilState DEPTH = new DepthStencilState(CompareOp.GREATER_THAN_OR_EQUAL, false);
static final RenderPipeline LINES_PIPELINE = add(RenderPipeline.builder(RenderPipelines.LINES_SNIPPET) static final RenderPipeline LINES_PIPELINE = add(copy(RenderPipelines.LINES)
.withLocation(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "pipeline/lines")) .withLocation(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "pipeline/lines"))
.withVertexBinding(0, DefaultVertexFormat.POSITION_COLOR_NORMAL_LINE_WIDTH) .withVertexBinding(0, DefaultVertexFormat.POSITION_COLOR_NORMAL_LINE_WIDTH)
.withPrimitiveTopology(PrimitiveTopology.LINES) .withPrimitiveTopology(PrimitiveTopology.LINES)
.withDepthStencilState(NO_DEPTH) .withDepthStencilState(NO_DEPTH)
.withCull(false) .withCull(false).build());
.build());
static final RenderPipeline LINES_CULL_PIPELINE = add(RenderPipeline.builder(RenderPipelines.LINES_SNIPPET) static final RenderPipeline LINES_CULL_PIPELINE = add(copy(RenderPipelines.LINES)
.withLocation(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "pipeline/lines_cull")) .withLocation(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "pipeline/lines_cull"))
.withVertexBinding(0, DefaultVertexFormat.POSITION_COLOR_NORMAL_LINE_WIDTH) .withVertexBinding(0, DefaultVertexFormat.POSITION_COLOR_NORMAL_LINE_WIDTH)
.withPrimitiveTopology(PrimitiveTopology.LINES) .withPrimitiveTopology(PrimitiveTopology.LINES)
.withDepthStencilState(DEPTH) .withDepthStencilState(DEPTH)
.withCull(true) .withCull(true).build());
.build());
static final RenderPipeline QUADS_PIPELINE = add(RenderPipeline.builder(RenderPipelines.DEBUG_FILLED_SNIPPET) static final RenderPipeline QUADS_PIPELINE = add(copy(RenderPipelines.DEBUG_QUADS)
.withLocation(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "pipeline/quads")) .withLocation(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "pipeline/quads"))
.withVertexBinding(0, DefaultVertexFormat.POSITION_COLOR) .withVertexBinding(0, DefaultVertexFormat.POSITION_COLOR)
.withPrimitiveTopology(PrimitiveTopology.QUADS) .withPrimitiveTopology(PrimitiveTopology.QUADS)
.withDepthStencilState(NO_DEPTH) .withDepthStencilState(NO_DEPTH)
.withCull(false) .withCull(false).build());
.build());
static final RenderPipeline QUADS_CULL_PIPELINE = add(RenderPipeline.builder(RenderPipelines.DEBUG_FILLED_SNIPPET) static final RenderPipeline QUADS_CULL_PIPELINE = add(copy(RenderPipelines.DEBUG_QUADS)
.withLocation(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "pipeline/quads_cull")) .withLocation(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "pipeline/quads_cull"))
.withVertexBinding(0, DefaultVertexFormat.POSITION_COLOR) .withVertexBinding(0, DefaultVertexFormat.POSITION_COLOR)
.withPrimitiveTopology(PrimitiveTopology.QUADS) .withPrimitiveTopology(PrimitiveTopology.QUADS)
.withDepthStencilState(DEPTH) .withDepthStencilState(DEPTH)
.withCull(false) .withCull(false).build());
.build());
static final RenderPipeline TEXT_PIPELINE = add(RenderPipeline.builder(RenderPipelines.GUI_TEXTURED_SNIPPET) static final RenderPipeline TEXT_PIPELINE = add(copy(RenderPipelines.GUI_TEXTURED)
.withLocation(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "pipeline/text")) .withLocation(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "pipeline/text"))
.withVertexBinding(0, DefaultVertexFormat.POSITION_TEX_COLOR) .withVertexBinding(0, DefaultVertexFormat.POSITION_TEX_COLOR)
.withPrimitiveTopology(PrimitiveTopology.TRIANGLES) .withPrimitiveTopology(PrimitiveTopology.TRIANGLES)
.withVertexShader(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "shaders/text.vert")) .withVertexShader(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "shaders/text.vert"))
.withFragmentShader(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "shaders/text.frag")) .withFragmentShader(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "shaders/text.frag"))
// 26.2 cambió los samplers por bind groups; ojo: los shaders de text.vert/frag
// siguen usando uniforms con nombre (u_Texture, u_ProjectionMatrix) y seguramente
// haya que reescribirlos para que casen con las convenciones nuevas
.withBindGroupLayout(BindGroupLayouts.SAMPLER0) .withBindGroupLayout(BindGroupLayouts.SAMPLER0)
.withDepthStencilState(NO_DEPTH) .withDepthStencilState(NO_DEPTH)
.withCull(false) .withCull(false).build());
.build());
public static void init() { public static void init() {
for (RenderPipeline pipeline : PIPELINES) { for (RenderPipeline pipeline : PIPELINES) precompile(pipeline);
precompile(pipeline);
}
} }
private static RenderPipeline add(RenderPipeline pipeline) { private static RenderPipeline add(RenderPipeline pipeline) {
@@ -92,17 +83,25 @@ public class Pipelines {
} }
public static void precompile(RenderPipeline pipeline) { public static void precompile(RenderPipeline pipeline) {
GpuDevice device = RenderSystem.getDevice(); // Pipeline compilation is lazy in 26.3; RenderPass resolves it from its RenderPipeline.
ResourceManager resources = Minecraft.getInstance().getResourceManager();
device.precompilePipeline(pipeline, (identifier, shaderType) -> {
Resource resource = resources.getResource(identifier).get();
try (InputStream is = resource.open()) {
return IOUtils.toString(is, StandardCharsets.UTF_8);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
} }
}
private static RenderPipeline.Builder copy(RenderPipeline base) {
RenderPipeline.Builder builder = RenderPipeline.builder()
.withLocation(base.getLocation())
.withCull(base.isCull())
.withPrimitiveTopology(base.getPrimitiveTopology())
.withPolygonMode(base.getPolygonMode());
base.getShaders().forEach((type, shader) -> {
if (type == ShaderType.VERTEX) builder.withVertexShader(shader);
else if (type == ShaderType.FRAGMENT) builder.withFragmentShader(shader);
});
base.getBindGroupLayouts().forEach(builder::withBindGroupLayout);
for (int i = 0; i < base.getVertexFormatBindings().size(); i++)
builder.withVertexBinding(i, base.getVertexFormatBinding(i));
for (int i = 0; i < base.getColorTargetStates().size(); i++)
builder.withColorTargetState(i, base.getColorTargetStates().get(i));
builder.withDepthStencilState(java.util.Optional.ofNullable(base.getDepthStencilState()));
return builder;
}
}
@@ -1,27 +1,33 @@
package me.retucio.sputnik.util.render; package me.retucio.sputnik.util.render;
import com.mojang.blaze3d.GpuFormat; import com.mojang.renderpearl.api.GpuFormat;
import com.mojang.blaze3d.buffers.GpuBuffer; import com.mojang.renderpearl.api.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.renderpearl.api.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.framegraph.FrameGraphBuilder; import com.mojang.blaze3d.framegraph.FrameGraphBuilder;
import com.mojang.blaze3d.framegraph.FramePass; import com.mojang.blaze3d.framegraph.FramePass;
import com.mojang.blaze3d.pipeline.BindGroupLayout; import com.mojang.renderpearl.api.pipeline.BindGroupLayout;
import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.renderpearl.api.pipeline.ColorTargetState;
import com.mojang.renderpearl.api.pipeline.CompiledRenderPipeline;
import com.mojang.renderpearl.api.pipeline.ShaderSource;
import com.mojang.renderpearl.api.pipeline.ShaderType;
import com.mojang.renderpearl.api.pipeline.RenderPipeline;
import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.pipeline.RenderTarget;
import com.mojang.blaze3d.resource.GraphicsResourceAllocator; import com.mojang.blaze3d.resource.GraphicsResourceAllocator;
import com.mojang.blaze3d.resource.RenderTargetDescriptor; import com.mojang.blaze3d.resource.RenderTargetDescriptor;
import com.mojang.blaze3d.resource.ResourceHandle; import com.mojang.blaze3d.resource.ResourceHandle;
import com.mojang.blaze3d.shaders.UniformType; import com.mojang.renderpearl.api.pipeline.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder; import com.mojang.renderpearl.api.commands.CommandEncoder;
import com.mojang.blaze3d.systems.RenderPass; import com.mojang.renderpearl.api.commands.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.FilterMode; import com.mojang.renderpearl.api.textures.FilterMode;
import com.mojang.blaze3d.textures.GpuSampler; import com.mojang.renderpearl.api.textures.GpuSampler;
import me.retucio.sputnik.Sputnik; import me.retucio.sputnik.Sputnik;
import net.minecraft.client.renderer.MappableRingBuffer; import net.minecraft.client.renderer.MappableRingBuffer;
import net.minecraft.client.renderer.BindGroupLayouts;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.resources.Identifier; import net.minecraft.resources.Identifier;
@@ -30,6 +36,8 @@ import org.joml.Vector4f;
import java.util.Optional; import java.util.Optional;
import java.util.OptionalDouble; import java.util.OptionalDouble;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -51,7 +59,8 @@ public class PostShader {
.withLocation(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "pipeline/post/blit")) .withLocation(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "pipeline/post/blit"))
.withVertexShader(SCREENQUAD) .withVertexShader(SCREENQUAD)
.withFragmentShader(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "post/blit")) .withFragmentShader(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "post/blit"))
.withBindGroupLayout(BindGroupLayout.builder().withSampler(INPUT_SAMPLER).build()) .withBindGroupLayout(BindGroupLayouts.IN_SAMPLER)
.withColorTargetState(ColorTargetState.DEFAULT)
.build(); .build();
private final String name; private final String name;
@@ -64,6 +73,7 @@ public class PostShader {
// 0 sin intentar, 1 ok, -1 falló al compilar (shader roto: no reintentar hasta recarga) // 0 sin intentar, 1 ok, -1 falló al compilar (shader roto: no reintentar hasta recarga)
private int state = 0; private int state = 0;
private static final Map<RenderPipeline, CompiledRenderPipeline> COMPILED = new ConcurrentHashMap<>();
private PostShader(String name, RenderPipeline pipeline, FilterMode filter, private PostShader(String name, RenderPipeline pipeline, FilterMode filter,
@Nullable String uniformBlock, int uniformSize) { @Nullable String uniformBlock, int uniformSize) {
@@ -86,14 +96,20 @@ public class PostShader {
private boolean ensureReady() { private boolean ensureReady() {
if (state != 0) return state == 1; if (state != 0) return state == 1;
boolean ok = RenderSystem.getDevice().precompilePipeline(pipeline).isValid() boolean ok;
&& RenderSystem.getDevice().precompilePipeline(BLIT_PIPELINE).isValid(); try {
compile(pipeline);
compile(BLIT_PIPELINE);
ok = true;
} catch (RuntimeException e) {
Sputnik.LOGGER.error("Failed to compile post shader '{}'", name, e);
ok = false;
}
if (ok && uniformBlock != null && uniformUbo == null) { if (ok && uniformBlock != null && uniformUbo == null) {
// 130 = USAGE_UNIFORM (128) | USAGE_MAP_WRITE (2): se reescribe cada frame // 130 = USAGE_UNIFORM (128) | USAGE_MAP_WRITE (2): se reescribe cada frame
uniformUbo = new MappableRingBuffer(() -> "sputnik post " + name, 130, uniformSize); uniformUbo = new MappableRingBuffer(() -> "sputnik post " + name, 130, uniformSize);
} }
state = ok ? 1 : -1; state = ok ? 1 : -1;
if (!ok) Sputnik.LOGGER.error("no se pudo compilar el shader de post '{}'", name);
return ok; return ok;
} }
@@ -109,8 +125,9 @@ public class PostShader {
FrameGraphBuilder frame = new FrameGraphBuilder(); FrameGraphBuilder frame = new FrameGraphBuilder();
ResourceHandle<RenderTarget> mainHandle = frame.importExternal(name + "_main", target); ResourceHandle<RenderTarget> mainHandle = frame.importExternal(name + "_main", target);
RenderTargetDescriptor swapDesc = new RenderTargetDescriptor( RenderTargetDescriptor swapDesc = new RenderTargetDescriptor(target.width, target.height,
target.width, target.height, true, NO_CLEAR, GpuFormat.RGBA8_UNORM); new RenderTargetDescriptor.TextureProperties(NO_CLEAR, GpuFormat.RGBA8_UNORM),
RenderTargetDescriptor.TextureProperties.DEFAULT_DEPTH);
ResourceHandle<RenderTarget> swapHandle = frame.createInternal(name + "_swap", swapDesc); ResourceHandle<RenderTarget> swapHandle = frame.createInternal(name + "_swap", swapDesc);
// pasada del efecto: main -> swap // pasada del efecto: main -> swap
@@ -145,16 +162,44 @@ public class PostShader {
() -> "sputnik post " + name, () -> "sputnik post " + name,
out.getColorTextureView(), out.getColorTextureView(),
Optional.empty(), Optional.empty(),
out.useDepth ? out.getDepthTextureView() : null, out.hasDepth() ? out.getDepthTextureView() : null,
OptionalDouble.empty())) { OptionalDouble.empty())) {
pass.setPipeline(pipeline); pass.setPipeline(compile(pipeline));
RenderSystem.bindDefaultUniforms(pass); RenderSystem.bindDefaultUniforms(pass);
if (uniform != null && uniformBlock != null) pass.setUniform(uniformBlock, uniform); if (uniform != null && uniformBlock != null) pass.setUniform(uniformBlock, uniform);
pass.bindTexture(INPUT_SAMPLER, in.getColorTextureView(), sampler); pass.setUniform(INPUT_SAMPLER, in.getColorTextureView(), sampler);
pass.draw(3, 1, 0, 0); pass.draw(3, 1, 0, 0);
} }
} }
private static CompiledRenderPipeline compile(RenderPipeline pipeline) {
return COMPILED.computeIfAbsent(pipeline, key -> {
ShaderSource source = new ShaderSource() {
@Override
public String getShader(Identifier id, ShaderType type) {
Identifier location = type.idConverter().idToFile(id);
try (var stream = Minecraft.getInstance().getResourceManager().getResourceOrThrow(location).open()) {
return new String(stream.readAllBytes(), java.nio.charset.StandardCharsets.UTF_8);
} catch (java.io.IOException e) {
throw new RuntimeException("Failed to load shader " + location, e);
}
}
@Override
public ShaderSource.CachedIncludeSource getInclude(Identifier id) {
return ShaderSource.CachedIncludeSource.create(id, getShader(id, ShaderType.VERTEX));
}
@Override public void close() { }
};
var pending = RenderSystem.getDevice().compilePipeline(key, source, Runnable::run).join();
if (pending == CompiledRenderPipeline.Pending.NULL) {
throw new IllegalStateException("Shader pipeline compilation failed: " + key.getLocation());
}
return pending.finishCompile();
});
}
public static class Builder { public static class Builder {
@@ -183,15 +228,17 @@ public class PostShader {
} }
public PostShader build() { public PostShader build() {
BindGroupLayout.Builder layout = BindGroupLayout.builder().withSampler(INPUT_SAMPLER); RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder(RenderPipelines.POST_PROCESSING_SNIPPET)
if (uniformBlock != null) layout.withUniform(uniformBlock, UniformType.UNIFORM_BUFFER);
RenderPipeline pipeline = RenderPipeline.builder(RenderPipelines.POST_PROCESSING_SNIPPET)
.withLocation(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "pipeline/post/" + name)) .withLocation(Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "pipeline/post/" + name))
.withVertexShader(SCREENQUAD) .withVertexShader(SCREENQUAD)
.withFragmentShader(fragmentShader) .withFragmentShader(fragmentShader)
.withBindGroupLayout(layout.build()) .withBindGroupLayout(BindGroupLayouts.IN_SAMPLER)
.build(); .withColorTargetState(ColorTargetState.DEFAULT);
if (uniformBlock != null) {
pipelineBuilder.withBindGroupLayout(
BindGroupLayout.builder().withUniform(uniformBlock, UniformType.UNIFORM_BUFFER).build());
}
RenderPipeline pipeline = pipelineBuilder.build();
return PostShaders.register(new PostShader(name, pipeline, filter, uniformBlock, uniformSize)); return PostShaders.register(new PostShader(name, pipeline, filter, uniformBlock, uniformSize));
} }
@@ -1,6 +1,6 @@
package me.retucio.sputnik.util.render; package me.retucio.sputnik.util.render;
import com.mojang.blaze3d.PrimitiveTopology; import com.mojang.renderpearl.api.pipeline.PrimitiveTopology;
import com.mojang.blaze3d.vertex.*; import com.mojang.blaze3d.vertex.*;
import com.mojang.math.Axis; import com.mojang.math.Axis;
import net.minecraft.client.Camera; import net.minecraft.client.Camera;
@@ -453,8 +453,8 @@ public class RenderUtil {
Camera camera = mc.gameRenderer.mainCamera(); Camera camera = mc.gameRenderer.mainCamera();
Vec3 camPos = camera.position(); Vec3 camPos = camera.position();
matrices.mulPose(Axis.XP.rotationDegrees(camera.yRot())); matrices.rotate(Axis.XP.rotationDegrees(camera.yRot()));
matrices.mulPose(Axis.YP.rotationDegrees(camera.xRot() + 180.0f)); matrices.rotate(Axis.YP.rotationDegrees(camera.xRot() + 180.0f));
matrices.translate( matrices.translate(
pos.x() - camPos.x(), pos.x() - camPos.x(),
@@ -1,8 +1,12 @@
package me.retucio.sputnik.util.render; package me.retucio.sputnik.util.render;
import com.mojang.blaze3d.PrimitiveTopology; import com.mojang.renderpearl.api.pipeline.PrimitiveTopology;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.renderpearl.api.vertex.VertexFormat;
import com.mojang.renderpearl.api.commands.CommandEncoder;
import com.mojang.renderpearl.api.commands.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.Minecraft;
import me.retucio.sputnik.Sputnik; import me.retucio.sputnik.Sputnik;
import net.minecraft.client.renderer.StagedVertexBuffer; import net.minecraft.client.renderer.StagedVertexBuffer;
import net.minecraft.client.renderer.rendertype.PreparedRenderType; import net.minecraft.client.renderer.rendertype.PreparedRenderType;
@@ -60,10 +64,18 @@ public class SputnikBuffers {
buffer.upload(); buffer.upload();
for (QueuedDraw queued : queue) { CommandEncoder encoder = RenderSystem.getDevice().createCommandEncoder();
StagedVertexBuffer.ExecuteInfo info = buffer.getExecuteInfo(queued.draw()); try (RenderPass pass = encoder.createRenderPass(() -> "sputnik buffers",
if (info != null) queued.type().drawFromBuffer(info); Minecraft.getInstance().gameRenderer.mainRenderTarget().getColorTextureView(),
java.util.Optional.empty(),
Minecraft.getInstance().gameRenderer.mainRenderTarget().getDepthTextureView(),
java.util.OptionalDouble.empty())) {
for (QueuedDraw queued : queue) {
StagedVertexBuffer.ExecuteInfo info = buffer.getExecuteInfo(queued.draw());
if (info != null) queued.type().drawFromBuffer(info, pass);
}
} }
encoder.submit();
queue.clear(); queue.clear();
buffer.endDraw(); buffer.endDraw();
@@ -1632,7 +1632,7 @@
"sputnik.ui.friends.title": "friends", "sputnik.ui.friends.title": "friends",
"sputnik.ui.list.tooltip": "%s (%s of %s)", "sputnik.ui.list.tooltip": "%s (%s of %s)",
"sputnik.ui.macros.empty": "no macros yet", "sputnik.ui.macros.empty": "no macros yet",
"sputnik.ui.macros.instructions": "left click: select / right click: bind / shift + right click: delete", "sputnik.ui.macros.instructions": "C: chat macro / K: keybind macro / left click: select / right click: bind / shift + right click: delete",
"sputnik.ui.macros.lineinstructions": "shift + right click on a line to remove it", "sputnik.ui.macros.lineinstructions": "shift + right click on a line to remove it",
"sputnik.ui.macros.lineplaceholder": "command or message...", "sputnik.ui.macros.lineplaceholder": "command or message...",
"sputnik.ui.macros.nameplaceholder": "macro name...", "sputnik.ui.macros.nameplaceholder": "macro name...",
@@ -1651,6 +1651,7 @@
"sputnik.ui.searchbar.placeholder": "search...", "sputnik.ui.searchbar.placeholder": "search...",
"sputnik.ui.settingsof": "%s settings", "sputnik.ui.settingsof": "%s settings",
"sputnik.ui.tab.hud": "hud", "sputnik.ui.tab.hud": "hud",
"sputnik.ui.tab.client_settings": "client settings",
"sputnik.ui.tab.macros": "macros", "sputnik.ui.tab.macros": "macros",
"sputnik.ui.tab.modules": "modules", "sputnik.ui.tab.modules": "modules",
"sputnik.ui.tab.profiles": "profiles", "sputnik.ui.tab.profiles": "profiles",
@@ -1665,5 +1666,10 @@
"sputnik.version.info.dev": "mod in a development state: v%s", "sputnik.version.info.dev": "mod in a development state: v%s",
"sputnik.version.info.uptodate": "the mod is up to date: v%s", "sputnik.version.info.uptodate": "the mod is up to date: v%s",
"sputnik.version.warn.check": "could not check whether the mod is up to date: %s", "sputnik.version.warn.check": "could not check whether the mod is up to date: %s",
"sputnik.version.warn.metadata": "could not build gradle.properties from the metadata" "sputnik.version.warn.metadata": "could not build gradle.properties from the metadata",
"sputnik.ui.friends.nickplaceholder": "nickname...",
"sputnik.ui.friends.befriendedon": "friends since %s",
"sputnik.ui.friends.removed": "you now hate %s",
"sputnik.ui.friends.empty": "you don't have any friends loser",
"sputnik.ui.friends.uuid": "UUID: %s"
} }
@@ -1632,7 +1632,7 @@
"sputnik.ui.friends.title": "amigos", "sputnik.ui.friends.title": "amigos",
"sputnik.ui.list.tooltip": "%s (%s de %s)", "sputnik.ui.list.tooltip": "%s (%s de %s)",
"sputnik.ui.macros.empty": "todavía no hay macros", "sputnik.ui.macros.empty": "todavía no hay macros",
"sputnik.ui.macros.instructions": "clic izq.: seleccionar / clic der.: asignar tecla / shift + clic der.: borrar", "sputnik.ui.macros.instructions": "C: macro de chat / K: macro de teclas / clic izq.: seleccionar / clic der.: asignar tecla / shift + clic der.: borrar",
"sputnik.ui.macros.lineinstructions": "shift + clic der. sobre una línea para quitarla", "sputnik.ui.macros.lineinstructions": "shift + clic der. sobre una línea para quitarla",
"sputnik.ui.macros.lineplaceholder": "comando o mensaje...", "sputnik.ui.macros.lineplaceholder": "comando o mensaje...",
"sputnik.ui.macros.nameplaceholder": "nombre de la macro...", "sputnik.ui.macros.nameplaceholder": "nombre de la macro...",
@@ -1651,6 +1651,7 @@
"sputnik.ui.searchbar.placeholder": "buscar...", "sputnik.ui.searchbar.placeholder": "buscar...",
"sputnik.ui.settingsof": "ajustes de %s", "sputnik.ui.settingsof": "ajustes de %s",
"sputnik.ui.tab.hud": "hud", "sputnik.ui.tab.hud": "hud",
"sputnik.ui.tab.client_settings": "ajustes",
"sputnik.ui.tab.macros": "macros", "sputnik.ui.tab.macros": "macros",
"sputnik.ui.tab.modules": "módulos", "sputnik.ui.tab.modules": "módulos",
"sputnik.ui.tab.profiles": "perfiles", "sputnik.ui.tab.profiles": "perfiles",
@@ -1665,5 +1666,10 @@
"sputnik.version.info.dev": "mod en estado de desarrollo: v%s", "sputnik.version.info.dev": "mod en estado de desarrollo: v%s",
"sputnik.version.info.uptodate": "el mod está al día: v%s", "sputnik.version.info.uptodate": "el mod está al día: v%s",
"sputnik.version.warn.check": "no se pudo comprobar si el mod está actualizado: %s", "sputnik.version.warn.check": "no se pudo comprobar si el mod está actualizado: %s",
"sputnik.version.warn.metadata": "no se pudo construir gradle.properties desde la metadata" "sputnik.version.warn.metadata": "no se pudo construir gradle.properties desde la metadata",
} "sputnik.ui.friends.nickplaceholder": "apodo...",
"sputnik.ui.friends.befriendedon": "amigos desde %s",
"sputnik.ui.friends.removed": "%s ya no es tu amigo",
"sputnik.ui.friends.empty": "no tienes amigos jajsjsjs",
"sputnik.ui.friends.uuid": "UUID: %s"
}
@@ -1,11 +1,12 @@
#version 330 #version 330
#extension GL_ARB_separate_shader_objects : require
// copia el resultado de la pasada lsd (un objetivo intermedio) de vuelta al objetivo // copia el resultado de la pasada lsd (un objetivo intermedio) de vuelta al objetivo
// principal: una pasada de post no puede leer y escribir la misma textura a la vez // principal: una pasada de post no puede leer y escribir la misma textura a la vez
uniform sampler2D InSampler; uniform sampler2D InSampler;
in vec2 texCoord; layout(location = 0) in vec2 texCoord;
out vec4 fragColor; layout(location = 0) out vec4 fragColor;
void main() { void main() {
fragColor = texture(InSampler, texCoord); fragColor = texture(InSampler, texCoord);
@@ -1,11 +1,10 @@
#version 330 #version 330
#extension GL_ARB_separate_shader_objects : require
#define M_PI 3.1415926535897932384626433832795
uniform sampler2D InSampler; uniform sampler2D InSampler;
in vec2 texCoord; layout(location = 0) in vec2 texCoord;
out vec4 fragColor; layout(location = 0) out vec4 fragColor;
layout(std140) uniform LsdConfig { layout(std140) uniform LsdConfig {
float strength; float strength;
@@ -87,32 +86,19 @@ float cnoise(vec3 P){
} }
vec3 hueShift(vec3 color, float hueAdjust){ vec3 rgbToHsv(vec3 color) {
const vec3 kRGBToYPrime = vec3(0.299, 0.587, 0.114); vec4 k = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
const vec3 kRGBToI = vec3(0.596, -0.275, -0.321); vec4 p = mix(vec4(color.bg, k.wz), vec4(color.gb, k.xy), step(color.b, color.g));
const vec3 kRGBToQ = vec3(0.212, -0.523, 0.311); vec4 q = mix(vec4(p.xyw, color.r), vec4(color.r, p.yzx), step(p.x, color.r));
float d = q.x - min(q.w, q.y);
const vec3 kYIQToR = vec3 (1.0, 0.956, 0.621); float e = 1.0e-10;
const vec3 kYIQToG = vec3 (1.0, -0.272, -0.647); return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
const vec3 kYIQToB = vec3 (1.0, -1.107, 1.704);
float YPrime = dot(color, kRGBToYPrime);
float I = dot(color, kRGBToI);
float Q = dot(color, kRGBToQ);
float hue = atan(Q, I);
float chroma = sqrt(I * I + Q * Q);
hue += hueAdjust;
Q = chroma * sin(hue);
I = chroma * cos(hue);
vec3 yIQ = vec3(YPrime, I, Q);
return vec3(dot(yIQ, kYIQToR), dot(yIQ, kYIQToG), dot(yIQ, kYIQToB));
} }
vec3 hsvToRgb(vec3 color) {
vec3 p = abs(fract(color.xxx + vec3(0.0, 2.0 / 3.0, 1.0 / 3.0)) * 6.0 - 3.0);
return color.z * mix(vec3(1.0), clamp(p - 1.0, 0.0, 1.0), color.y);
}
void main() { void main() {
vec2 oneTexel = vec2(1.0) / vec2(textureSize(InSampler, 0)); vec2 oneTexel = vec2(1.0) / vec2(textureSize(InSampler, 0));
@@ -122,5 +108,9 @@ void main() {
float c = cos(ang); float c = cos(ang);
vec2 offset = vec2(s, c) * perlin; vec2 offset = vec2(s, c) * perlin;
vec4 tex = texture(InSampler, texCoord + (offset * strength * 30.0) * oneTexel); vec4 tex = texture(InSampler, texCoord + (offset * strength * 30.0) * oneTexel);
fragColor = mix(tex, vec4(hueShift(tex.rgb, seed * 2.0 * M_PI), 1.0), strength); float hue = seed < 0.0 ? fract(texCoord.x + time * 0.08 + perlin * 0.08) : seed;
vec3 hsv = rgbToHsv(tex.rgb);
hsv.x = hue;
hsv.y = max(hsv.y, 0.65);
fragColor = vec4(mix(tex.rgb, hsvToRgb(hsv), strength), tex.a);
} }
-3
View File
@@ -34,9 +34,6 @@ accessible field net/minecraft/client/particle/Particle hasPhysics Z
# renderizado 3d # renderizado 3d
accessible method net/minecraft/client/renderer/rendertype/RenderType <init> (Ljava/lang/String;Lnet/minecraft/client/renderer/rendertype/RenderSetup;)V accessible method net/minecraft/client/renderer/rendertype/RenderType <init> (Ljava/lang/String;Lnet/minecraft/client/renderer/rendertype/RenderSetup;)V
accessible method net/minecraft/client/renderer/rendertype/RenderType create (Ljava/lang/String;Lnet/minecraft/client/renderer/rendertype/RenderSetup;)Lnet/minecraft/client/renderer/rendertype/RenderType; accessible method net/minecraft/client/renderer/rendertype/RenderType create (Ljava/lang/String;Lnet/minecraft/client/renderer/rendertype/RenderSetup;)Lnet/minecraft/client/renderer/rendertype/RenderType;
accessible field net/minecraft/client/renderer/RenderPipelines LINES_SNIPPET Lcom/mojang/blaze3d/pipeline/RenderPipeline$Snippet;
accessible field net/minecraft/client/renderer/RenderPipelines DEBUG_FILLED_SNIPPET Lcom/mojang/blaze3d/pipeline/RenderPipeline$Snippet;
accessible field net/minecraft/client/renderer/RenderPipelines GUI_TEXTURED_SNIPPET Lcom/mojang/blaze3d/pipeline/RenderPipeline$Snippet;
# pantallas # pantallas
accessible field net/minecraft/client/gui/screens/inventory/AbstractContainerScreen imageWidth I accessible field net/minecraft/client/gui/screens/inventory/AbstractContainerScreen imageWidth I
+2 -3
View File
@@ -81,11 +81,10 @@
"mixins.render.EntityRenderDispatcherMixin", "mixins.render.EntityRenderDispatcherMixin",
"mixins.render.EntityRenderStateMixin", "mixins.render.EntityRenderStateMixin",
"mixins.render.EquipmentLayerRendererMixin", "mixins.render.EquipmentLayerRendererMixin",
"mixins.render.ItemFeatureRendererMixin",
"mixins.render.FogRendererMixin", "mixins.render.FogRendererMixin",
"mixins.render.FontMixin", "mixins.render.FontMixin",
"mixins.render.GameRendererMixin", "mixins.render.GameRendererMixin",
"mixins.render.ItemFeatureRendererMixin",
"mixins.render.ItemInHandRendererMixin",
"mixins.render.LevelRendererMixin", "mixins.render.LevelRendererMixin",
"mixins.render.LightmapMixin", "mixins.render.LightmapMixin",
"mixins.render.LightmapRenderStateExtractorMixin", "mixins.render.LightmapRenderStateExtractorMixin",
@@ -115,4 +114,4 @@
"mixins.world.TrackingEmitterMixin", "mixins.world.TrackingEmitterMixin",
"mixins.world.VisGraphMixin" "mixins.world.VisGraphMixin"
] ]
} }