From 957fab15aa5f0e9c216d44f3cff8307158f1cdcb Mon Sep 17 00:00:00 2001 From: retuci0 Date: Sun, 10 May 2026 10:54:59 +0200 Subject: [PATCH] v5.2 --- cambios.md | 13 +- gradle.properties | 2 +- src/main/java/me/retucio/sputnik/Sputnik.java | 21 ++- .../sputnik/config/BinarySerializer.java | 77 ++++++--- .../retucio/sputnik/config/ClientConfig.java | 27 +-- .../retucio/sputnik/config/ConfigManager.java | 162 +++++++++++++----- .../sputnik/mixin/mixins/hud/GuiMixin.java | 2 +- .../mixin/mixins/screen/ScreenMixin.java | 2 +- .../me/retucio/sputnik/module/Module.java | 6 +- .../modules/client/ClientSettingsModule.java | 16 ++ .../sputnik/module/modules/client/Hud.java | 2 +- .../module/modules/client/Notifications.java | 2 +- .../module/modules/movement/Scaffold.java | 3 +- .../sputnik/ui/hud/HudEditorScreen.java | 6 +- .../retucio/sputnik/ui/hud/HudRenderer.java | 26 +-- .../sputnik/ui/hud/TextHudElement.java | 4 +- .../ui/hud/elements/TotemsElement.java | 24 ++- .../ui/widgets/misc/SearchBarWidget.java | 4 +- .../panels/settings/FriendSettingsPanel.java | 4 +- .../me/retucio/sputnik/util/NetworkUtil.java | 7 +- 20 files changed, 280 insertions(+), 130 deletions(-) diff --git a/cambios.md b/cambios.md index 8cdfc73..75bdcf6 100644 --- a/cambios.md +++ b/cambios.md @@ -1,4 +1,4 @@ -# v5.1 +# v5.2 ## novedades @@ -8,12 +8,11 @@ ### arreglos / mejoras -- añadido el grupo de ajustes `módulo` para distinguir los ajustes individuales de cada módulo con los comunes; -y añadido la opción de notificar el alternado de estado de un módulo mediante widgets de notificaciones -- varios arreglos relacionados con la config. -- cambiado `manos` de categoría: de "jugador" a "renderizado" -- `don quijote` ya funciona correctamente, en cuanto a los amigos +- `andamios` ya funciona correctamente +- autoguardado cada cierto intervalo de tiempo en vez de guardar inmediatamente tras cada cambio en los ajustes, por optimización +- el guardado se realiza desde otro hilo ahora, para evitar que el I/O bloque el hilo principal ## problemas reconocidos -- lo de siempre. \ No newline at end of file +- lo de siempre. +- el ítem del tótem no se renderiza en el editor del HUD si es abierto en la pantalla de inicio \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index f114fa8..4224110 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,6 +10,6 @@ discord_rpc_version=1.0.3 neutrino_version=1.1.0 jdk_version=25 -mod_version=5.1 +mod_version=5.2 maven_group=me.retucio archives_base_name=sputnik \ No newline at end of file diff --git a/src/main/java/me/retucio/sputnik/Sputnik.java b/src/main/java/me/retucio/sputnik/Sputnik.java index 839fafe..9d43cc2 100644 --- a/src/main/java/me/retucio/sputnik/Sputnik.java +++ b/src/main/java/me/retucio/sputnik/Sputnik.java @@ -83,7 +83,9 @@ public class Sputnik implements ClientModInitializer { @Override public void onInitializeClient() { mc = Minecraft.getInstance(); - ConfigManager.load(); + + ConfigManager.INSTANCE = new ConfigManager(); + ConfigManager.INSTANCE.load(); VersionChecker.INSTANCE.check(); @@ -101,6 +103,8 @@ public class Sputnik implements ClientModInitializer { Lists.init(); + HudRenderer.INSTANCE = new HudRenderer(); + CapeManager.INSTANCE = new CapeManager(); EVENT_BUS.post(new LoadCapeManagerEvent()); @@ -120,7 +124,7 @@ public class Sputnik implements ClientModInitializer { HudEditorScreen.INSTANCE = new HudEditorScreen(); EVENT_BUS.post(new LoadClickGuiEvent()); - HudRenderer.init(); + HudRenderer.INSTANCE.init(); }); Runtime.getRuntime().addShutdownHook(new Thread(() -> { @@ -131,14 +135,16 @@ public class Sputnik implements ClientModInitializer { // se ejecuta cada tick, es decir, 20 veces por segundo public void onTick() { if (!settingsApplied - && ConfigManager.getConfig() != null - && !ConfigManager.hasLoaded()) { - ConfigManager.applyConfig(); + && ConfigManager.INSTANCE.getConfig() != null + && !ConfigManager.INSTANCE.hasLoaded()) { + ConfigManager.INSTANCE.applyConfig(); settingsApplied = true; } ModuleManager.INSTANCE.getEnabledModules().forEach(Module::onTick); 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; 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()) module.setEnabled(true); @@ -259,7 +266,7 @@ public class Sputnik implements ClientModInitializer { @EventListener public void onStop(ShutdownEvent event) { - ConfigManager.save(); + ConfigManager.INSTANCE.saveOnShutdown(); } public static String getVersionName() { diff --git a/src/main/java/me/retucio/sputnik/config/BinarySerializer.java b/src/main/java/me/retucio/sputnik/config/BinarySerializer.java index 289fb0b..1d7bbdb 100644 --- a/src/main/java/me/retucio/sputnik/config/BinarySerializer.java +++ b/src/main/java/me/retucio/sputnik/config/BinarySerializer.java @@ -2,6 +2,8 @@ package me.retucio.sputnik.config; import java.io.*; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -21,33 +23,60 @@ public class BinarySerializer { private static final byte TYPE_INT_ARRAY = 6; private static final byte TYPE_FRAME_DATA = 7; - public static void writeConfig(ClientConfig config, File file) - throws IOException { - try (DataOutputStream out = new DataOutputStream( - new BufferedOutputStream(new FileOutputStream(file)))) { + public static void writeConfig(ClientConfig config, File file) throws IOException { + byte[] bytes = toBytes(config); + writeBytes(bytes, file); + } - // cabezal - out.writeInt(MAGIC_NUMBER); - out.writeInt(VERSION); + // serializar a bytes en memoria + public static byte[] toBytes(ClientConfig config) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream out = new DataOutputStream(baos)) { + writeConfigTo(config, out); + } + return baos.toByteArray(); + } - // mapas - 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); + // escribir bytes a disco (puede llamarse desde un hilo de fondo) + public static void writeBytes(byte[] bytes, File file) throws IOException { + // escribir a archivo temporal primero para evitar corrupción si el proceso muere a mitad + File temp = new File(file.getParent(), file.getName() + ".tmp"); + try (FileOutputStream fos = new FileOutputStream(temp); + BufferedOutputStream out = new BufferedOutputStream(fos)) { + out.write(bytes); + out.flush(); + fos.getFD().sync(); // forzar flush al disco antes de renombrar + } - // posición de la barra de búsqueda - if (config.searchBarPosition != null) { - out.writeBoolean(true); - out.writeInt(config.searchBarPosition[0]); - out.writeInt(config.searchBarPosition[1]); - } else { - out.writeBoolean(false); - } + // renombrar atómicamente + if (!temp.renameTo(file)) { + // renameTo puede fallar entre sistemas de archivos distintos + Files.move(temp.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING); + } + } + + // 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); } } diff --git a/src/main/java/me/retucio/sputnik/config/ClientConfig.java b/src/main/java/me/retucio/sputnik/config/ClientConfig.java index 59a4d96..c022c32 100644 --- a/src/main/java/me/retucio/sputnik/config/ClientConfig.java +++ b/src/main/java/me/retucio/sputnik/config/ClientConfig.java @@ -53,7 +53,7 @@ public class ClientConfig { @EventListener public void onToggleModule(ToggleModuleEvent event) { - ConfigManager.setModuleState(event.getModule()); + ConfigManager.INSTANCE.setModuleState(event.getModule()); } @SuppressWarnings("rawtypes") @@ -75,24 +75,24 @@ public class ClientConfig { default: break; } - ConfigManager.setSetting(event.getSetting(), value); + ConfigManager.INSTANCE.setSetting(event.getSetting(), value); } @EventListener public void onOpenSettingsPanel(SettingsPanelEvent.Open event) { - ConfigManager.setPanelPosition(event.getPanel()); + ConfigManager.INSTANCE.setPanelPosition(event.getPanel()); } @EventListener public void onCloseSettingsPanel(SettingsPanelEvent.Close event) { settingsPanels.remove(event.getPanel().getModule().getName()); - ConfigManager.save(); + ConfigManager.INSTANCE.markDirty(); } @EventListener public void onMoveSettingsPanel(SettingsPanelEvent.Move event) { settingsPanels.replace(event.getPanel().getModule().getName(), new int[]{event.getPanel().getX(), event.getPanel().getY()}); - ConfigManager.save(); + ConfigManager.INSTANCE.markDirty(); } @EventListener @@ -101,7 +101,7 @@ public class ClientConfig { event.getPanel().getX(), event.getPanel().getY(), event.getPanel().isExtended())); - ConfigManager.save(); + ConfigManager.INSTANCE.markDirty(); } @EventListener @@ -110,7 +110,7 @@ public class ClientConfig { event.getPanel().getX(), event.getPanel().getY(), event.getPanel().isExtended())); - ConfigManager.save(); + ConfigManager.INSTANCE.markDirty(); } @EventListener @@ -119,7 +119,7 @@ public class ClientConfig { ClickGui.INSTANCE.getClientSettingsPanel().getX(), ClickGui.INSTANCE.getClientSettingsPanel().getY(), ClickGui.INSTANCE.getClientSettingsPanel().isExtended())); - ConfigManager.save(); + ConfigManager.INSTANCE.markDirty(); } @EventListener @@ -128,7 +128,7 @@ public class ClientConfig { ClickGui.INSTANCE.getClientSettingsPanel().getX(), ClickGui.INSTANCE.getClientSettingsPanel().getY(), ClickGui.INSTANCE.getClientSettingsPanel().isExtended())); - ConfigManager.save(); + ConfigManager.INSTANCE.markDirty(); } @EventListener @@ -137,7 +137,7 @@ public class ClientConfig { ClickGui.INSTANCE.getFriendsPanel().getX(), ClickGui.INSTANCE.getFriendsPanel().getY(), ClickGui.INSTANCE.getFriendsPanel().isExtended())); - ConfigManager.save(); + ConfigManager.INSTANCE.markDirty(); } @EventListener @@ -146,7 +146,7 @@ public class ClientConfig { ClickGui.INSTANCE.getFriendsPanel().getX(), ClickGui.INSTANCE.getFriendsPanel().getY(), ClickGui.INSTANCE.getFriendsPanel().isExtended())); - ConfigManager.save(); + ConfigManager.INSTANCE.markDirty(); } @EventListener @@ -156,12 +156,13 @@ public class ClientConfig { if (!friends.containsKey(uuid)) { friends.put(uuid, name); } - ConfigManager.save(); + ConfigManager.INSTANCE.markDirty(); } + @EventListener public void onRemoveFriend(FriendEvent.Remove event) { friends.remove(event.getFriend().getUuid().toString()); - ConfigManager.save(); + ConfigManager.INSTANCE.markDirty(); } public record PanelData(int x, int y, boolean extended) implements Serializable { diff --git a/src/main/java/me/retucio/sputnik/config/ConfigManager.java b/src/main/java/me/retucio/sputnik/config/ConfigManager.java index 81832fb..9bdb494 100644 --- a/src/main/java/me/retucio/sputnik/config/ConfigManager.java +++ b/src/main/java/me/retucio/sputnik/config/ConfigManager.java @@ -7,14 +7,17 @@ import me.retucio.sputnik.friend.Friend; import me.retucio.sputnik.friend.FriendManager; import me.retucio.sputnik.module.Module; 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.settings.*; +import me.retucio.sputnik.ui.hud.HudRenderer; import me.retucio.sputnik.ui.widgets.Panel; import me.retucio.sputnik.ui.widgets.panels.FriendsPanel; import me.retucio.sputnik.ui.widgets.panels.ModulePanel; import me.retucio.sputnik.ui.screen.ClickGui; import me.retucio.sputnik.ui.widgets.panels.settings.ClientSettingsPanel; import me.retucio.sputnik.ui.widgets.panels.SettingsPanel; +import me.retucio.sputnik.util.ChatUtil; import java.io.File; import java.io.FileReader; @@ -22,6 +25,10 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; 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; // 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 LEGACY_JSON_FILE = new File("sputnik.json"); - private static boolean loaded = false; - private static ClientConfig config = null; + public static ConfigManager INSTANCE; + + 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 ------------------ // guardar configuraciones - public static void save() { + public void save() { if (!loaded) return; ensureConfig(); + // serializar a bytes en el hilo principal (snapshot inmediato, evita race conditions) + final byte[] snapshot; try { - BinarySerializer.writeConfig(config, CONFIG_FILE); - Sputnik.LOGGER.info("ajustes guardados"); + snapshot = BinarySerializer.toBytes(config); } 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..."); if (CONFIG_FILE.exists()) { @@ -82,7 +133,7 @@ public class ConfigManager { } // aplicar configuraciones cargadas - public static void applyConfig() { + public void applyConfig() { if (!shouldApply()) return; applyModuleStates(); @@ -98,7 +149,7 @@ public class ConfigManager { } // obtener configuración actual - public static ClientConfig getConfig() { + public ClientConfig getConfig() { ensureConfig(); return config; } @@ -106,65 +157,65 @@ public class ConfigManager { // ------------------ GUARDAR VALORES INDIVIDUALES EN LA CONFIG. ------------------ - public static void setModuleState(Module module) { + public void setModuleState(Module module) { ensureConfig(); 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(); config.settings.put(getSettingKey(setting), value); - save(); + markDirty(); } - public static void setPanelPosition(SettingsPanel panel) { + public void setPanelPosition(SettingsPanel panel) { ensureConfig(); if (!config.settingsPanels.containsKey(panel.getModule().getName())) config.settingsPanels.put(panel.getModule().getName(), new int[] {panel.getX(), panel.getY()}); else 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(); 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(); 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(); config.hudVisibilities.put(id, visible); - save(); + markDirty(); } - public static void setSearchBarPosition(int x, int y) { + public void setSearchBarPosition(int x, int y) { ensureConfig(); config.searchBarPosition = new int[] {x, y}; - save(); + markDirty(); } // ------------------ APLICAR AJUSTES ------------------ - public static void applyFriends() { - Sputnik.LOGGER.info("aplicando amigos: {}", config.friends); + public void applyFriends() { config.friends.forEach((uuid, name) -> { Friend friend = new Friend(UUID.fromString(uuid)); friend.setName(name); FriendManager.INSTANCE.add(friend); }); + Sputnik.LOGGER.info("amigos aplicados"); } @SuppressWarnings({"rawtypes", "unchecked"}) - public static void applySetting(Setting setting) { + public void applySetting(Setting setting) { String key = getSettingKey(setting); 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 -> { if (config.moduleStates.containsKey(module.getName())) { module.setEnabled(config.moduleStates.get(module.getName())); @@ -193,14 +244,14 @@ public class ConfigManager { Sputnik.LOGGER.info("estados de módulos aplicados"); } - private static void applyModuleSettings() { + private void applyModuleSettings() { ModuleManager.INSTANCE.getModules().forEach(module -> { - module.getSettings().forEach(ConfigManager::applySetting); + module.getSettings().forEach(this::applySetting); }); Sputnik.LOGGER.info("ajustes de módulos aplicados"); } - private static void applySettingsPanels() { + private void applySettingsPanels() { config.settingsPanels.forEach((moduleName, position) -> { Module module = ModuleManager.INSTANCE.getModuleByName(moduleName); @@ -215,7 +266,7 @@ public class ConfigManager { Sputnik.LOGGER.info("estados de marcos de ajustes aplicados"); } - private static void applySearchBarPosition() { + private void applySearchBarPosition() { if (config.searchBarPosition != null && config.searchBarPosition.length == 2) { ClickGui.INSTANCE.getSearchBar().setX(config.searchBarPosition[0]); 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"); } - private static void applyClientSettings() { + private void applyClientSettings() { ClientSettingsPanel.clientSettings.setEnabled(true); - ClientSettingsPanel.clientSettings.getSettings().forEach(ConfigManager::applySetting); + ClientSettingsPanel.clientSettings.getSettings().forEach(this::applySetting); Sputnik.LOGGER.info("ajustes del cliente aplicados"); } - private static void applyExtendablePanels() { + private void applyExtendablePanels() { for (ModulePanel panel : ClickGui.INSTANCE.getModulePanels()) { applyExtendablePanel(panel); } @@ -240,7 +291,7 @@ public class ConfigManager { ClickGui.INSTANCE.refreshListButtons(); } - private static void applyExtendablePanel(Panel panel) { + private void applyExtendablePanel(Panel panel) { ClientConfig.PanelData panelData = null; if (panel instanceof ModulePanel mp) { @@ -359,19 +410,42 @@ public class ConfigManager { // ------------------ 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) { 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; } + + 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; + } } \ No newline at end of file diff --git a/src/main/java/me/retucio/sputnik/mixin/mixins/hud/GuiMixin.java b/src/main/java/me/retucio/sputnik/mixin/mixins/hud/GuiMixin.java index fad5d1e..ef31532 100644 --- a/src/main/java/me/retucio/sputnik/mixin/mixins/hud/GuiMixin.java +++ b/src/main/java/me/retucio/sputnik/mixin/mixins/hud/GuiMixin.java @@ -79,7 +79,7 @@ public abstract class GuiMixin { @Inject(method = "extractRenderState", at = @At("RETURN")) 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)) diff --git a/src/main/java/me/retucio/sputnik/mixin/mixins/screen/ScreenMixin.java b/src/main/java/me/retucio/sputnik/mixin/mixins/screen/ScreenMixin.java index 8923099..88e8eaa 100644 --- a/src/main/java/me/retucio/sputnik/mixin/mixins/screen/ScreenMixin.java +++ b/src/main/java/me/retucio/sputnik/mixin/mixins/screen/ScreenMixin.java @@ -28,7 +28,7 @@ public class ScreenMixin { @Inject(method = "extractRenderState", at = @At("HEAD")) 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(); if (watermark == null || watermark.isEmpty()) return; gui.text(mc.font, watermark, diff --git a/src/main/java/me/retucio/sputnik/module/Module.java b/src/main/java/me/retucio/sputnik/module/Module.java index ec4b49c..11b84be 100644 --- a/src/main/java/me/retucio/sputnik/module/Module.java +++ b/src/main/java/me/retucio/sputnik/module/Module.java @@ -79,7 +79,7 @@ public class Module { this.bind.setDefaultValue(key); // puto marcos - if (ConfigManager.getConfig().settings + if (ConfigManager.INSTANCE.getConfig().settings .get(this.getName() + ":" + bind.getName()) == null) this.bind.setValue(key); } @@ -136,7 +136,7 @@ public class Module { public void onEnable() { if (notify.getValue()) { 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()) { if (method.isAnnotationPresent(EventListener.class)) { @@ -148,7 +148,7 @@ public class Module { public void onDisable() { 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)) { Sputnik.EVENT_BUS.unsubscribe(this); } diff --git a/src/main/java/me/retucio/sputnik/module/modules/client/ClientSettingsModule.java b/src/main/java/me/retucio/sputnik/module/modules/client/ClientSettingsModule.java index 082b059..da717ed 100644 --- a/src/main/java/me/retucio/sputnik/module/modules/client/ClientSettingsModule.java +++ b/src/main/java/me/retucio/sputnik/module/modules/client/ClientSettingsModule.java @@ -110,6 +110,22 @@ public class ClientSettingsModule extends Module { 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() { super("interfaz", "ajustes de la interfaz, y otros misceláneos", diff --git a/src/main/java/me/retucio/sputnik/module/modules/client/Hud.java b/src/main/java/me/retucio/sputnik/module/modules/client/Hud.java index 8105fd3..86a64ec 100644 --- a/src/main/java/me/retucio/sputnik/module/modules/client/Hud.java +++ b/src/main/java/me/retucio/sputnik/module/modules/client/Hud.java @@ -134,7 +134,7 @@ public class Hud extends Module { ); dyno.onUpdate(v -> { - DynoElement element = (DynoElement) HudRenderer.getElement(DynoElement.class); + DynoElement element = (DynoElement) HudRenderer.INSTANCE.getElement(DynoElement.class); if (element != null) element.reloadTexture(); }); } diff --git a/src/main/java/me/retucio/sputnik/module/modules/client/Notifications.java b/src/main/java/me/retucio/sputnik/module/modules/client/Notifications.java index dddc4fc..a51a4bd 100644 --- a/src/main/java/me/retucio/sputnik/module/modules/client/Notifications.java +++ b/src/main/java/me/retucio/sputnik/module/modules/client/Notifications.java @@ -194,7 +194,7 @@ public class Notifications extends Module { // enviar una notificación private void push(String title, String desc) { if (popup.getValue()) { - HudRenderer.pushNotification(title, desc); + HudRenderer.INSTANCE.pushNotification(title, desc); } if (sound.getValue() != SoundEvents.EMPTY) { mc.level.playSound(mc.player, mc.player.blockPosition(), diff --git a/src/main/java/me/retucio/sputnik/module/modules/movement/Scaffold.java b/src/main/java/me/retucio/sputnik/module/modules/movement/Scaffold.java index 2d017f3..6120a5b 100644 --- a/src/main/java/me/retucio/sputnik/module/modules/movement/Scaffold.java +++ b/src/main/java/me/retucio/sputnik/module/modules/movement/Scaffold.java @@ -330,11 +330,10 @@ public class Scaffold extends Module { mc.player.getInventory().setSelectedSlot(slot); } - // colocar bloque if (NetworkUtil.placeBlock( pos, InteractionHand.MAIN_HAND, - mc.player.getInventory().getSelectedSlot(), + slot, rotate.getValue(), rotate.getValue(), swingHand.getValue(), diff --git a/src/main/java/me/retucio/sputnik/ui/hud/HudEditorScreen.java b/src/main/java/me/retucio/sputnik/ui/hud/HudEditorScreen.java index a3bb2e0..2de412b 100644 --- a/src/main/java/me/retucio/sputnik/ui/hud/HudEditorScreen.java +++ b/src/main/java/me/retucio/sputnik/ui/hud/HudEditorScreen.java @@ -186,9 +186,9 @@ public class HudEditorScreen extends Screen { } private void saveElementToConfig(HudElement element) { - ConfigManager.setHudPosition(element.getId(), element.getX(), element.getY()); - ConfigManager.setHudVisibility(element.getId(), element.isVisible()); - ConfigManager.save(); + ConfigManager.INSTANCE.setHudPosition(element.getId(), element.getX(), element.getY()); + ConfigManager.INSTANCE.setHudVisibility(element.getId(), element.isVisible()); + ConfigManager.INSTANCE.save(); } private void saveAllElementsToConfig() { diff --git a/src/main/java/me/retucio/sputnik/ui/hud/HudRenderer.java b/src/main/java/me/retucio/sputnik/ui/hud/HudRenderer.java index 85636f1..5e7a861 100644 --- a/src/main/java/me/retucio/sputnik/ui/hud/HudRenderer.java +++ b/src/main/java/me/retucio/sputnik/ui/hud/HudRenderer.java @@ -22,16 +22,18 @@ public class HudRenderer { private static final Minecraft mc = Minecraft.getInstance(); - private static final List elements = new ArrayList<>(); - private static final Stack notifications = new Stack<>(); - private static boolean initialized = false; + public static HudRenderer INSTANCE; - public static void init() { + private final List elements = new ArrayList<>(); + private final Stack notifications = new Stack<>(); + private boolean initialized = false; + + public void init() { if (initialized) return; initialized = true; - Map positions = ConfigManager.getConfig().hudPositions; - Map visibilities = ConfigManager.getConfig().hudVisibilities; + Map positions = ConfigManager.INSTANCE.getConfig().hudPositions; + Map visibilities = ConfigManager.INSTANCE.getConfig().hudVisibilities; addElement(new CoordsElement(), positions, visibilities); addElement(new FpsElement(), positions, visibilities); @@ -49,7 +51,7 @@ public class HudRenderer { HudEditorScreen.INSTANCE.setElements(elements); } - private static void addElement(HudElement element, Map positions, Map visibilities) { + private void addElement(HudElement element, Map positions, Map visibilities) { int[] savedPos; if (positions.get(element.getId()) == null) @@ -68,7 +70,7 @@ public class HudRenderer { elements.add(element); } - public static HudElement getElement(Class clazz) { + public HudElement getElement(Class clazz) { for (HudElement element : elements) { if (element.getClass() == clazz) return element; @@ -82,7 +84,7 @@ public class HudRenderer { 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 screenWidth = mc.getWindow().getGuiScaledWidth(); int screenHeight = mc.getWindow().getGuiScaledHeight(); @@ -96,7 +98,7 @@ public class HudRenderer { 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); for (HudElement element : elements) { @@ -129,11 +131,11 @@ public class HudRenderer { || 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)); } - public static List getElements() { + public List getElements() { return elements; } } \ No newline at end of file diff --git a/src/main/java/me/retucio/sputnik/ui/hud/TextHudElement.java b/src/main/java/me/retucio/sputnik/ui/hud/TextHudElement.java index 64af80f..05b1d8a 100644 --- a/src/main/java/me/retucio/sputnik/ui/hud/TextHudElement.java +++ b/src/main/java/me/retucio/sputnik/ui/hud/TextHudElement.java @@ -19,7 +19,7 @@ public abstract class TextHudElement extends HudElement { String text = getText(delta, hud); int color = hud != null ? hud.color.getValue().getRGB() : -1; 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 @@ -32,7 +32,7 @@ public abstract class TextHudElement extends HudElement { int color = hud != null ? hud.color.getValue().getRGB() : -1; 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) { diff --git a/src/main/java/me/retucio/sputnik/ui/hud/elements/TotemsElement.java b/src/main/java/me/retucio/sputnik/ui/hud/elements/TotemsElement.java index 264d5d2..2bc60a3 100644 --- a/src/main/java/me/retucio/sputnik/ui/hud/elements/TotemsElement.java +++ b/src/main/java/me/retucio/sputnik/ui/hud/elements/TotemsElement.java @@ -12,6 +12,8 @@ import java.util.List; public class TotemsElement extends ImageHudElement { + private static ItemStack TOTEM_PREVIEW = null; + public TotemsElement() { super("totems", 363, 521); w = 16; @@ -38,7 +40,10 @@ public class TotemsElement extends ImageHudElement { 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 @@ -54,7 +59,11 @@ public class TotemsElement extends ImageHudElement { } 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 @@ -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; + } } diff --git a/src/main/java/me/retucio/sputnik/ui/widgets/misc/SearchBarWidget.java b/src/main/java/me/retucio/sputnik/ui/widgets/misc/SearchBarWidget.java index 607399f..dda3d37 100644 --- a/src/main/java/me/retucio/sputnik/ui/widgets/misc/SearchBarWidget.java +++ b/src/main/java/me/retucio/sputnik/ui/widgets/misc/SearchBarWidget.java @@ -175,8 +175,8 @@ public class SearchBarWidget extends Widget { } public void savePosition() { - if (ConfigManager.getConfig() != null) { - ConfigManager.setSearchBarPosition(x, y); + if (ConfigManager.INSTANCE.getConfig() != null) { + ConfigManager.INSTANCE.setSearchBarPosition(x, y); } } } diff --git a/src/main/java/me/retucio/sputnik/ui/widgets/panels/settings/FriendSettingsPanel.java b/src/main/java/me/retucio/sputnik/ui/widgets/panels/settings/FriendSettingsPanel.java index b6a0374..962bee8 100644 --- a/src/main/java/me/retucio/sputnik/ui/widgets/panels/settings/FriendSettingsPanel.java +++ b/src/main/java/me/retucio/sputnik/ui/widgets/panels/settings/FriendSettingsPanel.java @@ -42,8 +42,8 @@ public class FriendSettingsPanel extends SettingsPanel { dummyModule.getSgGeneral().add(nickname); nickname.onUpdate(name -> { friend.setName(name); - ConfigManager.getConfig().friends.put(friend.getUuid().toString(), name); - ConfigManager.save(); + ConfigManager.INSTANCE.getConfig().friends.put(friend.getUuid().toString(), name); + ConfigManager.INSTANCE.save(); }); buttons.clear(); diff --git a/src/main/java/me/retucio/sputnik/util/NetworkUtil.java b/src/main/java/me/retucio/sputnik/util/NetworkUtil.java index 4a3a501..2584a10 100644 --- a/src/main/java/me/retucio/sputnik/util/NetworkUtil.java +++ b/src/main/java/me/retucio/sputnik/util/NetworkUtil.java @@ -10,6 +10,7 @@ import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientboundSetTimePacket; +import net.minecraft.network.protocol.game.ServerboundSetCarriedItemPacket; import net.minecraft.network.protocol.game.ServerboundSwingPacket; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; @@ -137,11 +138,13 @@ public class NetworkUtil { if (rotateClient) EntityUtil.lookAtClient(hitPos); if (rotateServer) EntityUtil.lookAtServer(hitPos); - InventoryUtil.swapWithHotbar(mc.player.getInventory().getSelectedSlot(), slot); + mc.getConnection().send(new ServerboundSetCarriedItemPacket(slot)); + interactBlock(bhr, hand, swingHand); if (swapBack) { - InventoryUtil.swapWithHotbar(mc.player.getInventory().getSelectedSlot(), prevSlot); + mc.player.getInventory().setSelectedSlot(prevSlot); + mc.getConnection().send(new ServerboundSetCarriedItemPacket(prevSlot)); } return true;