diff --git a/README.en.md b/README.en.md new file mode 100644 index 0000000..719183a --- /dev/null +++ b/README.en.md @@ -0,0 +1,82 @@ +

+ español + english +

+ +# jenny's mod 2 (100% real) + +> Minecraft Fabric 26.2 mod that adds some "QOL" features, mostly related to the camera. + +## installation + +### for normal people: +1. go to [releases](https://codeberg.org/retucio/sputnik/releases) +2. choose the most recent version +3. download the .jar file +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`) + +issues could arise when using it with other mods, especially other clients, since they could conflict + +### for nerds +1. clone the repo (`git clone https://codeberg.org/retucio/sputnik`) +2. enter the repo dir (`cd sputnik`) +3. `gradlew build` for Windows (ew) or `chmod +x gradlew` + `./gradlew build` for Unix-likes (Linux & Mac) +4. the built .jar will be found in `/build/libs/sputnik-X.X.jar` + +## usage + +`rshift` by default to open the GUI + +`insert` by default to open the HUD editor + +`$` as prefix for commands (autocompleted) + +some modules have keys assigned by default, assign them `ESC` to unbind them. + +## ui + +- left click to toggle modules +- right click to open its settings +- left click + drag to move a panel +- right click on a panel's header to expand/contract it, or to close it +- left click over settings to change them +- shift + right click on a setting to reset it to its default value +- place the mouse cursor over a module/setting to read its description + +## screenshots + +auto mine +block ESP + light overlay +perspective plus +chatplus + nametags + screenshots plus +click GUI +freecam + tracers +HUD editor +item physics +lsd module +macros tab +projectile trajectories + + +## contribution + +yes please (PRs are welcome) + +## license + +[CC0 license](LICENSE) + +## disclaimer + +i don't give a single fuck what happens to you when using this mod on servers where its features are bannable and such. + +## deps + +- [fabric api](https://modrinth.com/mod/fabric-api/) + +## notes + +this mod IS BUGGY. VERY BUGGY, i know. i started this project when i was 14 and the codebase is such a mess i refuse to fix it. i might rewrite it in a future, though. \ No newline at end of file diff --git a/README.md b/README.md index 63adee5..65d268d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,11 @@ +

+ español + english +

+ # 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.2 que añade algunas cosas "QOL", mayormente relacionadas a la cámara. ## instalación @@ -14,10 +19,10 @@ asegúrate de tener una version de Minecraft y Fabric compatibles con el mod (MC 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 -1. clona el respositorio (`git clone https://github.com/retuci0/sputnik`) +1. clona el respositorio (`git clone https://codeberg.org/retucio/sputnik`) 2. entra al directorio del repositorio (`cd sputnik`) -3. `gradlew build` para Windows o `chmod +x gradlew` + `./gradlew build` para Linux (Mac es Linux) -4. el resultado estará en `/build/libs/sputnik-X.X.jar` (el que no lleva "sources" en el nombre) +3. `gradlew build` para Windows (ew) o `chmod +x gradlew` + `./gradlew build` para Unix-likes (Linux & Mac) +4. el resultado estará en `/build/libs/sputnik-X.X.jar` ## uso @@ -33,28 +38,25 @@ algunos módulos tienen teclas asignadas por defecto, asígnales `ESC` para desa - clic izquierdo para activar / desactivar módulos - clic derecho para abrir sus ajustes -- clic izquierdo + arrastrar para mover marcos +- clic izquierdo + arrastrar para mover paneles - clic derecho en la cabeza del marco para expandirlo / contraerlo o para cerrarlo - clic izquierdo sobre ajustes para modificarlos - shift + clic derecho sobre ajustes para restablecerlos - posiciona el puntero del ratón sobre un módulo o ajuste para leer su descripción -### protips -- shift mientras pasas el puntero por encima de un ajuste de modos para ver los modos disponibles -- clic derecho para ciclar hacia atrás en ajustes de modo -- usa la rueda del ratón para mover la interfaz verticalmente -- shift + rueda del ratón para mover todos los marcos a un rango visible en la pantalla - ## capturas -interfaz -nametags mostrando daño de un tridente -chatplus y capturas en uso -críticos -fullbright en modo gamma cambiando el color de los shaders -HUD +auto minado +resaltado de bloques + superposición de luz +perspectiva plus +chatplus + nametags + capturas +interfaz +cámara libre + trazos editor de HUD -selector de colores +físicas de items +LSD +macros +trayectorias ## contribuciones @@ -62,26 +64,16 @@ sí por favor ## licencia -no sé, haz lo que quieras con esto, es puta basura xd - -aunque estaría guay que acreditases - -pero bueno +[licencia CC0](LICENSE) ## descargo de responsabilidad me importa una puta mierda lo que pase al usar este mod en servers donde es baneable y así. -## mods recomendados +## dependencias -> mods que recomiendo usar junto a este: +- [fabric api](https://modrinth.com/mod/fabric-api/) -- [fabric api (necesario)](https://modrinth.com/mod/fabric-api/): necesario para el mod -- [sodium](https://modrinth.com/mod/sodium): mejora el rendimiento general del juego -- [viafabricplus](https://modrinth.com/mod/viafabricplus): te permite conectarte a servidores que tengan una versión distinta a la de tu cliente -- [xaero's world map](https://modrinth.com/mod/xaeros-world-map/) y [xaero's minimap](https://modrinth.com/mod/xaeros-minimap/): mapa chulo -- [mod menu](https://modrinth.com/mod/modmenu): lista de los mods instalados, y sus ajustes -- [iris](https://modrinth.com/mod/iris): shaders -- [lambdynamiclights](https://modrinth.com/mod/lambdynamiclights): iluminación dinámica -- [appleskin](https://modrinth.com/mod/appleskin/): información relacionada con la comida -- [baritone (desactualizado)](https://github.com/cabaletta/baritone): google maps para juego de cubos \ No newline at end of file +## notas + +este mod tiene MUCHOS bugs. empecé este proyecto cuando tenía 14 años y no sabía una mierda de programar. el código es un puto desastre y me niego a arreglarlo. puede que en un futuro reescriba el mod o algo. no sé. \ No newline at end of file diff --git a/cambios.md b/cambios.md index 552ee21..7131a93 100644 --- a/cambios.md +++ b/cambios.md @@ -1,22 +1,20 @@ -# v6.3 +# v6.4 ## novedades -- actualizado a Gradle 9.7.1 +- README en inglés +- capturas actualizadas (las de los README) ### adiciones #### módulos nuevos: -- autominado: mina automáticamente los bloques seleccionados, con distintos modos de selección -- estiloso: haz truquitos con el ítem que tienes en la mano - ### arreglos / mejoras -- mejoras varias a `puto gordo` -- ahora `trazos` con `uno mismo` solo te apunta en cámara libre -- nuevo ajuste de distancia máxima de renderizado para `nametags` +- ahora la detección de clics sobre cabezales de grupos de ajustes funciona correctamente ## problemas reconocidos +- `reponer` no funciona +- `copiar` tras sacar una captura con `capturas` no funciona correctamente - lo de siempre. diff --git a/gradle.properties b/gradle.properties index 1e4c1af..a8ad369 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=6.3 +mod_version=6.4 maven_group=me.retucio archives_base_name=sputnik \ No newline at end of file diff --git a/screenshots/automine.png b/screenshots/automine.png new file mode 100644 index 0000000..416c51e Binary files /dev/null and b/screenshots/automine.png differ diff --git a/screenshots/blockesp.png b/screenshots/blockesp.png new file mode 100644 index 0000000..decb660 Binary files /dev/null and b/screenshots/blockesp.png differ diff --git a/screenshots/camtweaks.png b/screenshots/camtweaks.png new file mode 100644 index 0000000..44bed93 Binary files /dev/null and b/screenshots/camtweaks.png differ diff --git a/screenshots/chatplus.png b/screenshots/chatplus.png index 2a24aff..1df804e 100644 Binary files a/screenshots/chatplus.png and b/screenshots/chatplus.png differ diff --git a/screenshots/clickgui.png b/screenshots/clickgui.png new file mode 100644 index 0000000..9844490 Binary files /dev/null and b/screenshots/clickgui.png differ diff --git a/screenshots/colorpicker.png b/screenshots/colorpicker.png deleted file mode 100644 index 6ee3f08..0000000 Binary files a/screenshots/colorpicker.png and /dev/null differ diff --git a/screenshots/crits.png b/screenshots/crits.png deleted file mode 100644 index d83b26b..0000000 Binary files a/screenshots/crits.png and /dev/null differ diff --git a/screenshots/damageoverlay.png b/screenshots/damageoverlay.png deleted file mode 100644 index e90a04a..0000000 Binary files a/screenshots/damageoverlay.png and /dev/null differ diff --git a/screenshots/freecam.png b/screenshots/freecam.png new file mode 100644 index 0000000..1a28072 Binary files /dev/null and b/screenshots/freecam.png differ diff --git a/screenshots/fullbright.png b/screenshots/fullbright.png deleted file mode 100644 index 24ee692..0000000 Binary files a/screenshots/fullbright.png and /dev/null differ diff --git a/screenshots/hud.png b/screenshots/hud.png deleted file mode 100644 index 6515bd8..0000000 Binary files a/screenshots/hud.png and /dev/null differ diff --git a/screenshots/hudeditor.png b/screenshots/hudeditor.png index d2e85e8..791bd35 100644 Binary files a/screenshots/hudeditor.png and b/screenshots/hudeditor.png differ diff --git a/screenshots/itemphysics.png b/screenshots/itemphysics.png new file mode 100644 index 0000000..bc43658 Binary files /dev/null and b/screenshots/itemphysics.png differ diff --git a/screenshots/lsd.png b/screenshots/lsd.png new file mode 100644 index 0000000..06f3cf9 Binary files /dev/null and b/screenshots/lsd.png differ diff --git a/screenshots/macros.png b/screenshots/macros.png new file mode 100644 index 0000000..2db03b4 Binary files /dev/null and b/screenshots/macros.png differ diff --git a/screenshots/nametags.png b/screenshots/nametags.png deleted file mode 100644 index 0986e3d..0000000 Binary files a/screenshots/nametags.png and /dev/null differ diff --git a/screenshots/trajectories.png b/screenshots/trajectories.png new file mode 100644 index 0000000..01ca950 Binary files /dev/null and b/screenshots/trajectories.png differ diff --git a/screenshots/ui.png b/screenshots/ui.png deleted file mode 100644 index 4ebc2f4..0000000 Binary files a/screenshots/ui.png and /dev/null differ diff --git a/src/main/java/me/retucio/sputnik/module/modules/render/Nametags.java b/src/main/java/me/retucio/sputnik/module/modules/render/Nametags.java index 4408006..805ce0f 100644 --- a/src/main/java/me/retucio/sputnik/module/modules/render/Nametags.java +++ b/src/main/java/me/retucio/sputnik/module/modules/render/Nametags.java @@ -3,6 +3,7 @@ package me.retucio.sputnik.module.modules.render; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import me.retucio.sputnik.Sputnik; +import me.retucio.sputnik.config.ConfigManager; import me.retucio.sputnik.mixin.mixins.entity.EntityMixin; import me.retucio.sputnik.mixin.mixins.entity.ItemEntityMixin; import me.retucio.sputnik.mixin.mixins.player.PlayerMixin; @@ -90,7 +91,7 @@ public class Nametags extends Module { defaultEntities.replace(EntityTypes.TNT, true); entities.setDefaultValue(defaultEntities); - health.onUpdate(v -> healthMode.visibility(v)); + health.onUpdate(healthMode::visibility); entities.onUpdate(entities -> { items.visibility(entities.get(EntityTypes.ITEM)); @@ -131,7 +132,7 @@ public class Nametags extends Module { @SuppressWarnings("deprecation") public String getOwnerName(EntityReference owner) { // si el dueño está en línea (de manera segura) - if (mc.level instanceof UniquelyIdentifyable queriableWorld) { // UUIDLookup ?? + if (mc.level instanceof UniquelyIdentifyable queriableWorld) { LivingEntity ownerEntity = owner.resolve(queriableWorld, LivingEntity.class); if (ownerEntity instanceof Player playerEntity) return playerEntity.getName().getString(); } diff --git a/src/main/java/me/retucio/sputnik/ui/screen/ClickGui.java b/src/main/java/me/retucio/sputnik/ui/screen/ClickGui.java index dd91887..37a8ae3 100644 --- a/src/main/java/me/retucio/sputnik/ui/screen/ClickGui.java +++ b/src/main/java/me/retucio/sputnik/ui/screen/ClickGui.java @@ -79,6 +79,8 @@ public class ClickGui extends Screen { private final ProfilesTab profilesTab = new ProfilesTab(); private final MacrosTab macrosTab = new MacrosTab(); + private static final int PLACEMENT_SEARCH_STEP = 8; + public ClickGui() { super(Component.translatable("sputnik.ui.clickgui.title")); Sputnik.EVENT_BUS.subscribe(this); @@ -202,6 +204,49 @@ public class ClickGui extends Screen { return bottom + 20; // padding } + private int[] findEmptyPosition(int w, int h, int preferredX, int preferredY) { + int screenWidth = mc.getWindow().getGuiScaledWidth(); + int maxX = Math.max(0, screenWidth - w); + int startX = Math.clamp(preferredX, 0, maxX); + int startY = Math.max(preferredY, 0); + + int searchBottom = calculateContentHeight() + h; + + for (int y = startY; y <= searchBottom; y += PLACEMENT_SEARCH_STEP) { + for (int candidateX = 0; candidateX <= maxX; candidateX += PLACEMENT_SEARCH_STEP) { + if (!overlapsAnything(candidateX, y, w, h)) { + return new int[]{candidateX, y}; + } + } + } + + // no hay hueco: colocarlo debajo de todo lo demás, para llegar a él haciendo scroll + return new int[]{startX, calculateContentHeight()}; + } + + private boolean overlapsAnything(int x, int y, int w, int h) { + for (ModulePanel mp : modulePanels) { + int mpHeight = mp.getH() + (mp.isExtended() ? mp.getTotalHeight() : 0); + if (rectsOverlap(x, y, w, h, mp.getX(), mp.getY(), mp.getW(), mpHeight)) return true; + } + + for (SettingsPanel sp : settingsPanels) { + int spHeight = sp.getH() + sp.getTotalHeight(); + if (rectsOverlap(x, y, w, h, sp.getX(), sp.getY(), sp.getW(), spHeight)) return true; + } + + int friendsHeight = friendsPanel.getH() + (friendsPanel.isExtended() ? friendsPanel.getTotalHeight() : 0); + 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) { + return ax < bx + bw && ax + aw > bx + && ay < by + bh && ay + ah > by; + } + @Override public boolean mouseClicked(MouseButtonEvent click, boolean doubled) { int x = (int) click.x(); @@ -433,12 +478,18 @@ public class ClickGui extends Screen { ); } - // abrir un marco donde se encuentran los ajustes del módulo deseado + // abrir un marco donde se encuentran los ajustes del módulo deseado, buscando un + // hueco libre cerca de (x, y) para que no se solape con otros paneles ya abiertos public void openSettingsPanel(Module module, int x, int y) { - // asegurarse de que no se sale de la pantalla - x = Math.clamp(x, 0, mc.getWindow().getGuiScaledWidth() - 80); + SettingsPanel panel = new SettingsPanel(module, 0, 0, 100, 20); + panel.updateTotalHeight(); // altura real disponible ya tras el constructor + + int panelHeight = panel.getH() + panel.getTotalHeight(); + int[] position = findEmptyPosition(panel.getW(), panelHeight, x, y); + + panel.setX(position[0]); + panel.setY(position[1]); - SettingsPanel panel = new SettingsPanel(module, x, y, 100, 20); settingsPanels.add(panel); Sputnik.EVENT_BUS.post(new SettingsPanelEvent.Open(panel)); diff --git a/src/main/java/me/retucio/sputnik/ui/widgets/Panel.java b/src/main/java/me/retucio/sputnik/ui/widgets/Panel.java index 5ebe1a8..c1ef93f 100644 --- a/src/main/java/me/retucio/sputnik/ui/widgets/Panel.java +++ b/src/main/java/me/retucio/sputnik/ui/widgets/Panel.java @@ -9,10 +9,6 @@ import java.util.function.Supplier; public abstract class Panel extends Widget { - // el título se resuelve al pintarlo, no al construir el marco: los marcos se crean en - // la inicialización del mod, cuando el idioma todavía no ha cargado, así que guardar el - // texto ya traducido dejaba los títulos en español para siempre (y no cambiaban aunque - // se cambiara el idioma del juego en marcha) private Supplier title; protected final List buttons = new ArrayList<>(); diff --git a/src/main/java/me/retucio/sputnik/ui/widgets/panels/SettingsPanel.java b/src/main/java/me/retucio/sputnik/ui/widgets/panels/SettingsPanel.java index cdb3aa0..6b2b70f 100644 --- a/src/main/java/me/retucio/sputnik/ui/widgets/panels/SettingsPanel.java +++ b/src/main/java/me/retucio/sputnik/ui/widgets/panels/SettingsPanel.java @@ -8,7 +8,6 @@ import me.retucio.sputnik.module.setting.settings.*; import me.retucio.sputnik.ui.widgets.buttons.settings.*; import me.retucio.sputnik.ui.screen.ClickGui; import me.retucio.sputnik.ui.widgets.buttons.*; -import me.retucio.sputnik.ui.widgets.Panel; import me.retucio.sputnik.util.Colors; import me.retucio.sputnik.util.I18nUtil; @@ -43,6 +42,7 @@ public class SettingsPanel extends CloseablePanel> groupButtons = getButtonsForGroup(group); - for (int j = 0; j < groupButtons.size(); j++) { - SettingButton sb = groupButtons.get(j); - if (sb.getSetting().isVisible() && sb.getSetting().isSearchMatch()) { - if (j < groupButtons.size() - 1) { - totalHeight += (h - h / 4) + PADDING; - } else { - totalHeight += (h - h / 4); - } - } - } - totalHeight += PADDING; - } - } - } - // fondo del marco gui.fill(x, descBoxTop - PADDING + 1, x + w, descBoxTop + totalHeight, Colors.panelBgColor.getRGB()); @@ -112,10 +89,9 @@ public class SettingsPanel extends CloseablePanel descLines = wrapDescription(module.getDisplayDescription(), w - 2 * PADDING); + int descHeight = descLines.size() * mc.font.lineHeight + (descLines.size() - 1) * 2; + + int height = descHeight + 3 * PADDING; + + for (SettingGroup group : settingGroups) { + if (!hasVisibleSettingsInGroup(group)) continue; + + height += h + PADDING; + + if (group.isExtended()) { + List> groupButtons = getButtonsForGroup(group); + for (int j = 0; j < groupButtons.size(); j++) { + SettingButton sb = groupButtons.get(j); + if (sb.getSetting().isVisible() && sb.getSetting().isSearchMatch()) { + if (j < groupButtons.size() - 1) { + height += (h - h / 4) + PADDING; + } else { + height += (h - h / 4); + } + } + } + height += PADDING; + } + } + + totalHeight = height; + } + public void updatePosition(double mouseX, double mouseY) { if (dragging) { x = (int) (mouseX - dragX); @@ -246,44 +251,40 @@ public class SettingsPanel extends CloseablePanel descLines = wrapDescription(module.getDisplayDescription(), w - 2 * PADDING); int descHeight = descLines.size() * mc.font.lineHeight + (descLines.size() - 1) * 2; currentY += descHeight + 3 * PADDING; // descBoxBottom + padding - // iterar hasta llegar al grupo deseado - int currentIndex = 0; for (SettingGroup group : settingGroups) { - if (hasVisibleSettingsInGroup(group)) { - if (currentIndex == groupIndex) { - return currentY; - } + if (!hasVisibleSettingsInGroup(group)) continue; + if (group == targetGroup) { + return currentY; + } - currentY += h + PADDING; + currentY += h + PADDING; - if (group.isExtended()) { - List> groupButtons = getButtonsForGroup(group); - for (int j = 0; j < groupButtons.size(); j++) { - SettingButton sb = groupButtons.get(j); - if (sb.getSetting().isVisible() && sb.getSetting().isSearchMatch()) { - if (j < groupButtons.size() - 1) { - currentY += (h - h / 4) + PADDING; - } else { - currentY += (h - h / 4); - } + if (group.isExtended()) { + List> groupButtons = getButtonsForGroup(group); + for (int j = 0; j < groupButtons.size(); j++) { + SettingButton sb = groupButtons.get(j); + if (sb.getSetting().isVisible() && sb.getSetting().isSearchMatch()) { + if (j < groupButtons.size() - 1) { + currentY += (h - h / 4) + PADDING; + } else { + currentY += (h - h / 4); } } - currentY += PADDING; } - currentIndex++; + currentY += PADDING; } } // fallback return currentY; } - public boolean isGroupHeaderHovered(int mouseX, int mouseY, int groupIndex) { - int headerY = getGroupHeaderY(groupIndex); + public boolean isGroupHeaderHovered(int mouseX, int mouseY, SettingGroup group) { + int headerY = getGroupHeaderY(group); return mouseX > x + PADDING && mouseX < x + w - PADDING && mouseY > headerY && mouseY < headerY + h;