This commit is contained in:
retuci0 committed 2026-05-10 10:54:59 +02:00
1 parent 321505657c
commit 957fab15aa
20 files changed
+279 -129

No files matched your search

+5 -6
View File
@@ -1,4 +1,4 @@
# v5.1 # v5.2
## novedades ## novedades
@@ -8,12 +8,11 @@
### arreglos / mejoras ### arreglos / mejoras
- añadido el grupo de ajustes `módulo` para distinguir los ajustes individuales de cada módulo con los comunes; - `andamios` ya funciona correctamente
y añadido la opción de notificar el alternado de estado de un módulo mediante widgets de notificaciones - autoguardado cada cierto intervalo de tiempo en vez de guardar inmediatamente tras cada cambio en los ajustes, por optimización
- varios arreglos relacionados con la config. - el guardado se realiza desde otro hilo ahora, para evitar que el I/O bloque el hilo principal
- cambiado `manos` de categoría: de "jugador" a "renderizado"
- `don quijote` ya funciona correctamente, en cuanto a los amigos
## problemas reconocidos ## problemas reconocidos
- lo de siempre. - lo de siempre.
- el ítem del tótem no se renderiza en el editor del HUD si es abierto en la pantalla de inicio
+1 -1
View File
@@ -10,6 +10,6 @@ discord_rpc_version=1.0.3
neutrino_version=1.1.0 neutrino_version=1.1.0
jdk_version=25 jdk_version=25
mod_version=5.1 mod_version=5.2
maven_group=me.retucio maven_group=me.retucio
archives_base_name=sputnik archives_base_name=sputnik
+14 -7
View File
@@ -83,7 +83,9 @@ public class Sputnik implements ClientModInitializer {
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
mc = Minecraft.getInstance(); mc = Minecraft.getInstance();
ConfigManager.load();
ConfigManager.INSTANCE = new ConfigManager();
ConfigManager.INSTANCE.load();
VersionChecker.INSTANCE.check(); VersionChecker.INSTANCE.check();
@@ -101,6 +103,8 @@ public class Sputnik implements ClientModInitializer {
Lists.init(); Lists.init();
HudRenderer.INSTANCE = new HudRenderer();
CapeManager.INSTANCE = new CapeManager(); CapeManager.INSTANCE = new CapeManager();
EVENT_BUS.post(new LoadCapeManagerEvent()); EVENT_BUS.post(new LoadCapeManagerEvent());
@@ -120,7 +124,7 @@ public class Sputnik implements ClientModInitializer {
HudEditorScreen.INSTANCE = new HudEditorScreen(); HudEditorScreen.INSTANCE = new HudEditorScreen();
EVENT_BUS.post(new LoadClickGuiEvent()); EVENT_BUS.post(new LoadClickGuiEvent());
HudRenderer.init(); HudRenderer.INSTANCE.init();
}); });
Runtime.getRuntime().addShutdownHook(new Thread(() -> { Runtime.getRuntime().addShutdownHook(new Thread(() -> {
@@ -131,14 +135,16 @@ public class Sputnik implements ClientModInitializer {
// se ejecuta cada tick, es decir, 20 veces por segundo // se ejecuta cada tick, es decir, 20 veces por segundo
public void onTick() { public void onTick() {
if (!settingsApplied if (!settingsApplied
&& ConfigManager.getConfig() != null && ConfigManager.INSTANCE.getConfig() != null
&& !ConfigManager.hasLoaded()) { && !ConfigManager.INSTANCE.hasLoaded()) {
ConfigManager.applyConfig(); ConfigManager.INSTANCE.applyConfig();
settingsApplied = true; settingsApplied = true;
} }
ModuleManager.INSTANCE.getEnabledModules().forEach(Module::onTick); ModuleManager.INSTANCE.getEnabledModules().forEach(Module::onTick);
mc.getWindow().setTitle(ClientSettingsPanel.clientSettings.windowTitle.getValue()); mc.getWindow().setTitle(ClientSettingsPanel.clientSettings.windowTitle.getValue());
ConfigManager.INSTANCE.tickAutosave();
} }
@@ -180,7 +186,8 @@ public class Sputnik implements ClientModInitializer {
if (mc.screen != null && mc.screen != ClickGui.INSTANCE) return; if (mc.screen != null && mc.screen != ClickGui.INSTANCE) return;
for (Module module : ModuleManager.INSTANCE.getModules()) { for (Module module : ModuleManager.INSTANCE.getModules()) {
if (key != module.getKey() || anyFocused || KeyUtil.isKeyDown(GLFW.GLFW_KEY_F3)) continue; // 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 (module.shouldToggleOnBindRelease() && !module.isEnabled()) if (module.shouldToggleOnBindRelease() && !module.isEnabled())
module.setEnabled(true); module.setEnabled(true);
@@ -259,7 +266,7 @@ public class Sputnik implements ClientModInitializer {
@EventListener @EventListener
public void onStop(ShutdownEvent event) { public void onStop(ShutdownEvent event) {
ConfigManager.save(); ConfigManager.INSTANCE.saveOnShutdown();
} }
public static String getVersionName() { public static String getVersionName() {
@@ -2,6 +2,8 @@ package me.retucio.sputnik.config;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -21,33 +23,60 @@ 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;
public static void writeConfig(ClientConfig config, File file) public static void writeConfig(ClientConfig config, File file) throws IOException {
throws IOException { byte[] bytes = toBytes(config);
try (DataOutputStream out = new DataOutputStream( writeBytes(bytes, file);
new BufferedOutputStream(new FileOutputStream(file)))) { }
// cabezal // serializar a bytes en memoria
out.writeInt(MAGIC_NUMBER); public static byte[] toBytes(ClientConfig config) throws IOException {
out.writeInt(VERSION); ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (DataOutputStream out = new DataOutputStream(baos)) {
writeConfigTo(config, out);
}
return baos.toByteArray();
}
// mapas // escribir bytes a disco (puede llamarse desde un hilo de fondo)
writeStringBooleanMap(out, config.moduleStates); public static void writeBytes(byte[] bytes, File file) throws IOException {
writeSettingsMap(out, config.settings); // escribir a archivo temporal primero para evitar corrupción si el proceso muere a mitad
writeStringIntArrayMap(out, config.settingsPanels); File temp = new File(file.getParent(), file.getName() + ".tmp");
writeExtendableFrames(out, config.extendablePanels); try (FileOutputStream fos = new FileOutputStream(temp);
writeStringIntArrayMap(out, config.hudPositions); BufferedOutputStream out = new BufferedOutputStream(fos)) {
writeStringBooleanMap(out, config.hudVisibilities); out.write(bytes);
writeStringStringMap(out, config.hudImagePaths); out.flush();
writeStringStringMap(out, config.friends); fos.getFD().sync(); // forzar flush al disco antes de renombrar
}
// posición de la barra de búsqueda // renombrar atómicamente
if (config.searchBarPosition != null) { if (!temp.renameTo(file)) {
out.writeBoolean(true); // renameTo puede fallar entre sistemas de archivos distintos
out.writeInt(config.searchBarPosition[0]); Files.move(temp.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
out.writeInt(config.searchBarPosition[1]); }
} else { }
out.writeBoolean(false);
} // lógica de serialización compartida
private static void writeConfigTo(ClientConfig config, DataOutputStream out) throws IOException {
// cabezal
out.writeInt(MAGIC_NUMBER);
out.writeInt(VERSION);
// el resto
writeStringBooleanMap(out, config.moduleStates);
writeSettingsMap(out, config.settings);
writeStringIntArrayMap(out, config.settingsPanels);
writeExtendableFrames(out, config.extendablePanels);
writeStringIntArrayMap(out, config.hudPositions);
writeStringBooleanMap(out, config.hudVisibilities);
writeStringStringMap(out, config.hudImagePaths);
writeStringStringMap(out, config.friends);
if (config.searchBarPosition != null) {
out.writeBoolean(true);
out.writeInt(config.searchBarPosition[0]);
out.writeInt(config.searchBarPosition[1]);
} else {
out.writeBoolean(false);
} }
} }
@@ -53,7 +53,7 @@ public class ClientConfig {
@EventListener @EventListener
public void onToggleModule(ToggleModuleEvent event) { public void onToggleModule(ToggleModuleEvent event) {
ConfigManager.setModuleState(event.getModule()); ConfigManager.INSTANCE.setModuleState(event.getModule());
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@@ -75,24 +75,24 @@ public class ClientConfig {
default: break; default: break;
} }
ConfigManager.setSetting(event.getSetting(), value); ConfigManager.INSTANCE.setSetting(event.getSetting(), value);
} }
@EventListener @EventListener
public void onOpenSettingsPanel(SettingsPanelEvent.Open event) { public void onOpenSettingsPanel(SettingsPanelEvent.Open event) {
ConfigManager.setPanelPosition(event.getPanel()); ConfigManager.INSTANCE.setPanelPosition(event.getPanel());
} }
@EventListener @EventListener
public void onCloseSettingsPanel(SettingsPanelEvent.Close event) { public void onCloseSettingsPanel(SettingsPanelEvent.Close event) {
settingsPanels.remove(event.getPanel().getModule().getName()); settingsPanels.remove(event.getPanel().getModule().getName());
ConfigManager.save(); ConfigManager.INSTANCE.markDirty();
} }
@EventListener @EventListener
public void onMoveSettingsPanel(SettingsPanelEvent.Move event) { public void onMoveSettingsPanel(SettingsPanelEvent.Move event) {
settingsPanels.replace(event.getPanel().getModule().getName(), new int[]{event.getPanel().getX(), event.getPanel().getY()}); settingsPanels.replace(event.getPanel().getModule().getName(), new int[]{event.getPanel().getX(), event.getPanel().getY()});
ConfigManager.save(); ConfigManager.INSTANCE.markDirty();
} }
@EventListener @EventListener
@@ -101,7 +101,7 @@ public class ClientConfig {
event.getPanel().getX(), event.getPanel().getX(),
event.getPanel().getY(), event.getPanel().getY(),
event.getPanel().isExtended())); event.getPanel().isExtended()));
ConfigManager.save(); ConfigManager.INSTANCE.markDirty();
} }
@EventListener @EventListener
@@ -110,7 +110,7 @@ public class ClientConfig {
event.getPanel().getX(), event.getPanel().getX(),
event.getPanel().getY(), event.getPanel().getY(),
event.getPanel().isExtended())); event.getPanel().isExtended()));
ConfigManager.save(); ConfigManager.INSTANCE.markDirty();
} }
@EventListener @EventListener
@@ -119,7 +119,7 @@ public class ClientConfig {
ClickGui.INSTANCE.getClientSettingsPanel().getX(), ClickGui.INSTANCE.getClientSettingsPanel().getX(),
ClickGui.INSTANCE.getClientSettingsPanel().getY(), ClickGui.INSTANCE.getClientSettingsPanel().getY(),
ClickGui.INSTANCE.getClientSettingsPanel().isExtended())); ClickGui.INSTANCE.getClientSettingsPanel().isExtended()));
ConfigManager.save(); ConfigManager.INSTANCE.markDirty();
} }
@EventListener @EventListener
@@ -128,7 +128,7 @@ public class ClientConfig {
ClickGui.INSTANCE.getClientSettingsPanel().getX(), ClickGui.INSTANCE.getClientSettingsPanel().getX(),
ClickGui.INSTANCE.getClientSettingsPanel().getY(), ClickGui.INSTANCE.getClientSettingsPanel().getY(),
ClickGui.INSTANCE.getClientSettingsPanel().isExtended())); ClickGui.INSTANCE.getClientSettingsPanel().isExtended()));
ConfigManager.save(); ConfigManager.INSTANCE.markDirty();
} }
@EventListener @EventListener
@@ -137,7 +137,7 @@ public class ClientConfig {
ClickGui.INSTANCE.getFriendsPanel().getX(), ClickGui.INSTANCE.getFriendsPanel().getX(),
ClickGui.INSTANCE.getFriendsPanel().getY(), ClickGui.INSTANCE.getFriendsPanel().getY(),
ClickGui.INSTANCE.getFriendsPanel().isExtended())); ClickGui.INSTANCE.getFriendsPanel().isExtended()));
ConfigManager.save(); ConfigManager.INSTANCE.markDirty();
} }
@EventListener @EventListener
@@ -146,7 +146,7 @@ public class ClientConfig {
ClickGui.INSTANCE.getFriendsPanel().getX(), ClickGui.INSTANCE.getFriendsPanel().getX(),
ClickGui.INSTANCE.getFriendsPanel().getY(), ClickGui.INSTANCE.getFriendsPanel().getY(),
ClickGui.INSTANCE.getFriendsPanel().isExtended())); ClickGui.INSTANCE.getFriendsPanel().isExtended()));
ConfigManager.save(); ConfigManager.INSTANCE.markDirty();
} }
@EventListener @EventListener
@@ -156,12 +156,13 @@ public class ClientConfig {
if (!friends.containsKey(uuid)) { if (!friends.containsKey(uuid)) {
friends.put(uuid, name); friends.put(uuid, name);
} }
ConfigManager.save(); ConfigManager.INSTANCE.markDirty();
} }
@EventListener @EventListener
public void onRemoveFriend(FriendEvent.Remove event) { public void onRemoveFriend(FriendEvent.Remove event) {
friends.remove(event.getFriend().getUuid().toString()); friends.remove(event.getFriend().getUuid().toString());
ConfigManager.save(); 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 {
@@ -7,14 +7,17 @@ import me.retucio.sputnik.friend.Friend;
import me.retucio.sputnik.friend.FriendManager; import me.retucio.sputnik.friend.FriendManager;
import me.retucio.sputnik.module.Module; import me.retucio.sputnik.module.Module;
import me.retucio.sputnik.module.ModuleManager; import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.client.ClientSettingsModule;
import me.retucio.sputnik.module.setting.*; import me.retucio.sputnik.module.setting.*;
import me.retucio.sputnik.module.setting.settings.*; import me.retucio.sputnik.module.setting.settings.*;
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.FriendsPanel; 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 java.io.File; import java.io.File;
import java.io.FileReader; import java.io.FileReader;
@@ -22,6 +25,10 @@ import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer; import java.util.function.Consumer;
// se ocupa de guardar, cargar y aplicar ajustes // se ocupa de guardar, cargar y aplicar ajustes
@@ -30,26 +37,70 @@ public class ConfigManager {
private static final File CONFIG_FILE = new File("sputnik.dat"); private static final File CONFIG_FILE = new File("sputnik.dat");
private static final File LEGACY_JSON_FILE = new File("sputnik.json"); private static final File LEGACY_JSON_FILE = new File("sputnik.json");
private static boolean loaded = false; public static ConfigManager INSTANCE;
private static ClientConfig config = null;
private boolean loaded = false;
private boolean dirty = false;
private long lastDirtyTime = 0L;
private ClientConfig config = null;
private final ExecutorService saveExecutor = Executors.newSingleThreadExecutor(r -> {
Thread t = new Thread(r, "sputnik-config-save");
t.setDaemon(true); // no bloquear el cierre de la JVM
return t;
});
private final AtomicBoolean saveQueued = new AtomicBoolean(false);
// ------------------ MÉTODOS PRINCIPALES ------------------ // ------------------ MÉTODOS PRINCIPALES ------------------
// guardar configuraciones // guardar configuraciones
public static void save() { public void save() {
if (!loaded) return; if (!loaded) return;
ensureConfig(); ensureConfig();
// serializar a bytes en el hilo principal (snapshot inmediato, evita race conditions)
final byte[] snapshot;
try { try {
BinarySerializer.writeConfig(config, CONFIG_FILE); snapshot = BinarySerializer.toBytes(config);
Sputnik.LOGGER.info("ajustes guardados");
} catch (IOException e) { } catch (IOException e) {
Sputnik.LOGGER.error("error al guardar ajustes", e); Sputnik.LOGGER.error("error al serializar ajustes", e);
return;
} }
// si ya hay un guardado en cola, no añadir otro
if (!saveQueued.compareAndSet(false, true)) return;
saveExecutor.execute(() -> {
try {
BinarySerializer.writeBytes(snapshot, CONFIG_FILE);
Sputnik.LOGGER.info("ajustes guardados");
} catch (IOException e) {
Sputnik.LOGGER.error("error al guardar ajustes", e);
} finally {
saveQueued.set(false);
}
});
} }
public static void load() { public void saveOnShutdown() {
// esperar a que termine cualquier guardado en curso, luego guardar síncronamente
saveExecutor.shutdown();
try {
// dar hasta 5 segundos para que termine el guardado en curso
if (!saveExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
Sputnik.LOGGER.warn("el hilo de guardado no terminó a tiempo");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// guardado final sincrónico por si había cambios pendientes no guardados
if (dirty) save();
}
public void load() {
Sputnik.LOGGER.info("cargando ajustes..."); Sputnik.LOGGER.info("cargando ajustes...");
if (CONFIG_FILE.exists()) { if (CONFIG_FILE.exists()) {
@@ -82,7 +133,7 @@ public class ConfigManager {
} }
// aplicar configuraciones cargadas // aplicar configuraciones cargadas
public static void applyConfig() { public void applyConfig() {
if (!shouldApply()) return; if (!shouldApply()) return;
applyModuleStates(); applyModuleStates();
@@ -98,7 +149,7 @@ public class ConfigManager {
} }
// obtener configuración actual // obtener configuración actual
public static ClientConfig getConfig() { public ClientConfig getConfig() {
ensureConfig(); ensureConfig();
return config; return config;
} }
@@ -106,65 +157,65 @@ public class ConfigManager {
// ------------------ GUARDAR VALORES INDIVIDUALES EN LA CONFIG. ------------------ // ------------------ GUARDAR VALORES INDIVIDUALES EN LA CONFIG. ------------------
public static void setModuleState(Module module) { public void setModuleState(Module module) {
ensureConfig(); ensureConfig();
config.moduleStates.put(module.getName(), module.isEnabled()); config.moduleStates.put(module.getName(), module.isEnabled());
save(); markDirty();
} }
public static void setSetting(Setting<?> setting, Object value) { public void setSetting(Setting<?> setting, Object value) {
ensureConfig(); ensureConfig();
config.settings.put(getSettingKey(setting), value); config.settings.put(getSettingKey(setting), value);
save(); markDirty();
} }
public static void setPanelPosition(SettingsPanel panel) { public void setPanelPosition(SettingsPanel panel) {
ensureConfig(); ensureConfig();
if (!config.settingsPanels.containsKey(panel.getModule().getName())) if (!config.settingsPanels.containsKey(panel.getModule().getName()))
config.settingsPanels.put(panel.getModule().getName(), new int[] {panel.getX(), panel.getY()}); config.settingsPanels.put(panel.getModule().getName(), new int[] {panel.getX(), panel.getY()});
else else
config.settingsPanels.replace(panel.getModule().getName(), new int[] {panel.getX(), panel.getY()}); config.settingsPanels.replace(panel.getModule().getName(), new int[] {panel.getX(), panel.getY()});
save(); markDirty();
} }
public static void setExtendablePanel(String key, ClientConfig.PanelData data) { public void setExtendablePanel(String key, ClientConfig.PanelData data) {
ensureConfig(); ensureConfig();
config.extendablePanels.put(key, data); config.extendablePanels.put(key, data);
save(); markDirty();
} }
public static void setHudPosition(String id, int x, int y) { public void setHudPosition(String id, int x, int y) {
ensureConfig(); ensureConfig();
config.hudPositions.put(id, new int[] {x, y}); config.hudPositions.put(id, new int[] {x, y});
save(); markDirty();
} }
public static void setHudVisibility(String id, Boolean visible) { public void setHudVisibility(String id, Boolean visible) {
ensureConfig(); ensureConfig();
config.hudVisibilities.put(id, visible); config.hudVisibilities.put(id, visible);
save(); markDirty();
} }
public static void setSearchBarPosition(int x, int y) { public void setSearchBarPosition(int x, int y) {
ensureConfig(); ensureConfig();
config.searchBarPosition = new int[] {x, y}; config.searchBarPosition = new int[] {x, y};
save(); markDirty();
} }
// ------------------ APLICAR AJUSTES ------------------ // ------------------ APLICAR AJUSTES ------------------
public static void applyFriends() { public void applyFriends() {
Sputnik.LOGGER.info("aplicando amigos: {}", config.friends);
config.friends.forEach((uuid, name) -> { config.friends.forEach((uuid, name) -> {
Friend friend = new Friend(UUID.fromString(uuid)); Friend friend = new Friend(UUID.fromString(uuid));
friend.setName(name); friend.setName(name);
FriendManager.INSTANCE.add(friend); FriendManager.INSTANCE.add(friend);
}); });
Sputnik.LOGGER.info("amigos aplicados");
} }
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
public static void applySetting(Setting<?> setting) { public void applySetting(Setting<?> setting) {
String key = getSettingKey(setting); String key = getSettingKey(setting);
if (!config.settings.containsKey(key)) return; if (!config.settings.containsKey(key)) return;
@@ -184,7 +235,7 @@ public class ConfigManager {
} }
} }
private static void applyModuleStates() { private void applyModuleStates() {
ModuleManager.INSTANCE.getModules().forEach(module -> { ModuleManager.INSTANCE.getModules().forEach(module -> {
if (config.moduleStates.containsKey(module.getName())) { if (config.moduleStates.containsKey(module.getName())) {
module.setEnabled(config.moduleStates.get(module.getName())); module.setEnabled(config.moduleStates.get(module.getName()));
@@ -193,14 +244,14 @@ public class ConfigManager {
Sputnik.LOGGER.info("estados de módulos aplicados"); Sputnik.LOGGER.info("estados de módulos aplicados");
} }
private static void applyModuleSettings() { private void applyModuleSettings() {
ModuleManager.INSTANCE.getModules().forEach(module -> { ModuleManager.INSTANCE.getModules().forEach(module -> {
module.getSettings().forEach(ConfigManager::applySetting); module.getSettings().forEach(this::applySetting);
}); });
Sputnik.LOGGER.info("ajustes de módulos aplicados"); Sputnik.LOGGER.info("ajustes de módulos aplicados");
} }
private static void applySettingsPanels() { private void applySettingsPanels() {
config.settingsPanels.forEach((moduleName, position) -> { config.settingsPanels.forEach((moduleName, position) -> {
Module module = ModuleManager.INSTANCE.getModuleByName(moduleName); Module module = ModuleManager.INSTANCE.getModuleByName(moduleName);
@@ -215,7 +266,7 @@ public class ConfigManager {
Sputnik.LOGGER.info("estados de marcos de ajustes aplicados"); Sputnik.LOGGER.info("estados de marcos de ajustes aplicados");
} }
private static void applySearchBarPosition() { private void applySearchBarPosition() {
if (config.searchBarPosition != null && config.searchBarPosition.length == 2) { if (config.searchBarPosition != null && config.searchBarPosition.length == 2) {
ClickGui.INSTANCE.getSearchBar().setX(config.searchBarPosition[0]); ClickGui.INSTANCE.getSearchBar().setX(config.searchBarPosition[0]);
ClickGui.INSTANCE.getSearchBar().setY(config.searchBarPosition[1]); ClickGui.INSTANCE.getSearchBar().setY(config.searchBarPosition[1]);
@@ -223,13 +274,13 @@ public class ConfigManager {
Sputnik.LOGGER.info("posición de la barra de búsqueda aplicada"); Sputnik.LOGGER.info("posición de la barra de búsqueda aplicada");
} }
private static void applyClientSettings() { private void applyClientSettings() {
ClientSettingsPanel.clientSettings.setEnabled(true); ClientSettingsPanel.clientSettings.setEnabled(true);
ClientSettingsPanel.clientSettings.getSettings().forEach(ConfigManager::applySetting); ClientSettingsPanel.clientSettings.getSettings().forEach(this::applySetting);
Sputnik.LOGGER.info("ajustes del cliente aplicados"); Sputnik.LOGGER.info("ajustes del cliente aplicados");
} }
private static void applyExtendablePanels() { private void applyExtendablePanels() {
for (ModulePanel panel : ClickGui.INSTANCE.getModulePanels()) { for (ModulePanel panel : ClickGui.INSTANCE.getModulePanels()) {
applyExtendablePanel(panel); applyExtendablePanel(panel);
} }
@@ -240,7 +291,7 @@ public class ConfigManager {
ClickGui.INSTANCE.refreshListButtons(); ClickGui.INSTANCE.refreshListButtons();
} }
private static void applyExtendablePanel(Panel<?> panel) { private void applyExtendablePanel(Panel<?> panel) {
ClientConfig.PanelData panelData = null; ClientConfig.PanelData panelData = null;
if (panel instanceof ModulePanel mp) { if (panel instanceof ModulePanel mp) {
@@ -359,19 +410,42 @@ public class ConfigManager {
// ------------------ MÉTODOS DE AYUDA ------------------ // ------------------ MÉTODOS DE AYUDA ------------------
private static boolean shouldApply() {
return Sputnik.mc != null && ModuleManager.INSTANCE != null && config != null;
}
private static void ensureConfig() {
if (config == null) config = new ClientConfig();
}
private static String getSettingKey(Setting<?> setting) { private static String getSettingKey(Setting<?> setting) {
return setting.getSg().getModule().getName() + ":" + setting.getTrueName(); return setting.getSg().getModule().getName() + ":" + setting.getTrueName();
} }
public static boolean hasLoaded() { private boolean shouldApply() {
return Sputnik.mc != null && ModuleManager.INSTANCE != null && config != null;
}
private void ensureConfig() {
if (config == null) config = new ClientConfig();
}
public boolean hasLoaded() {
return loaded; return loaded;
} }
public void markDirty() {
this.dirty = true;
this.lastDirtyTime = System.currentTimeMillis();
}
public boolean isDirty() {
return dirty;
}
public void tickAutosave() {
if (!loaded || !dirty) return;
ClientSettingsModule settings = ClientSettingsPanel.clientSettings;
if (!settings.autosave.getValue()) return;
long intervalMs = (long) (settings.autosaveInterval.getValue() * 1000);
if (System.currentTimeMillis() - lastDirtyTime < intervalMs) return;
HudRenderer.INSTANCE.pushNotification("autoguardando...", "guardando configuración...");
save();
dirty = false;
}
} }
@@ -79,7 +79,7 @@ public abstract class GuiMixin {
@Inject(method = "extractRenderState", at = @At("RETURN")) @Inject(method = "extractRenderState", at = @At("RETURN"))
private void renderHUD(GuiGraphicsExtractor gui, DeltaTracker dt, CallbackInfo ci) { private void renderHUD(GuiGraphicsExtractor gui, DeltaTracker dt, CallbackInfo ci) {
HudRenderer.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/blaze3d/pipeline/RenderPipeline;Lnet/minecraft/resources/Identifier;IIII)V", ordinal = 0))
@@ -28,7 +28,7 @@ public class ScreenMixin {
@Inject(method = "extractRenderState", at = @At("HEAD")) @Inject(method = "extractRenderState", at = @At("HEAD"))
private void renderWatermark(GuiGraphicsExtractor gui, int mouseX, int mouseY, float a, CallbackInfo ci) { private void renderWatermark(GuiGraphicsExtractor gui, int mouseX, int mouseY, float a, CallbackInfo ci) {
if (!ConfigManager.hasLoaded()) return; // para evitar dibujar la marca de agua por defecto if (!ConfigManager.INSTANCE.hasLoaded()) return; // para evitar dibujar la marca de agua por defecto
String watermark = ClientSettingsPanel.clientSettings.watermark.getValue(); String watermark = ClientSettingsPanel.clientSettings.watermark.getValue();
if (watermark == null || watermark.isEmpty()) return; if (watermark == null || watermark.isEmpty()) return;
gui.text(mc.font, watermark, gui.text(mc.font, watermark,
@@ -79,7 +79,7 @@ public class Module {
this.bind.setDefaultValue(key); this.bind.setDefaultValue(key);
// puto marcos // puto marcos
if (ConfigManager.getConfig().settings if (ConfigManager.INSTANCE.getConfig().settings
.get(this.getName() + ":" + bind.getName()) == null) .get(this.getName() + ":" + bind.getName()) == null)
this.bind.setValue(key); this.bind.setValue(key);
} }
@@ -136,7 +136,7 @@ public class Module {
public void onEnable() { public void onEnable() {
if (notify.getValue()) { if (notify.getValue()) {
if (notifyMode.is(NotifyMode.CHAT)) ChatUtil.info(getName() + " fue activado"); if (notifyMode.is(NotifyMode.CHAT)) ChatUtil.info(getName() + " fue activado");
else HudRenderer.pushNotification(getName() + " fue activado", getName() + "fue activado."); else HudRenderer.INSTANCE.pushNotification(getName() + " fue activado", getName() + " fue activado.");
} }
for (Method method : getClass().getDeclaredMethods()) { for (Method method : getClass().getDeclaredMethods()) {
if (method.isAnnotationPresent(EventListener.class)) { if (method.isAnnotationPresent(EventListener.class)) {
@@ -148,7 +148,7 @@ public class Module {
public void onDisable() { public void onDisable() {
if (notifyMode.is(NotifyMode.CHAT)) ChatUtil.info(getName() + " fue desactivado"); if (notifyMode.is(NotifyMode.CHAT)) ChatUtil.info(getName() + " fue desactivado");
else HudRenderer.pushNotification(getName() + " fue desactivado", getName() + "fue desactivado."); else HudRenderer.INSTANCE.pushNotification(getName() + " fue desactivado", getName() + " fue desactivado.");
if (Sputnik.EVENT_BUS.isSubscribed(this)) { if (Sputnik.EVENT_BUS.isSubscribed(this)) {
Sputnik.EVENT_BUS.unsubscribe(this); Sputnik.EVENT_BUS.unsubscribe(this);
} }
@@ -110,6 +110,22 @@ public class ClientSettingsModule extends Module {
50 50
)); ));
public final BooleanSetting autosave = sgMisc.add(new BooleanSetting(
"autoguardado",
"autoguardar ajustes cada cierto intervalo de tiempo",
true
));
public final NumberSetting autosaveInterval = sgMisc.add(new NumberSetting(
"intervalo de autoguardado",
"cada cuántos segundos autoguardar",
120,
1,
1000,
1
)).visibility(autosave::getValue);
public ClientSettingsModule() { public ClientSettingsModule() {
super("interfaz", super("interfaz",
"ajustes de la interfaz, y otros misceláneos", "ajustes de la interfaz, y otros misceláneos",
@@ -134,7 +134,7 @@ public class Hud extends Module {
); );
dyno.onUpdate(v -> { dyno.onUpdate(v -> {
DynoElement element = (DynoElement) HudRenderer.getElement(DynoElement.class); DynoElement element = (DynoElement) HudRenderer.INSTANCE.getElement(DynoElement.class);
if (element != null) element.reloadTexture(); if (element != null) element.reloadTexture();
}); });
} }
@@ -194,7 +194,7 @@ public class Notifications extends Module {
// enviar una notificación // enviar una notificación
private void push(String title, String desc) { private void push(String title, String desc) {
if (popup.getValue()) { if (popup.getValue()) {
HudRenderer.pushNotification(title, desc); HudRenderer.INSTANCE.pushNotification(title, desc);
} }
if (sound.getValue() != SoundEvents.EMPTY) { if (sound.getValue() != SoundEvents.EMPTY) {
mc.level.playSound(mc.player, mc.player.blockPosition(), mc.level.playSound(mc.player, mc.player.blockPosition(),
@@ -330,11 +330,10 @@ public class Scaffold extends Module {
mc.player.getInventory().setSelectedSlot(slot); mc.player.getInventory().setSelectedSlot(slot);
} }
// colocar bloque // colocar bloque
if (NetworkUtil.placeBlock( if (NetworkUtil.placeBlock(
pos, InteractionHand.MAIN_HAND, pos, InteractionHand.MAIN_HAND,
mc.player.getInventory().getSelectedSlot(), slot,
rotate.getValue(), rotate.getValue(),
rotate.getValue(), rotate.getValue(),
swingHand.getValue(), swingHand.getValue(),
@@ -186,9 +186,9 @@ public class HudEditorScreen extends Screen {
} }
private void saveElementToConfig(HudElement element) { private void saveElementToConfig(HudElement element) {
ConfigManager.setHudPosition(element.getId(), element.getX(), element.getY()); ConfigManager.INSTANCE.setHudPosition(element.getId(), element.getX(), element.getY());
ConfigManager.setHudVisibility(element.getId(), element.isVisible()); ConfigManager.INSTANCE.setHudVisibility(element.getId(), element.isVisible());
ConfigManager.save(); ConfigManager.INSTANCE.save();
} }
private void saveAllElementsToConfig() { private void saveAllElementsToConfig() {
@@ -22,16 +22,18 @@ public class HudRenderer {
private static final Minecraft mc = Minecraft.getInstance(); private static final Minecraft mc = Minecraft.getInstance();
private static final List<HudElement> elements = new ArrayList<>(); public static HudRenderer INSTANCE;
private static final Stack<NotificationWidget> notifications = new Stack<>();
private static boolean initialized = false;
public static void init() { private final List<HudElement> elements = new ArrayList<>();
private final Stack<NotificationWidget> notifications = new Stack<>();
private boolean initialized = false;
public void init() {
if (initialized) return; if (initialized) return;
initialized = true; initialized = true;
Map<String, int[]> positions = ConfigManager.getConfig().hudPositions; Map<String, int[]> positions = ConfigManager.INSTANCE.getConfig().hudPositions;
Map<String, Boolean> visibilities = ConfigManager.getConfig().hudVisibilities; Map<String, Boolean> visibilities = ConfigManager.INSTANCE.getConfig().hudVisibilities;
addElement(new CoordsElement(), positions, visibilities); addElement(new CoordsElement(), positions, visibilities);
addElement(new FpsElement(), positions, visibilities); addElement(new FpsElement(), positions, visibilities);
@@ -49,7 +51,7 @@ public class HudRenderer {
HudEditorScreen.INSTANCE.setElements(elements); HudEditorScreen.INSTANCE.setElements(elements);
} }
private static void addElement(HudElement element, Map<String, int[]> positions, Map<String, Boolean> visibilities) { private void addElement(HudElement element, Map<String, int[]> positions, Map<String, Boolean> visibilities) {
int[] savedPos; int[] savedPos;
if (positions.get(element.getId()) == null) if (positions.get(element.getId()) == null)
@@ -68,7 +70,7 @@ public class HudRenderer {
elements.add(element); elements.add(element);
} }
public static HudElement getElement(Class<? extends HudElement> clazz) { public HudElement getElement(Class<? extends HudElement> clazz) {
for (HudElement element : elements) { for (HudElement element : elements) {
if (element.getClass() == clazz) if (element.getClass() == clazz)
return element; return element;
@@ -82,7 +84,7 @@ public class HudRenderer {
return hud.color.getValue(); return hud.color.getValue();
} }
public static void drawSnappedText(GuiGraphicsExtractor gui, String text, int x, int y, int color, boolean shadow) { public void drawSnappedText(GuiGraphicsExtractor gui, String text, int x, int y, int color, boolean shadow) {
int textWidth = mc.font.width(text); int textWidth = mc.font.width(text);
int screenWidth = mc.getWindow().getGuiScaledWidth(); int screenWidth = mc.getWindow().getGuiScaledWidth();
int screenHeight = mc.getWindow().getGuiScaledHeight(); int screenHeight = mc.getWindow().getGuiScaledHeight();
@@ -96,7 +98,7 @@ public class HudRenderer {
gui.text(mc.font, text, drawX, y, color, shadow); gui.text(mc.font, text, drawX, y, color, shadow);
} }
public static void render(GuiGraphicsExtractor gui, DeltaTracker dt) { public void render(GuiGraphicsExtractor gui, DeltaTracker dt) {
Hud hud = ModuleManager.INSTANCE.getModuleByClass(Hud.class); Hud hud = ModuleManager.INSTANCE.getModuleByClass(Hud.class);
for (HudElement element : elements) { for (HudElement element : elements) {
@@ -129,11 +131,11 @@ public class HudRenderer {
|| mc.screen instanceof HudEditorScreen; || mc.screen instanceof HudEditorScreen;
} }
public static void pushNotification(String title, String desc) { public void pushNotification(String title, String desc) {
notifications.push(new NotificationWidget(title, desc)); notifications.push(new NotificationWidget(title, desc));
} }
public static List<HudElement> getElements() { public List<HudElement> getElements() {
return elements; return elements;
} }
} }
@@ -19,7 +19,7 @@ public abstract class TextHudElement extends HudElement {
String text = getText(delta, hud); String text = getText(delta, hud);
int color = hud != null ? hud.color.getValue().getRGB() : -1; int color = hud != null ? hud.color.getValue().getRGB() : -1;
boolean shadow = hud != null && hud.shadow.getValue(); boolean shadow = hud != null && hud.shadow.getValue();
HudRenderer.drawSnappedText(gui, text, x, y, color, shadow); HudRenderer.INSTANCE.drawSnappedText(gui, text, x, y, color, shadow);
} }
@Override @Override
@@ -32,7 +32,7 @@ public abstract class TextHudElement extends HudElement {
int color = hud != null ? hud.color.getValue().getRGB() : -1; int color = hud != null ? hud.color.getValue().getRGB() : -1;
boolean shadow = hud != null && hud.shadow.getValue(); boolean shadow = hud != null && hud.shadow.getValue();
HudRenderer.drawSnappedText(gui, previewText, x, y, color, shadow); HudRenderer.INSTANCE.drawSnappedText(gui, previewText, x, y, color, shadow);
} }
protected void drawEditorBackground(GuiGraphicsExtractor gui) { protected void drawEditorBackground(GuiGraphicsExtractor gui) {
@@ -12,6 +12,8 @@ import java.util.List;
public class TotemsElement extends ImageHudElement { public class TotemsElement extends ImageHudElement {
private static ItemStack TOTEM_PREVIEW = null;
public TotemsElement() { public TotemsElement() {
super("totems", 363, 521); super("totems", 363, 521);
w = 16; w = 16;
@@ -38,7 +40,10 @@ public class TotemsElement extends ImageHudElement {
count = 69; count = 69;
} }
drawItem(gui, new ItemStack(Items.TOTEM_OF_UNDYING, Math.max(1, count)), count); ItemStack stack = getTotemPreview(count);
if (stack != null) {
drawItem(gui, stack, count);
}
} }
@Override @Override
@@ -54,7 +59,11 @@ public class TotemsElement extends ImageHudElement {
} }
drawEditorBackground(gui); drawEditorBackground(gui);
drawItem(gui, new ItemStack(Items.TOTEM_OF_UNDYING, Math.max(1, count)), count);
ItemStack stack = getTotemPreview(count);
if (stack != null) {
drawItem(gui, stack, count);
}
} }
@Override @Override
@@ -80,4 +89,15 @@ public class TotemsElement extends ImageHudElement {
); );
} }
} }
private static ItemStack getTotemPreview(int count) {
if (TOTEM_PREVIEW == null) {
try {
TOTEM_PREVIEW = new ItemStack(Items.TOTEM_OF_UNDYING, 1);
} catch (Exception e) {
return null; // registries not ready yet
}
}
return TOTEM_PREVIEW;
}
} }
@@ -175,8 +175,8 @@ public class SearchBarWidget extends Widget {
} }
public void savePosition() { public void savePosition() {
if (ConfigManager.getConfig() != null) { if (ConfigManager.INSTANCE.getConfig() != null) {
ConfigManager.setSearchBarPosition(x, y); ConfigManager.INSTANCE.setSearchBarPosition(x, y);
} }
} }
} }
@@ -42,8 +42,8 @@ public class FriendSettingsPanel extends SettingsPanel {
dummyModule.getSgGeneral().add(nickname); dummyModule.getSgGeneral().add(nickname);
nickname.onUpdate(name -> { nickname.onUpdate(name -> {
friend.setName(name); friend.setName(name);
ConfigManager.getConfig().friends.put(friend.getUuid().toString(), name); ConfigManager.INSTANCE.getConfig().friends.put(friend.getUuid().toString(), name);
ConfigManager.save(); ConfigManager.INSTANCE.save();
}); });
buttons.clear(); buttons.clear();
@@ -10,6 +10,7 @@ import net.minecraft.network.Connection;
import net.minecraft.network.PacketListener; 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.ServerboundSwingPacket; 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;
@@ -137,11 +138,13 @@ public class NetworkUtil {
if (rotateClient) EntityUtil.lookAtClient(hitPos); if (rotateClient) EntityUtil.lookAtClient(hitPos);
if (rotateServer) EntityUtil.lookAtServer(hitPos); if (rotateServer) EntityUtil.lookAtServer(hitPos);
InventoryUtil.swapWithHotbar(mc.player.getInventory().getSelectedSlot(), slot); mc.getConnection().send(new ServerboundSetCarriedItemPacket(slot));
interactBlock(bhr, hand, swingHand); interactBlock(bhr, hand, swingHand);
if (swapBack) { if (swapBack) {
InventoryUtil.swapWithHotbar(mc.player.getInventory().getSelectedSlot(), prevSlot); mc.player.getInventory().setSelectedSlot(prevSlot);
mc.getConnection().send(new ServerboundSetCarriedItemPacket(prevSlot));
} }
return true; return true;