This commit is contained in:
retuci0 committed 2025-12-31 00:44:36 +01:00
1 parent a9cf6dd924
commit 347ec658bb
67 files changed
+2522 -849

No files matched your search

+3 -1
View File
@@ -43,4 +43,6 @@ replay_*.log
todo.txt
cambios.md
remappedSrc/
remappedSrc/
src/main/java/me/retucio/camtweaks/ui/widgets/Frame.java
src/main/java/me/retucio/camtweaks/ui/widgets/Button.java
+16 -3
View File
@@ -1,15 +1,28 @@
# v1.9.1
# v2.0
## novedades
- ARREGLADO EL SELECTOR DE COLORES
### adiciones
- ajuste de opción: similar a enumsetting, pero abre un marco de selección, igual que listsetting.
#### módulos nuevos:
- resaltado de bloques: resalta bloques de cierto tipo renderizando una caja con su forma, visible a través de paredes
- delay de paquetes: simula un ping alto añadiendo delay a los paquetes
- inventario plus: te permite mover items a cualquier slot del inventario mediante teclas (ej.: d + tecla para slot 4);
- progreso de minado: muestra el progreso de minado de un bloque de una manera más visual, mediante cajas de color
- mano secundaria: equipa de manera automática un ítem en tu mano secundaria
- moverse en interfaz: te permite utilizar las teclas de movimiento con ciertas interfaces abiertas (configurable)
### arreglos / mejoras
- ahora se pueden mostrar también las coordenadas del nether en el elemento del hud para coordenadas
- ahora ChatPlus utilizará los corchetes [] para mostrar la hora (antes era <>), además de también detectar cuando un jugador se une a la hora de dibujar las cabezas
- ahora puedes elegir el sonido en aviso de baja dur., junto a la altura y volumen de este
- ya no se pueden abrir interfaces del mod estando en pantallas donde se suele escribir (chat, carteles, etc.)
- arreglado algunos problemas con las configuraciones
## problemas reconocidos
- muchos, pero repórtalos en la página de problemas si quieres para que queden bien registrados
+1 -1
View File
@@ -6,7 +6,7 @@ yarn_mappings=1.21.10+build.2
loader_version=0.17.3
loom_version=1.11-SNAPSHOT
mod_version=1.9
mod_version=2.0
maven_group=me.retucio
archives_base_name=camtweaks
@@ -18,27 +18,30 @@ import me.retucio.camtweaks.module.ModuleManager;
import me.retucio.camtweaks.module.modules.HUD;
import me.retucio.camtweaks.ui.screen.ClickGUI;
import me.retucio.camtweaks.ui.screen.HudEditorScreen;
import me.retucio.camtweaks.ui.HudRenderer;
import me.retucio.camtweaks.ui.hud.HudEditorScreen;
import me.retucio.camtweaks.ui.hud.HudRenderer;
import me.retucio.camtweaks.ui.buttons.BindButton;
import me.retucio.camtweaks.ui.buttons.SettingButton;
import me.retucio.camtweaks.ui.buttons.TextButton;
import me.retucio.camtweaks.ui.frames.ClientSettingsFrame;
import me.retucio.camtweaks.ui.frames.SettingsFrame;
import me.retucio.camtweaks.util.ChatUtil;
import me.retucio.camtweaks.util.KeyUtil;
import me.retucio.camtweaks.util.Lists;
import me.retucio.camtweaks.util.MiscUtil;
import me.retucio.camtweaks.util.*;
import me.retucio.camtweaks.util.render.DrawUtil;
import me.retucio.camtweaks.util.render.RenderUtil;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.SharedConstants;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.AbstractCommandBlockScreen;
import net.minecraft.client.gui.screen.ingame.AbstractSignEditScreen;
import net.minecraft.client.gui.screen.ingame.AnvilScreen;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -68,7 +71,7 @@ public class CameraTweaks implements ClientModInitializer {
private Screen prevScreen;
public boolean settingsApplied = false;
public static boolean settingsApplied = false;
@Override
@@ -80,14 +83,20 @@ public class CameraTweaks implements ClientModInitializer {
ConfigManager.load();
EVENT_BUS.register(this);
EVENT_BUS.register(new HudRenderer());
EVENT_BUS.register(MiscUtil.class);
EVENT_BUS.register(ChatUtil.class);
EVENT_BUS.register(DrawUtil.class);
EVENT_BUS.register(EntityUtil.class);
EVENT_BUS.register(InventoryUtil.class);
EVENT_BUS.register(MiscUtil.class);
EVENT_BUS.register(NetworkUtil.class);
EVENT_BUS.register(RenderUtil.class);
Lists.init();
ModuleManager.INSTANCE = new ModuleManager(EVENT_BUS);
ModuleManager.INSTANCE = new ModuleManager();
EVENT_BUS.post(new LoadModuleManagerEvent());
CommandManager.INSTANCE = new CommandManager();
@@ -172,7 +181,8 @@ public class CameraTweaks implements ClientModInitializer {
// maneja la lógica de apertura de la interfaz
private void handleClickGUIKey(int key, boolean anyFocused) {
if (key != ClientSettingsFrame.guiSettings.getKey() || anyFocused) return;
if (key != ClientSettingsFrame.guiSettings.getKey() || anyFocused || isOnTypingScreen())
return;
// al parecer esto hace que con la tecla de la interfaz puedas ir cambiando de splash text en la pantalla del título
// pero me ha hecho gracia así que así se queda
@@ -188,13 +198,13 @@ public class CameraTweaks implements ClientModInitializer {
// manejar la lógica de apertura del editor de elementos del hud, con la misma lógica que handleClickGUIKey()
private void handleHudEditorKey(int key, boolean anyFocused) {
HUD hud = ModuleManager.INSTANCE.getModuleByClass(HUD.class);
if (key != hud.editorKey.getKey() || anyFocused) return;
if (!hud.isEnabled()) {
ChatUtil.warn("HUD está desactivado, lumbreras");
return;
}
if (key != hud.editorKey.getKey() || anyFocused || isOnTypingScreen()) return;
if (mc.currentScreen != HudEditorScreen.INSTANCE) {
if (!hud.isEnabled()) {
ChatUtil.warn("HUD está desactivado, lumbreras");
return;
}
prevScreen = mc.currentScreen;
mc.setScreen(HudEditorScreen.INSTANCE);
} else {
@@ -212,6 +222,13 @@ public class CameraTweaks implements ClientModInitializer {
module.setEnabled(false);
}
private boolean isOnTypingScreen() {
return mc.currentScreen instanceof ChatScreen
|| mc.currentScreen instanceof AnvilScreen
|| mc.currentScreen instanceof AbstractSignEditScreen
|| mc.currentScreen instanceof AbstractCommandBlockScreen;
}
@SubscribeEvent
public void onStop(ShutdownEvent event) {
ConfigManager.save();
@@ -8,7 +8,7 @@ import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import me.retucio.camtweaks.util.MiscUtil;
import me.retucio.camtweaks.util.EntityUtil;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.text.Text;
@@ -190,7 +190,7 @@ public class EntityArgumentType implements ArgumentType<Entity> {
builder.suggest("@r");
builder.suggest("@s");
Entity lookingAt = MiscUtil.getEntityPlayerIsLookingAt();
Entity lookingAt = EntityUtil.getEntityPlayerIsLookingAt();
if (lookingAt != null)
builder.suggest(lookingAt.getUuid().toString());
@@ -4,23 +4,11 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import me.retucio.camtweaks.CameraTweaks;
import me.retucio.camtweaks.command.Command;
import me.retucio.camtweaks.event.SubscribeEvent;
import me.retucio.camtweaks.event.events.DisconnectEvent;
import me.retucio.camtweaks.event.events.OpenScreenEvent;
import me.retucio.camtweaks.event.events.PacketEvent;
import me.retucio.camtweaks.event.events.TickEvent;
import me.retucio.camtweaks.ui.screen.PreviewScreen;
import me.retucio.camtweaks.util.ChatUtil;
import me.retucio.camtweaks.util.MiscUtil;
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
import me.retucio.camtweaks.util.InventoryUtil;
import net.minecraft.command.CommandSource;
import net.minecraft.inventory.EnderChestInventory;
import net.minecraft.inventory.Inventories;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.SimpleInventory;
import net.minecraft.network.packet.s2c.play.CloseScreenS2CPacket;
import net.minecraft.screen.GenericContainerScreenHandler;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
// accede a los contenidos de tu enderchest
public class EnderChestCommand extends Command {
@@ -36,7 +24,7 @@ public class EnderChestCommand extends Command {
builder.executes(ctx -> {
mc.execute(() -> {
if (mc.player == null) return;
if (MiscUtil.getEchestInv() == null) {
if (InventoryUtil.getEchestInv() == null) {
ChatUtil.warn("necesitas abrir un enderchest una vez primero");
return;
}
@@ -52,8 +40,8 @@ public class EnderChestCommand extends Command {
public void onTick(TickEvent.Post event) {
if (shouldOpenEchest) {
shouldOpenEchest = false;
if (MiscUtil.getEchestInv() != null)
mc.setScreen(new PreviewScreen(MiscUtil.getEchestInv(), null));
if (InventoryUtil.getEchestInv() != null)
mc.setScreen(new PreviewScreen(InventoryUtil.getEchestInv(), null));
}
}
}
@@ -5,6 +5,7 @@ import me.retucio.camtweaks.command.Command;
import me.retucio.camtweaks.command.args.EntityArgumentType;
import me.retucio.camtweaks.event.SubscribeEvent;
import me.retucio.camtweaks.event.events.KeyEvent;
import me.retucio.camtweaks.util.EntityUtil;
import me.retucio.camtweaks.util.MiscUtil;
import net.minecraft.command.CommandSource;
import net.minecraft.entity.Entity;
@@ -21,7 +22,7 @@ public class SpectateCommand extends Command {
builder
.executes(ctx -> { // If no argument, use the entity player is looking at
mc.execute(() -> {
Entity target = MiscUtil.getEntityPlayerIsLookingAt();
Entity target = EntityUtil.getEntityPlayerIsLookingAt();
if (target != null)
mc.setCameraEntity(target);
});
@@ -57,8 +57,9 @@ public class ClientConfig {
case KeySetting k: value = k.getKey(); break;
case NumberSetting n: value = n.getValue(); break;
case StringSetting s: value = s.getValue(); break;
case ListSetting l: value = l.getValues(); break;
case ListSetting l: value = l.getConfigValues(); break;
case ColorSetting c: value = c.getConfigValue(); break;
case OptionSetting o: value = o.getIndex(); break;
default: break;
}
@@ -6,6 +6,7 @@ import me.retucio.camtweaks.CameraTweaks;
import me.retucio.camtweaks.module.Module;
import me.retucio.camtweaks.module.ModuleManager;
import me.retucio.camtweaks.module.settings.*;
import me.retucio.camtweaks.ui.frames.ModuleFrame;
import me.retucio.camtweaks.ui.screen.ClickGUI;
import me.retucio.camtweaks.ui.frames.ClientSettingsFrame;
import me.retucio.camtweaks.ui.frames.SettingsFrame;
@@ -23,24 +24,29 @@ public class ConfigManager {
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static final File CONFIG_FILE = new File("camera_tweaks.json");
private static boolean loaded = false;
private static boolean loaded = false;
private static ClientConfig config = null;
// ------------------ MÉTODOS PRINCIPALES ------------------
// guardar configuraciones
public static void save() {
ensureConfig();
try (FileWriter writer = new FileWriter(CONFIG_FILE)) {
GSON.toJson(config, writer);
CameraTweaks.LOGGER.info("ajustes guardados");
} catch (IOException e) {
e.printStackTrace();
CameraTweaks.LOGGER.error("error al guardar ajustes", e);
}
}
// cargar configuraciones
public static void load() {
CameraTweaks.LOGGER.info("ajustes cargados");
CameraTweaks.LOGGER.info("cargando ajustes...");
if (!CONFIG_FILE.exists()) {
ensureConfig();
save();
@@ -49,79 +55,52 @@ public class ConfigManager {
try (FileReader reader = new FileReader(CONFIG_FILE)) {
config = GSON.fromJson(reader, ClientConfig.class);
CameraTweaks.LOGGER.info("ajustes cargados");
} catch (IOException e) {
e.printStackTrace();
CameraTweaks.LOGGER.error("no se pudieron cargar los ajustes, usando ajustes por defecto", e);
ensureConfig();
}
}
// aplicar configuraciones cargadas
public static void applyConfig() {
if (CameraTweaks.mc == null || ModuleManager.INSTANCE == null || config == null)
return;
if (!shouldApply()) return;
ModuleManager.INSTANCE.getModules().forEach(module -> {
if (config.moduleStates.containsKey(module.getName()))
module.setEnabled(config.moduleStates.get(module.getName())); // estados
module.getSettings().forEach(setting -> applySetting(module, setting));
if (config.settingsFrames.containsKey(module.getName())) {
int[] position = config.settingsFrames.get(module.getName());
ClickGUI.INSTANCE.openSettingsFrame(module, position[0], position[1]);
}
});
if (config.searchBarPosition != null && config.searchBarPosition.length == 2) {
ClickGUI.INSTANCE.getSearchBar().setX(config.searchBarPosition[0]);
ClickGUI.INSTANCE.getSearchBar().setY(config.searchBarPosition[1]);
}
ClientSettingsFrame.guiSettings.setEnabled(true);
ClientSettingsFrame.guiSettings.getSettings().forEach(setting -> applySetting(ClientSettingsFrame.guiSettings, setting));
CameraTweaks.LOGGER.info("módulos encendidos cargados");
CameraTweaks.LOGGER.info("ajustes de módulos cargados");
ClientConfig.FrameData moduleFrameData = config.extendableFrames.get("M");
if (moduleFrameData != null) {
ClickGUI.INSTANCE.getModulesFrame().x = moduleFrameData.x();
ClickGUI.INSTANCE.getModulesFrame().y = moduleFrameData.y();
ClickGUI.INSTANCE.getModulesFrame().extended = moduleFrameData.extended();
}
ClientConfig.FrameData guiSettingsData = config.extendableFrames.get("S");
if (guiSettingsData != null) {
ClickGUI.INSTANCE.getGuiSettingsFrame().x = guiSettingsData.x();
ClickGUI.INSTANCE.getGuiSettingsFrame().y = guiSettingsData.y();
ClickGUI.INSTANCE.getGuiSettingsFrame().extended = guiSettingsData.extended();
}
CameraTweaks.LOGGER.info("posiciones de frames cargadas");
ClickGUI.INSTANCE.refreshListButtons();
applyModuleStates();
applyModuleSettings();
applySettingsFrames();
applySearchBarPosition();
applyGuiSettings();
applyExtendableFrames();
loaded = true;
CameraTweaks.LOGGER.info("ajustes aplicados");
}
// obtener configuración actual
public static ClientConfig getConfig() {
ensureConfig();
return config;
}
// ------------------ GUARDAR VALORES INDIVIDUALES EN LA CONFIG. ------------------
public static void setModuleState(Module module) {
ensureConfig();
config.moduleStates.put(module.getName(), module.isEnabled());
save();
}
public static void setSetting(AbstractSetting setting, Object value) {
public static void setSetting(Setting setting, Object value) {
ensureConfig();
config.settings.put(setting.getModule().getName() + ":" + setting.getName(), value);
config.settings.put(getSettingKey(setting), value);
save();
}
public static void setFramePosition(SettingsFrame frame) {
ensureConfig();
config.settingsFrames.put(frame.module.getName(), new int[]{frame.x, frame.y});
config.settingsFrames.put(frame.module.getName(), new int[] {frame.x, frame.y});
save();
}
@@ -133,7 +112,7 @@ public class ConfigManager {
public static void setHudPosition(String id, int x, int y) {
ensureConfig();
config.hudPositions.put(id, new int[]{x, y});
config.hudPositions.put(id, new int[] {x, y});
save();
}
@@ -145,62 +124,197 @@ public class ConfigManager {
public static void setSearchBarPosition(int x, int y) {
ensureConfig();
config.searchBarPosition = new int[]{x, y};
config.searchBarPosition = new int[] {x, y};
save();
}
// ------------------ APLICAR AJUSTES ------------------
@SuppressWarnings({"rawtypes", "unchecked"})
public static void applySetting(Module parent, AbstractSetting setting) {
String id = parent.getName() + ":" + setting.getName();
if (config.settings.containsKey(id)) {
Object value = config.settings.get(id);
public static void applySetting(Module parent, Setting setting) {
String key = getSettingKey(setting);
switch (setting) {
case BooleanSetting b -> b.setEnabled((boolean) value);
case EnumSetting e -> e.setIndex(value instanceof Double val ? val.intValue() : (int) value);
case NumberSetting n -> n.setValue((double) value);
case StringSetting s -> s.setValue((String) value);
case KeySetting k -> k.setKey(value instanceof Double val ? val.intValue() : (int) value);
case ListSetting l -> {
if (value instanceof Map<?, ?> map) {
Map<Object, Boolean> converted = new HashMap<>();
for (Object option : l.getOptions()) {
Object key = String.valueOf(option);
Object bv = map.get(key);
converted.put(option, bv instanceof Boolean b && b);
}
l.setValues(converted);
}
} case ColorSetting c -> {
if (value instanceof Map<?, ?> map) {
Number r = (Number) map.get("r");
Number g = (Number) map.get("g");
Number b = (Number) map.get("b");
Number a = (Number) map.get("a");
Boolean rainbow = (Boolean) map.get("rb");
Number rainbowSpeed = (Number) map.get("rs");
Number saturation = (Number) map.get("sat");
Number brightness = (Number) map.get("bri");
if (!config.settings.containsKey(key)) return;
if (r != null && g != null && b != null && a != null)
c.setRGB(r.intValue(), g.intValue(), b.intValue(), a.intValue());
Object value = config.settings.get(key);
if (rainbow != null) c.setRainbow(rainbow);
if (rainbowSpeed != null) c.setRainbowSpeed(rainbowSpeed.intValue());
if (saturation != null) c.setSaturation(saturation.floatValue());
if (brightness != null) c.setBrightness(brightness.floatValue());
}
}
default -> {}
}
switch (setting) {
case BooleanSetting booleanSetting -> applyBooleanSetting(booleanSetting, value);
case EnumSetting enumSetting -> applyEnumSetting(enumSetting, value);
case NumberSetting numberSetting -> applyNumberSetting(numberSetting, value);
case StringSetting stringSetting -> applyStringSetting(stringSetting, value);
case KeySetting keySetting -> applyKeySetting(keySetting, value);
case ListSetting listSetting -> applyListSetting(listSetting, value);
case ColorSetting colorSetting -> applyColorSetting(colorSetting, value);
case OptionSetting optionSetting -> applyOptionSetting(optionSetting, value);
default -> CameraTweaks.LOGGER.warn("watafac queseso: {}", setting.getClass().getSimpleName());
}
}
private static void applyModuleStates() {
ModuleManager.INSTANCE.getModules().forEach(module -> {
if (config.moduleStates.containsKey(module.getName())) {
module.setEnabled(config.moduleStates.get(module.getName()));
}
});
CameraTweaks.LOGGER.info("estados de módulos aplicados");
}
private static void applyModuleSettings() {
ModuleManager.INSTANCE.getModules().forEach(module -> {
module.getSettings().forEach(setting -> applySetting(module, setting));
});
CameraTweaks.LOGGER.info("ajustes de módulos aplicados");
}
private static void applySettingsFrames() {
config.settingsFrames.forEach((moduleName, position) -> {
Module module = ModuleManager.INSTANCE.getModuleByName(moduleName);
ClickGUI.INSTANCE.openSettingsFrame(module, position[0], position[1]);
});
CameraTweaks.LOGGER.info("estados de marcos de ajustes aplicados");
}
private static void applySearchBarPosition() {
if (config.searchBarPosition != null && config.searchBarPosition.length == 2) {
ClickGUI.INSTANCE.getSearchBar().setX(config.searchBarPosition[0]);
ClickGUI.INSTANCE.getSearchBar().setY(config.searchBarPosition[1]);
}
CameraTweaks.LOGGER.info("posición de la barra de búsqueda aplicada");
}
private static void applyGuiSettings() {
ClientSettingsFrame.guiSettings.setEnabled(true);
ClientSettingsFrame.guiSettings.getSettings().forEach(setting -> {
applySetting(ClientSettingsFrame.guiSettings, setting);
});
CameraTweaks.LOGGER.info("ajustes del cliente aplicados");
}
private static void applyExtendableFrames() {
applyExtendableFrame(ClickGUI.INSTANCE.getModulesFrame());
applyExtendableFrame(ClickGUI.INSTANCE.getGuiSettingsFrame());
CameraTweaks.LOGGER.info("posiciones de marcos extendibles aplicadasa");
ClickGUI.INSTANCE.refreshListButtons();
}
private static void applyExtendableFrame(ModuleFrame frame) {
ClientConfig.FrameData frameData = config.extendableFrames.get("M");
if (frameData != null) {
frame.x = frameData.x();
frame.y = frameData.y();
frame.extended = frameData.extended();
}
}
private static void applyExtendableFrame(ClientSettingsFrame frame) {
ClientConfig.FrameData frameData = config.extendableFrames.get("S");
if (frameData != null) {
frame.x = frameData.x();
frame.y = frameData.y();
frame.extended = frameData.extended();
}
}
// ajustes de módulos
private static void applyBooleanSetting(BooleanSetting setting, Object value) {
if (value instanceof Boolean) {
setting.setEnabled((Boolean) value);
}
}
private static <T extends Enum<T>> void applyEnumSetting(EnumSetting<T> setting, Object value) {
if (value instanceof Double) {
setting.setIndex(((Double) value).intValue());
} else if (value instanceof Integer) {
setting.setIndex((Integer) value);
}
}
private static void applyNumberSetting(NumberSetting setting, Object value) {
if (value instanceof Double) {
setting.setValue((Double) value);
}
}
private static void applyStringSetting(StringSetting setting, Object value) {
if (value instanceof String) {
setting.setValue((String) value);
}
}
private static void applyKeySetting(KeySetting setting, Object value) {
if (value instanceof Double) {
setting.setKey(((Double) value).intValue());
} else if (value instanceof Integer) {
setting.setKey((Integer) value);
}
}
private static <T> void applyListSetting(ListSetting<T> setting, Object value) {
if (value instanceof Map<?, ?> map) {
Map<T, Boolean> convertedValues = new HashMap<>();
for (T option : setting.getOptions()) {
String key = setting.getDisplayName(option);
Object booleanValue = map.get(key);
convertedValues.put(option, booleanValue instanceof Boolean && (Boolean) booleanValue);
}
setting.setValues(convertedValues);
}
}
private static void applyColorSetting(ColorSetting setting, Object value) {
if (!(value instanceof Map<?, ?> map)) return;
Number r = (Number) map.get("r");
Number g = (Number) map.get("g");
Number b = (Number) map.get("b");
Number a = (Number) map.get("a");
if (r != null && g != null && b != null && a != null)
setting.setRGB(r.intValue(), g.intValue(), b.intValue(), a.intValue());
applyOptionalProperty(map, "rb", Boolean.class, setting::setRainbow);
applyOptionalProperty(map, "rs", Number.class, val -> setting.setRainbowSpeed(val.intValue()));
applyOptionalProperty(map, "sat", Number.class, val -> setting.setSaturation(val.floatValue()));
applyOptionalProperty(map, "bri", Number.class, val -> setting.setBrightness(val.floatValue()));
}
private static <T> void applyOptionSetting(OptionSetting<T> setting, Object value) {
if (value instanceof Double) {
int index = ((Double) value).intValue();
setting.setValue(setting.getOption(index));
}
}
private static <T> void applyOptionalProperty(Map<?, ?> map, String key, Class<T> type, java.util.function.Consumer<T> setter) {
Object value = map.get(key);
if (type.isInstance(value)) {
setter.accept(type.cast(value));
}
}
// ------------------ MÉTODOS DE AYUDA ------------------
private static boolean shouldApply() {
return CameraTweaks.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.getModule().getName() + ":" + setting.getName();
}
public static boolean hasLoaded() {
return loaded;
}
@@ -0,0 +1,21 @@
package me.retucio.camtweaks.event;
import net.minecraft.client.world.ClientWorld;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/**
* @see me.retucio.camtweaks.mixin.MinecraftClientMixin#onJoinWorld
*/
public class JoinWorldEvent extends Event {
private final ClientWorld world;
public JoinWorldEvent(ClientWorld world) {
this.world = world;
}
public ClientWorld getWorld() {
return world;
}
}
@@ -1,12 +1,14 @@
package me.retucio.camtweaks.event.events;
import io.netty.channel.ChannelFutureListener;
import me.retucio.camtweaks.event.Event;
import me.retucio.camtweaks.event.Stage;
import net.minecraft.network.packet.Packet;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/**
* @see me.retucio.camtweaks.mixin.ClientConnectionMixin#onSendPacketPre
* @see me.retucio.camtweaks.mixin.ClientConnectionMixin#onSendPacketPre
* @see me.retucio.camtweaks.mixin.ClientConnectionMixin#onSendPacketPost
* @see me.retucio.camtweaks.mixin.ClientConnectionMixin#onReceivePacket
*/
@@ -1,20 +1,20 @@
package me.retucio.camtweaks.event.events.camtweaks;
import me.retucio.camtweaks.event.Event;
import me.retucio.camtweaks.module.settings.AbstractSetting;
import me.retucio.camtweaks.module.settings.Setting;
// se genera cada que se cambia el valor de un ajuste
public class UpdateSettingEvent extends Event {
private final AbstractSetting setting;
private final Setting setting;
private boolean shouldSave;
public UpdateSettingEvent(AbstractSetting setting, boolean shouldSave) {
public UpdateSettingEvent(Setting setting, boolean shouldSave) {
this.setting = setting;
this.shouldSave = shouldSave;
}
public AbstractSetting getSetting() {
public Setting getSetting() {
return setting;
}
@@ -5,7 +5,7 @@ import me.retucio.camtweaks.module.ModuleManager;
import me.retucio.camtweaks.module.modules.ChatPlus;
import me.retucio.camtweaks.module.modules.Freecam;
import me.retucio.camtweaks.module.modules.NoRender;
import me.retucio.camtweaks.ui.HudRenderer;
import me.retucio.camtweaks.ui.hud.HudRenderer;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.hud.InGameHud;
@@ -4,6 +4,7 @@ import com.ibm.icu.util.CodePointTrie;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import com.llamalad7.mixinextras.sugar.Local;
import me.retucio.camtweaks.CameraTweaks;
import me.retucio.camtweaks.event.JoinWorldEvent;
import me.retucio.camtweaks.event.events.OpenScreenEvent;
import me.retucio.camtweaks.event.events.ShutdownEvent;
import me.retucio.camtweaks.event.events.TickEvent;
@@ -12,6 +13,7 @@ import me.retucio.camtweaks.module.ModuleManager;
import me.retucio.camtweaks.module.modules.FastUse;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;
import org.spongepowered.asm.mixin.Mixin;
@@ -70,4 +72,10 @@ public abstract class MinecraftClientMixin {
if (!fastUse.isEnabled()) return;
itemUseCooldown = fastUse.getCooldown(stack);
}
@Inject(method = "joinWorld", at = @At("HEAD"), cancellable = true)
private void onJoinWorld(ClientWorld world, CallbackInfo ci) {
JoinWorldEvent event = EVENT_BUS.post(new JoinWorldEvent(world));
if (event.isCancelled()) ci.cancel();
}
}
@@ -10,4 +10,7 @@ public interface HandledScreenAccessor {
@Accessor("focusedSlot")
Slot getFocusedSlot();
@Accessor("doubleClicking")
void setDoubleClicking(boolean doubleClicking);
}
@@ -1,12 +1,14 @@
package me.retucio.camtweaks.module;
import me.retucio.camtweaks.CameraTweaks;
import me.retucio.camtweaks.config.ClientConfig;
import me.retucio.camtweaks.config.ConfigManager;
import me.retucio.camtweaks.event.SubscribeEvent;
import me.retucio.camtweaks.event.events.camtweaks.ToggleModuleEvent;
import me.retucio.camtweaks.module.settings.BooleanSetting;
import me.retucio.camtweaks.module.settings.EnumSetting;
import me.retucio.camtweaks.module.settings.KeySetting;
import me.retucio.camtweaks.module.settings.AbstractSetting;
import me.retucio.camtweaks.module.settings.Setting;
import me.retucio.camtweaks.util.ChatUtil;
import net.minecraft.client.MinecraftClient;
import org.lwjgl.glfw.GLFW;
@@ -30,7 +32,7 @@ public class Module {
protected KeySetting bind = new KeySetting("tecla", "tecla asignada al módulo, ESC para desactivar", GLFW.GLFW_KEY_UNKNOWN);
protected BooleanSetting notify = new BooleanSetting("notificar", "notificar en el chat al activar / desactivar", true);
private final List<AbstractSetting> settings = new ArrayList<>();
private final List<Setting> settings = new ArrayList<>();
protected MinecraftClient mc = MinecraftClient.getInstance();
@@ -45,23 +47,26 @@ public class Module {
this.description = description;
addSettings(bind, keyMode, notify);
this.bind.setDefaultKey(key);
this.bind.setKey(key);
// puto marcos
if (ConfigManager.getConfig().settings.get(this.getName() + ":" + bind.getName()) == null)
this.bind.setKey(key);
}
// ajustes
public List<AbstractSetting> getSettings() {
public List<Setting> getSettings() {
return settings;
}
@SuppressWarnings("unchecked")
public <S extends AbstractSetting> S addSetting(AbstractSetting setting) {
public <S extends Setting> S addSetting(Setting setting) {
settings.add(setting);
setting.setModule(this);
return (S) setting; // por conveniencia
}
public void addSettings(AbstractSetting... settings) {
for (AbstractSetting setting : settings) addSetting(setting);
public void addSettings(Setting... settings) {
for (Setting setting : settings) addSetting(setting);
}
@@ -1,5 +1,6 @@
package me.retucio.camtweaks.module;
import me.retucio.camtweaks.CameraTweaks;
import me.retucio.camtweaks.event.EventBus;
import me.retucio.camtweaks.event.SubscribeEvent;
import me.retucio.camtweaks.module.modules.*;
@@ -16,10 +17,8 @@ public class ModuleManager {
public static ModuleManager INSTANCE;
private final List<Module> modules = new ArrayList<>();
private final EventBus eventBus;
public ModuleManager(EventBus bus) {
this.eventBus = bus;
public ModuleManager() {
addModules();
}
@@ -29,8 +28,10 @@ public class ModuleManager {
modules.add(new AnvilFont());
modules.add(new AttributeSwapper());
modules.add(new AutoSign());
modules.add(new BlockESP());
modules.add(new BlockOutline());
modules.add(new BossbarStack());
modules.add(new BreakingProgress());
modules.add(new BungeecordSpoofer());
modules.add(new ChatPlus());
modules.add(new ColoredSigns());
@@ -45,19 +46,24 @@ public class ModuleManager {
modules.add(new HandView());
modules.add(new Headhitters());
modules.add(new HUD());
modules.add(new InventoryPlus());
modules.add(new LightOverlay());
modules.add(new LogoutSpots());
modules.add(new Nametags());
modules.add(new NoMiningInterruptions());
modules.add(new NoRender());
modules.add(new Offhand());
modules.add(new PacketDelay());
modules.add(new PerspectivePlus());
modules.add(new PortalGUI());
modules.add(new Racist());
modules.add(new Reconnect());
modules.add(new Rotations());
modules.add(new RPackBypass());
modules.add(new ScreenshotPlus());
modules.add(new ShulkerPeek());
modules.add(new TimeChanger());
modules.add(new UIMove());
modules.add(new WarnLowDurability());
modules.add(new Zoom());
@@ -67,7 +73,7 @@ public class ModuleManager {
for (Module module : getEnabledModules()) {
for (Method method : module.getClass().getDeclaredMethods()) {
if (method.isAnnotationPresent(SubscribeEvent.class)) {
eventBus.register(module);
CameraTweaks.EVENT_BUS.register(module);
break;
}
}
@@ -0,0 +1,96 @@
package me.retucio.camtweaks.module.modules;
import me.retucio.camtweaks.event.SubscribeEvent;
import me.retucio.camtweaks.event.events.RenderWorldEvent;
import me.retucio.camtweaks.module.Module;
import me.retucio.camtweaks.module.settings.BooleanSetting;
import me.retucio.camtweaks.module.settings.ColorSetting;
import me.retucio.camtweaks.module.settings.ListSetting;
import me.retucio.camtweaks.module.settings.NumberSetting;
import me.retucio.camtweaks.util.Colors;
import me.retucio.camtweaks.util.Lists;
import me.retucio.camtweaks.util.render.RenderUtil;
import net.minecraft.block.Block;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3i;
import net.minecraft.util.shape.VoxelShape;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public class BlockESP extends Module {
public ListSetting<Block> blocks = addSetting(new ListSetting<>("bloques", "bloques a resaltar",
Lists.blockList, Lists.allFalse(Lists.blockList), Lists.blockNames));
public NumberSetting radius = addSetting(new NumberSetting("radio", "radio de búsqueda de bloques", 24, 2, 128, 1));
public BooleanSetting outlines = addSetting(new BooleanSetting("contorno", "renderizar contorno de bloques", true));
public ColorSetting outlineColor = addSetting(new ColorSetting("color del contorno", "color del contorno", Colors.CELESTE, false));
public NumberSetting lineWidth = addSetting(new NumberSetting("grosor del contorno", "grosor de las líneas del contorno", 1, 1, 5, 0.2));
public BooleanSetting fillings = addSetting(new BooleanSetting("relleno", "renderizar relleno de bloques", true));
public ColorSetting fillingColor = addSetting(new ColorSetting("color del relleno", "color del relleno", new Color(57, 177, 215, 67), false));
public BlockESP() {
super("resaltado de bloques", "te muestra la posición de cierto tipo de bloque renderizando una caja con su forma");
outlines.onUpdate(v -> {
outlineColor.setVisible(v);
lineWidth.setVisible(v);
});
fillings.onUpdate(v -> fillingColor.setVisible(v));
}
@SubscribeEvent
public void onRenderWorld(RenderWorldEvent event) {
if (mc.player == null || mc.world == null) return;
for (Block block : blocks.getOptions()) {
if (blocks.isEnabled(block)) {
List<BlockPos> blocksToHighlight = getNearbyBlocks(block);
for (BlockPos pos : blocksToHighlight) {
if (outlines.isEnabled()) {
RenderUtil.drawVoxelShapeOutline(
event.getMatrices(),
getVoxelShape(pos),
pos,
outlineColor.getColor(),
lineWidth.getFloatValue());
}
if (fillings.isEnabled()) {
RenderUtil.drawVoxelShapeFilled(
event.getMatrices(),
getVoxelShape(pos),
pos,
fillingColor.getColor());
}
}
}
}
}
private List<BlockPos> getNearbyBlocks(Block block) {
List<BlockPos> blockPosList = new ArrayList<>();
for (int i = -radius.getIntValue(); i < radius.getIntValue(); i++) {
for (int j = -radius.getIntValue(); j < radius.getIntValue(); j++) {
for (int k = -radius.getIntValue(); k < radius.getIntValue(); k++) {
BlockPos pos = mc.player.getBlockPos().add(new Vec3i(i, j, k));
if (mc.world.getBlockState(pos).getBlock() == block) {
blockPosList.add(pos);
}
}
}
}
return blockPosList;
}
private VoxelShape getVoxelShape(BlockPos pos) {
return mc.world.getBlockState(pos).getOutlineShape(mc.world, pos);
}
}
@@ -0,0 +1,80 @@
package me.retucio.camtweaks.module.modules;
import me.retucio.camtweaks.event.SubscribeEvent;
import me.retucio.camtweaks.event.events.RenderWorldEvent;
import me.retucio.camtweaks.module.Module;
import me.retucio.camtweaks.module.settings.BooleanSetting;
import me.retucio.camtweaks.module.settings.ColorSetting;
import me.retucio.camtweaks.module.settings.EnumSetting;
import me.retucio.camtweaks.module.settings.NumberSetting;
import me.retucio.camtweaks.util.render.RenderUtil;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.shape.VoxelShape;
import java.awt.*;
public class BreakingProgress extends Module {
public EnumSetting<BreakMode> breakMode = addSetting(new EnumSetting<>("modo de minado", "elige si el cubo se encoge o se dilata",
BreakMode.class, BreakMode.INWARDS));
public BooleanSetting outlines = addSetting(new BooleanSetting("contorno", "renderizar contorno", true));
public ColorSetting outlineColor = addSetting(new ColorSetting("color del contorno", "color del contorno",
new Color(0, 255, 0, 200), false));
public NumberSetting lineWidth = addSetting(new NumberSetting("grosor de línea", "grosor de las líneas del contorno", 1, 1, 5, 0.1));
public BooleanSetting fillings = addSetting(new BooleanSetting("relleno", "renderizar relleno", true));
public ColorSetting fillingColor = addSetting(new ColorSetting("color del relleno", "color del relleno",
new Color(0, 255, 0, 60), false));
public BreakingProgress() {
super("progreso de minado", "te muestra el progreso de minado de un bloque de manera más visible");
}
@SubscribeEvent
public void onRenderWorld(RenderWorldEvent event) {
if (mc.interactionManager == null || mc.world == null) return;
if (!(mc.crosshairTarget instanceof BlockHitResult hitResult)) return;
BlockPos pos = hitResult.getBlockPos();
int breakingProgress = mc.interactionManager.getBlockBreakingProgress();
if (breakingProgress <= 0) return;
float progress = breakingProgress / 10f;
VoxelShape shape = mc.world.getBlockState(pos).getOutlineShape(mc.world, pos);
if (shape.isEmpty()) return;
Box box = shape.getBoundingBox().offset(pos);
float shrinkFactor = breakMode.is(BreakMode.INWARDS)
? 1f - progress
: progress;
double centerX = (box.minX + box.maxX) / 2;
double centerY = (box.minY + box.maxY) / 2;
double centerZ = (box.minZ + box.maxZ) / 2;
double shrunkX = (box.maxX - box.minX) / 2 * shrinkFactor;
double shrunkY = (box.maxY - box.minY) / 2 * shrinkFactor;
double shrunkZ = (box.maxZ - box.minZ) / 2 * shrinkFactor;
Box scaledBox = new Box(
centerX - shrunkX, centerY - shrunkY, centerZ - shrunkZ,
centerX + shrunkX, centerY + shrunkZ, centerZ + shrunkZ
);
if (outlines.isEnabled()) RenderUtil.drawOutlineBox(event.getMatrices(), scaledBox, outlineColor.getColor(), lineWidth.getFloatValue());
if (fillings.isEnabled()) RenderUtil.drawFilledBox(event.getMatrices(), scaledBox, fillingColor.getColor());
}
public enum BreakMode {
INWARDS("para dentro"),
OUTWARDS("para fuera");
private final String name;
BreakMode(String name) { this.name = name; }
@Override public String toString() { return name; }
}
}
@@ -68,7 +68,7 @@ public class ChatPlus extends Module {
private SimpleDateFormat dateFormat;
private static final Pattern loggerRegex = Pattern.compile("\\n(\\n|\\s)+\\n");
private static final Pattern usernameRegex = Pattern.compile("^(?:<[0-9]{2}:[0-9]{2}>\\s)?<(.*?)>.*");
private static final Pattern usernameRegex = Pattern.compile("^(?:\\[[0-9]{2}:[0-9]{2}\\]\\s*)?(?:<([^<>\\s]+)>|([^<>\\s]+)).*");
private static final Pattern timestampRegex = Pattern.compile("^<\\d{1,2}:\\d{1,2}>");
private static final Pattern coordRegex = Pattern.compile("(?<x>-?\\d{3,}(?:\\.\\d*)?)(?:\\s+(?<y>-?\\d{1,3}(?:\\.\\d*)?))?\\s+(?<z>-?\\d{3,}(?:\\.\\d*)?)");
@@ -96,7 +96,7 @@ public class ChatPlus extends Module {
// agregar sellos de tiempo a los mensajes
if (timestamps.isEnabled()) {
Text timestamp = Text.literal("<" + dateFormat.format(new Date()) + "> ").formatted(Formatting.GRAY);
Text timestamp = Text.literal("[" + dateFormat.format(new Date()) + "] ").formatted(Formatting.GRAY);
message = Text.empty().append(timestamp).append(message);
}
@@ -178,6 +178,8 @@ public class ChatPlus extends Module {
if (usernameMatcher.matches()) {
String username = usernameMatcher.group(1);
if (username == null)
username = usernameMatcher.group(2);
PlayerListEntry entry = mc.getNetworkHandler().getPlayerListEntry(username);
if (entry != null) sender = entry.getProfile();
@@ -2,14 +2,17 @@ package me.retucio.camtweaks.module.modules;
import me.retucio.camtweaks.module.Module;
import me.retucio.camtweaks.module.settings.*;
import me.retucio.camtweaks.ui.screen.HudEditorScreen;
import me.retucio.camtweaks.ui.hud.CoordsElement;
import me.retucio.camtweaks.ui.hud.HudElement;
import me.retucio.camtweaks.ui.hud.HudRenderer;
import me.retucio.camtweaks.ui.hud.HudEditorScreen;
import org.lwjgl.glfw.GLFW;
import java.awt.*;
/** lógica del HUD manejada en:
* @see me.retucio.camtweaks.ui.HudRenderer
* @see me.retucio.camtweaks.ui.widgets.HudElement
* @see HudRenderer
* @see HudElement
* @see HudEditorScreen
*/
@@ -28,6 +31,7 @@ public class HUD extends Module {
public NumberSetting timezone = addSetting(new NumberSetting("zona horaria", "zona horaria en UTC+n", 1, -6, 6, 1));
public EnumSetting<TimeFormat> timeFormat = addSetting(new EnumSetting<>("formato de la hora", "12h o 24h", TimeFormat.class, TimeFormat.TWENTY_FOUR_HOUR));
public StringSetting customText = addSetting(new StringSetting("texto custom", "marca de agua (dejar vacío para quitar)", "adolf jitler inshtagram feishbuc twiter", 40));
public EnumSetting<CoordsMode> coordsMode = addSetting(new EnumSetting<>("modo de coordenadas", "qué coordenadas mostrar", CoordsMode.class, CoordsMode.OVERWORLD));
public HUD() {
super("HUD", "superposición de la pantalla con info. adicional");
@@ -41,4 +45,14 @@ public class HUD extends Module {
TimeFormat(String name) { this.name = name; }
@Override public String toString() { return name; }
}
public enum CoordsMode {
OVERWORLD("superficie"),
NETHER("nether"),
BOTH("ambas");
private final String name;
CoordsMode(String name) { this.name = name; }
@Override public String toString() { return name; }
}
}
@@ -0,0 +1,70 @@
package me.retucio.camtweaks.module.modules;
import me.retucio.camtweaks.event.Event;
import me.retucio.camtweaks.event.SubscribeEvent;
import me.retucio.camtweaks.event.events.KeyEvent;
import me.retucio.camtweaks.event.events.MouseClickEvent;
import me.retucio.camtweaks.mixin.accessor.HandledScreenAccessor;
import me.retucio.camtweaks.module.Module;
import me.retucio.camtweaks.module.settings.KeySetting;
import me.retucio.camtweaks.util.InventoryUtil;
import me.retucio.camtweaks.util.KeyUtil;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.screen.slot.Slot;
import org.lwjgl.glfw.GLFW;
public class InventoryPlus extends Module {
public KeySetting row1key = addSetting(new KeySetting("fila 1", "tecla para mover items a la primera fila", GLFW.GLFW_KEY_A));
public KeySetting row2key = addSetting(new KeySetting("fila 2", "tecla para mover items a la segunda fila", GLFW.GLFW_KEY_S));
public KeySetting row3key = addSetting(new KeySetting("fila 3", "tecla para mover items a la tercera fila", GLFW.GLFW_KEY_D));
public InventoryPlus() {
super("inventario plus", "mueve ítems del inventario usando solo el teclado");
}
@SubscribeEvent
public void onKey(KeyEvent event) {
if (event.getAction() == GLFW.GLFW_RELEASE) return;
processInput(event.getKey(), event);
}
@SubscribeEvent
public void onMouseButton(MouseClickEvent event) {
if (event.getAction() == GLFW.GLFW_RELEASE) return;
processInput(event.getButton(), event);
}
private void processInput(int inputCode, Event event) {
if (!(mc.currentScreen instanceof HandledScreen<?> screen) || mc.player == null) return;
Slot focusedSlot = ((HandledScreenAccessor) screen).getFocusedSlot();
if (focusedSlot == null) return;
int containerSlot = focusedSlot.id;
int hotbarKeyIndex = InventoryUtil.getSlotNumberFromKey(inputCode);
if (hotbarKeyIndex == -1) return;
int rowOffset = InventoryUtil.getRowOffset(screen);
if (KeyUtil.isKeyDown(row1key.getKey())) {
event.cancel();
swapWithRow(screen, containerSlot, hotbarKeyIndex, rowOffset);
}
else if (KeyUtil.isKeyDown(row2key.getKey())) {
event.cancel();
swapWithRow(screen, containerSlot, hotbarKeyIndex, rowOffset + 9);
}
else if (KeyUtil.isKeyDown(row3key.getKey())) {
event.cancel();
swapWithRow(screen, containerSlot, hotbarKeyIndex, rowOffset + 18);
}
}
private void swapWithRow(HandledScreen<?> screen, int containerSlot, int column, int rowOffset) {
int targetContainerSlot = InventoryUtil.calculateTargetSlot(screen, containerSlot, column, rowOffset);
if (targetContainerSlot != -1) {
InventoryUtil.swapSlots(containerSlot, targetContainerSlot, screen);
}
}
}
@@ -50,6 +50,7 @@ public class LightOverlay extends Module {
}
for (BlockPos block : blocks) {
if (mc.world.getBlockState(block).isAir() || !mc.world.getBlockState(block.up()).isAir()) continue;
if (!mc.world.isTopSolid(block, mc.player) || !mc.world.getBlockState(block).isOpaque()) continue;
int light = mc.world.getLightLevel(LightType.BLOCK, block.up());
@@ -9,6 +9,8 @@ import me.retucio.camtweaks.module.ModuleManager;
import me.retucio.camtweaks.module.settings.BooleanSetting;
import me.retucio.camtweaks.module.settings.ColorSetting;
import me.retucio.camtweaks.module.settings.EnumSetting;
import me.retucio.camtweaks.module.settings.NumberSetting;
import me.retucio.camtweaks.util.MiscUtil;
import me.retucio.camtweaks.util.render.RenderUtil;
import net.minecraft.client.network.OtherClientPlayerEntity;
import net.minecraft.client.network.PlayerListEntry;
@@ -33,6 +35,7 @@ public class LogoutSpots extends Module {
public BooleanSetting outlines = addSetting(new BooleanSetting("contorno", "renderizar contorno de la caja (lados)", true));
public ColorSetting outlineColor = addSetting(new ColorSetting("color del contorno", "Color de las líneas", new Color(255, 0, 0, 230), false));
public NumberSetting lineWidth = addSetting(new NumberSetting("grosor de línea", "grosor de las líneas del contorno", 1.5, 0.5, 5, 0.1));
public BooleanSetting filling = addSetting(new BooleanSetting("relleno", "renderizar relleno de la caja (caras)", true));
public ColorSetting fillingColor = addSetting(new ColorSetting("color del relleno", "Color de los lados", new Color(230, 0, 0, 55), false));
@@ -40,8 +43,6 @@ public class LogoutSpots extends Module {
public BooleanSetting fullHeight = addSetting(new BooleanSetting("hitbox completa", "renderizar la caja completa de la hitbox, o solo marcar la posición", true));
public BooleanSetting dummy = addSetting(new BooleanSetting("monigote", "spawnear un monigote para marcar la posición", true));
public EnumSetting<Nametags.HealthMode> healthMode = addSetting(new EnumSetting<>("formato de vida", "en qué formato mostrar la vida del jugador",
Nametags.HealthMode.class, Nametags.HealthMode.POINTS));
private final List<LogoutEntry> players = new ArrayList<>();
private final List<PlayerListEntry> lastPlayerList = new ArrayList<>();
@@ -65,7 +66,6 @@ public class LogoutSpots extends Module {
dummy.onUpdate(v -> {
if (!v) removeDummies();
healthMode.setVisible(v);
});
}
@@ -215,7 +215,6 @@ public class LogoutSpots extends Module {
public final UUID uuid;
public final String name;
public final int health;
public final String logoutTime;
public final String dummyName;
@@ -234,45 +233,25 @@ public class LogoutSpots extends Module {
this.uuid = player.getUuid();
this.name = player.getName().getString();
this.health = Math.round(player.getHealth() + player.getAbsorptionAmount());
this.logoutTime = getLogoutTime();
this.logoutTime = MiscUtil.getCurrentFormattedTime();
String healthText = healthMode.is(Nametags.HealthMode.HEARTS)
? String.format("%.2f", (float) health / 2)
: health + "hp";
this.dummyName = name + " [" + healthText + "] (" + logoutTime + ")";
this.dummyName = name + " (" + logoutTime + ")";
this.dummy = ModuleManager.INSTANCE.getModuleByClass(FakePlayer.class).addPlayer(player, dummyName);
this.dummy.updatePositionAndAngles(x + halfWidth, y, z + halfWidth,
player.getYaw(), player.getPitch());
}
private String getLogoutTime() {
try {
HUD hud = ModuleManager.INSTANCE.getModuleByClass(HUD.class);
Instant instant = Instant.now();
ZoneOffset offset = ZoneOffset.ofHours(hud.timezone.getIntValue());
LocalTime logoutTime = LocalTime.from(instant.atOffset(offset));
boolean is24 = hud.timeFormat.is(HUD.TimeFormat.TWENTY_FOUR_HOUR);
DateTimeFormatter format = DateTimeFormatter.ofPattern(is24 ? "HH:mm" : "hh:mm a");
return logoutTime.format(format);
} catch (Exception e) {
return "??:??";
}
}
public void renderBox(MatrixStack matrices) {
if (fullHeight.isEnabled()) {
if (outlines.isEnabled())
RenderUtil.drawOutlineBox(matrices, new Box(x, y, z, x + xWidth, y + height, z + zWidth), outlineColor.getColor(), 1.5);
RenderUtil.drawOutlineBox(matrices, new Box(x, y, z, x + xWidth, y + height, z + zWidth), outlineColor.getColor(), lineWidth.getFloatValue());
if (filling.isEnabled())
RenderUtil.drawFilledBox(matrices, new Box(x, y, z, x + xWidth, y + height, z + zWidth), fillingColor.getColor());
} else {
if (outlines.isEnabled()) {
Box bottomBox = new Box(x, y, z, x + xWidth, y + 0.01, z + zWidth);
RenderUtil.drawOutlineBox(matrices, bottomBox, outlineColor.getColor(), 1.5);
RenderUtil.drawOutlineBox(matrices, bottomBox, outlineColor.getColor(), lineWidth.getFloatValue());
}
if (filling.isEnabled()) {
RenderUtil.drawBlockFaceFilled(matrices,
@@ -8,6 +8,7 @@ import me.retucio.camtweaks.module.settings.EnumSetting;
import me.retucio.camtweaks.module.settings.ListSetting;
import me.retucio.camtweaks.util.Lists;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LazyEntityReference;
import net.minecraft.entity.LivingEntity;
@@ -24,6 +25,7 @@ import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@@ -39,8 +41,9 @@ import java.util.concurrent.Executors;
public class Nametags extends Module {
Map<EntityType<?>, Boolean> defaultEntities = Lists.allFalse(Lists.entityList);
public ListSetting<EntityType<?>> entities = addSetting(new ListSetting<>("entidades", "entidades cuyo nametag será visible",
Lists.entityList, Lists.allFalse(Lists.entityList), Lists.entityNames));
Lists.entityList, defaultEntities, Lists.entityNames));
public BooleanSetting alwaysVisible = addSetting(new BooleanSetting("siempre mostrar nametags", "mostrar nametag cuando el jugador está agachado o es invisible", false));
public BooleanSetting health = addSetting(new BooleanSetting("mostrar vida", "muestra la vida de una entidad en su nametag", true));
@@ -62,17 +65,22 @@ public class Nametags extends Module {
super("nametags", "modifica la manera en la que se renderizan los nametags");
// entidades activadas por defecto
entities.setEnabled(EntityType.PLAYER, true);
entities.setEnabled(EntityType.ITEM, true);
entities.setEnabled(EntityType.ARROW, true);
entities.setEnabled(EntityType.SPECTRAL_ARROW, true);
entities.setEnabled(EntityType.TRIDENT, true);
entities.setDefaultValues(entities.getValues());
defaultEntities.replace(EntityType.PLAYER, true);
defaultEntities.replace(EntityType.ITEM, true);
defaultEntities.replace(EntityType.ARROW, true);
defaultEntities.replace(EntityType.SPECTRAL_ARROW, true);
defaultEntities.replace(EntityType.TRIDENT, true);
entities.setDefaultValues(defaultEntities);
health.onUpdate(v -> healthMode.setVisible(v));
entities.onUpdate(entities -> {
items.setVisible(entities.get(EntityType.ITEM));
boolean anyProjectile = entities.get(EntityType.TRIDENT)
|| entities.get(EntityType.ARROW)
|| entities.get(EntityType.SPECTRAL_ARROW);
showProjectileDamage.setVisible(anyProjectile);
});
}
@@ -0,0 +1,83 @@
package me.retucio.camtweaks.module.modules;
import me.retucio.camtweaks.module.Module;
import me.retucio.camtweaks.module.settings.BooleanSetting;
import me.retucio.camtweaks.module.settings.NumberSetting;
import me.retucio.camtweaks.module.settings.OptionSetting;
import me.retucio.camtweaks.util.Lists;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket;
import net.minecraft.screen.slot.SlotActionType;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
public class Offhand extends Module {
public OptionSetting<Item> item = addSetting(new OptionSetting<>("ítem", "ítem a equipar",
Lists.itemList, Items.TOTEM_OF_UNDYING, Lists.itemNames));
public NumberSetting delaySetting = addSetting(new NumberSetting("delay", "delay del cambiazo (en ticks)", 0, 0, 20, 1));
public BooleanSetting override = addSetting(new BooleanSetting("anular", "ignora que ya haya un ítem en la mano secundaria", true));
private int delay;
private boolean holdingItem;
public Offhand() {
super("mano secundaria", "automáticamente equipa un ítem en la mano secundaria");
}
@Override
public void onTick() {
if (mc.player == null || mc.interactionManager == null) return;
if (holdingItem && mc.player.getOffHandStack().getItem() != item.getValue())
delay = Math.max(delaySetting.getIntValue(), delay);
holdingItem = mc.player.getOffHandStack().getItem() == item.getValue();
if (delay > 0) {
delay--;
return;
}
if (holdingItem || (!mc.player.getOffHandStack().isEmpty()
&& !override.isEnabled()))
return;
if (mc.player.playerScreenHandler == mc.player.currentScreenHandler) {
for (int i = 9; i < 45; i++) {
if (mc.player.getInventory().getStack(i >= 36 ? i - 36 : i).getItem() == item.getValue()) {
boolean itemInOffhand = !mc.player.getOffHandStack().isEmpty();
mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, i, 0, SlotActionType.PICKUP, mc.player);
mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, 45, 0, SlotActionType.PICKUP, mc.player);
if (itemInOffhand)
mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, i, 0, SlotActionType.PICKUP, mc.player);
delay = delaySetting.getIntValue();
return;
}
}
} else {
for (int i = 0; i < 9; i++) {
if (mc.player.getInventory().getStack(i).getItem() == item.getValue()) {
if (i != mc.player.getInventory().getSelectedSlot()) {
mc.player.getInventory().setSelectedSlot(i);
mc.player.networkHandler.sendPacket(new UpdateSelectedSlotC2SPacket(i));
}
mc.player.networkHandler.sendPacket(new PlayerActionC2SPacket(
PlayerActionC2SPacket.Action.SWAP_ITEM_WITH_OFFHAND,
BlockPos.ORIGIN,
Direction.DOWN));
delay = delaySetting.getIntValue();
return;
}
}
}
}
}
@@ -0,0 +1,148 @@
package me.retucio.camtweaks.module.modules;
import me.retucio.camtweaks.event.JoinWorldEvent;
import me.retucio.camtweaks.event.SubscribeEvent;
import me.retucio.camtweaks.event.events.DisconnectEvent;
import me.retucio.camtweaks.event.events.PacketEvent;
import me.retucio.camtweaks.module.Module;
import me.retucio.camtweaks.module.settings.EnumSetting;
import me.retucio.camtweaks.module.settings.NumberSetting;
import me.retucio.camtweaks.util.ChatUtil;
import me.retucio.camtweaks.util.NetworkUtil;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.listener.PacketListener;
import net.minecraft.network.message.SentMessage;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.c2s.common.CustomPayloadC2SPacket;
import net.minecraft.network.packet.c2s.common.KeepAliveC2SPacket;
import net.minecraft.network.packet.s2c.common.KeepAliveS2CPacket;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class PacketDelay extends Module {
public NumberSetting delay = addSetting(new NumberSetting("delay", "delay a añadir a los paquetes, en milisegundos", 1500, 0, 3000, 5));
public EnumSetting<Directions> directions = addSetting(new EnumSetting<>("dirección", "dirección de los paquetes a los que añadir delay",
Directions.class, Directions.BOTH));
public EnumSetting<Packets> packets = addSetting(new EnumSetting<>("paquetes", "paquetes a los que aplicar el delay",
Packets.class, Packets.ALL));
private final List<DelayedPacket> delayedPackets = new CopyOnWriteArrayList<>();
private long lastProcessTime = 0;
public PacketDelay() {
super("delay de paquetes", "aplica un delay a los paquetes");
}
@Override
public void onDisable() {
for (DelayedPacket delayedPacket : delayedPackets)
processDelayedPacket(delayedPacket);
delayedPackets.clear();
super.onDisable();
}
@Override
public void onTick() {
if (mc.player == null || mc.world == null || mc.getNetworkHandler() == null) {
delayedPackets.clear();
return;
}
long currentTime = System.currentTimeMillis();
if (currentTime - lastProcessTime < 50) return;
lastProcessTime = currentTime;
List<DelayedPacket> toProcess = new ArrayList<>();
for (DelayedPacket packet : delayedPackets) {
if (System.currentTimeMillis() >= packet.scheduledTime())
toProcess.add(packet);
}
for (DelayedPacket packet : toProcess) {
processDelayedPacket(packet);
delayedPackets.remove(packet);
}
}
@SubscribeEvent
public void onPacketSend(PacketEvent.Send event) {
if (directions.is(Directions.S2C)
|| mc.player == null || mc.world == null || mc.getNetworkHandler() == null
|| (event.getPacket() instanceof KeepAliveC2SPacket && !packets.is(Packets.OTHERS)))
return;
event.cancel();
delayedPackets.add(new DelayedPacket(
event.getPacket(),
System.currentTimeMillis() + delay.getLongValue(),
true,
mc.getNetworkHandler().getConnection().getPacketListener()
));
}
@SubscribeEvent
public void onPacketReceive(PacketEvent.Receive event) {
if (mc.player == null || mc.world == null
|| mc.getNetworkHandler() == null || mc.getNetworkHandler().getConnection() == null
|| (event.getPacket() instanceof KeepAliveS2CPacket && !packets.is(Packets.OTHERS)))
return;
event.cancel();
ClientConnection connection = mc.getNetworkHandler().getConnection();
delayedPackets.add(new DelayedPacket(
event.getPacket(),
System.currentTimeMillis() + delay.getLongValue(),
false,
connection.getPacketListener()
));
}
@SubscribeEvent
public void onJoinWorld(JoinWorldEvent event) {
ChatUtil.error("delay de paquetes no funciona en un solo jugador");
toggle();
}
private void processDelayedPacket(DelayedPacket delayedPacket) {
if (mc.getNetworkHandler() == null) return;
if (delayedPacket.isOutgoing()) {
NetworkUtil.sendPacketNoEvent(delayedPacket.packet());
} else {
if (delayedPacket.packetListener != null && mc.getNetworkHandler().getConnection() != null) {
NetworkUtil.receivePacketNoEvent(delayedPacket.packet(), delayedPacket.packetListener());
} else {
NetworkUtil.receivePacketNoEvent(delayedPacket.packet());
}
}
}
private record DelayedPacket(Packet<?> packet, long scheduledTime, boolean isOutgoing, PacketListener packetListener) {}
public enum Directions {
C2S("cliente a server"),
S2C("server a cliente"),
BOTH("ambos");
private final String name;
Directions(String name) { this.name = name; }
@Override public String toString() { return name; }
}
public enum Packets {
KEEP_ALIVE("paquetes KeepAlive"),
OTHERS("todos menos KeepAlive"),
ALL("todos");
private final String name;
Packets(String name) { this.name = name; }
@Override public String toString() { return name; }
}
}
@@ -0,0 +1,59 @@
package me.retucio.camtweaks.module.modules;
import me.retucio.camtweaks.module.Module;
import me.retucio.camtweaks.util.EntityUtil;
import net.minecraft.entity.Entity;
import net.minecraft.entity.mob.EndermanEntity;
import java.util.ArrayList;
import java.util.List;
public class Racist extends Module {
private int lookTimer;
private final List<EndermanEntity> lookedEndermen = new ArrayList<>();
public Racist() {
super("racismo", "amego segarro");
}
@Override
public void onDisable() {
lookedEndermen.clear();
super.onDisable();
}
@Override
public void onTick() {
if (mc.world == null || mc.player == null) return;
for (Entity entity : mc.world.getEntities()) {
if (!(entity instanceof EndermanEntity enderman)) continue;
if (shouldLookAt(enderman)) {
lookAtEnderman(enderman);
lookedEndermen.add(enderman);
lookTimer = 0;
return;
}
}
lookTimer++;
}
private boolean shouldLookAt(EndermanEntity enderman) {
return !(lookedEndermen.contains(enderman)) && lookTimer >= 10
&& EntityUtil.hasLineOfSight(mc.player, enderman);
}
private void lookAtEnderman(EndermanEntity enderman) {
double yaw = EntityUtil.getYaw(enderman);
double pitch = EntityUtil.getPitch(enderman, EntityUtil.Target.HEAD);
mc.player.setYaw((float) yaw);
mc.player.setPitch((float) pitch);
}
}
@@ -10,6 +10,7 @@ import me.retucio.camtweaks.ui.screen.PreviewScreen;
import me.retucio.camtweaks.util.ChatUtil;
import me.retucio.camtweaks.util.Colors;
import me.retucio.camtweaks.util.InventoryUtil;
import me.retucio.camtweaks.util.MiscUtil;
import net.minecraft.block.ShulkerBoxBlock;
import net.minecraft.client.gui.screen.Screen;
@@ -94,11 +95,11 @@ public class ShulkerPeek extends Module {
} else return;
if (stack.getItem() == Items.ENDER_CHEST) {
if (MiscUtil.getEchestInv() == null) {
if (InventoryUtil.getEchestInv() == null) {
ChatUtil.warn("abre un enderchest primero");
return;
}
mc.setScreen(new PreviewScreen(MiscUtil.getEchestInv(), mc.currentScreen));
mc.setScreen(new PreviewScreen(InventoryUtil.getEchestInv(), mc.currentScreen));
return;
}
@@ -0,0 +1,88 @@
package me.retucio.camtweaks.module.modules;
import me.retucio.camtweaks.mixin.accessor.KeyBindingAccessor;
import me.retucio.camtweaks.module.Module;
import me.retucio.camtweaks.module.settings.ListSetting;
import me.retucio.camtweaks.ui.screen.ClickGUI;
import me.retucio.camtweaks.util.KeyUtil;
import me.retucio.camtweaks.util.Lists;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.option.KeyBinding;
import net.minecraft.screen.GenericContainerScreenHandler;
import net.minecraft.screen.ScreenHandlerType;
import java.util.Arrays;
import java.util.List;
public class UIMove extends Module {
public ListSetting<ScreenHandlerType<?>> screens = addSetting(new ListSetting<>("interfaces", "interfaces en las que te podrás mover",
Lists.screenList, Lists.allTrue(Lists.screenList), Lists.screenNames));
private List<KeyBinding> movementKeys;
private final ScreenHandlerType<?> inventoryHandlerType = ScreenHandlerType.register(
"player_inventory", GenericContainerScreenHandler::createGeneric9x3);
private final ScreenHandlerType<?> clickGuiHandlerType = ScreenHandlerType.register(
"camtweaks_clickgui", GenericContainerScreenHandler::createGeneric9x3); // 9x3 porque no importa (creo)
public UIMove() {
super("moverse en interfaz", "te permite seguir usando las teclas de movimiento aún estando en ciertas interfaces");
screens.addOption(inventoryHandlerType, true, "inventario");
screens.addOption(clickGuiHandlerType, true, "interfaz del mod");
screens.onUpdate(v -> unpress());
}
@Override
public void onEnable() {
movementKeys = Arrays.asList(
mc.options.forwardKey,
mc.options.backKey,
mc.options.leftKey,
mc.options.rightKey,
mc.options.jumpKey,
mc.options.sneakKey,
mc.options.sprintKey);
super.onEnable();
}
@Override
public void onDisable() {
unpress();
super.onDisable();
}
@Override
public void onTick() {
if (mc.player == null || mc.options == null || mc.currentScreen == null) return;
ScreenHandlerType<?> handler = null;
if (mc.currentScreen == ClickGUI.INSTANCE)
handler = clickGuiHandlerType;
if (mc.currentScreen instanceof HandledScreen<?> screen) {
try {
handler = screen.getScreenHandler().getType();
} catch (UnsupportedOperationException e) {
handler = inventoryHandlerType;
}
}
if (handler == null || !screens.isEnabled(handler)) return;
for (KeyBinding kb : movementKeys) {
kb.setPressed(KeyUtil.isKeyDown((
(KeyBindingAccessor) kb).getBoundKey().getCode()));
}
}
private void unpress() {
if (movementKeys == null) return;
for (KeyBinding kb : movementKeys) {
kb.setPressed(false);
}
}
}
@@ -3,9 +3,12 @@ package me.retucio.camtweaks.module.modules;
import me.retucio.camtweaks.module.Module;
import me.retucio.camtweaks.module.settings.BooleanSetting;
import me.retucio.camtweaks.module.settings.NumberSetting;
import me.retucio.camtweaks.module.settings.OptionSetting;
import me.retucio.camtweaks.util.ChatUtil;
import me.retucio.camtweaks.util.Lists;
import net.minecraft.item.ItemStack;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
@@ -15,19 +18,29 @@ import java.util.ArrayList;
import java.util.List;
// al parecer DamageItemEvent no se lanza si estás en un server de Paper, o sea que ahora se usa onTick()
public class WarnLowDurability extends Module {
public NumberSetting limitPercentage = addSetting(new NumberSetting("porcentaje", "porcentaje de durabilidad restante a la que se te avisa",
5, 1, 100, 1));
public BooleanSetting message = addSetting(new BooleanSetting("mensaje", "enviar un mensaje para alertar al usuario", true));
public BooleanSetting sound = addSetting(new BooleanSetting("sonido", "reproducir un sonido para alertar al usuario", true));
public BooleanSetting message = addSetting(new BooleanSetting("enviar mensaje", "enviar un mensaje para alertar al usuario", true));
public BooleanSetting playSound = addSetting(new BooleanSetting("reproducir sonido", "reproducir un sonido para alertar al usuario", true));
public OptionSetting<SoundEvent> sound = addSetting(new OptionSetting<>("sonido", "qué sonido reproducir",
Lists.soundList, SoundEvents.BLOCK_NOTE_BLOCK_BELL.value(), Lists.soundNames));
public NumberSetting volume = addSetting(new NumberSetting("volumen", "volumen del sonido", 70, 0, 125, 1));
public NumberSetting pitch = addSetting(new NumberSetting("frecuencia", "altura del sonido", 70, 0, 125, 1));
private final List<ItemStack> warned = new ArrayList<>();
public WarnLowDurability() {
super("aviso de baja dur.", "te avisa cuando la herramienta que sostengas sobrepase un límite de durabilidad");
playSound.onUpdate(v -> {
sound.setVisible(v);
volume.setVisible(v);
pitch.setVisible(v);
});
}
@Override
@@ -39,9 +52,13 @@ public class WarnLowDurability extends Module {
float percentage = (1 - (float) stack.getDamage() / stack.getMaxDamage()) * 100;
if (percentage <= limitPercentage.getValue()) {
if (sound.isEnabled())
if (playSound.isEnabled())
mc.world.playSound(mc.player, mc.player.getBlockPos(),
SoundEvents.BLOCK_BELL_USE, SoundCategory.AMBIENT, 1, 1);
sound.getValue(),
SoundCategory.AMBIENT,
toExponential(volume),
toExponential(pitch)
);
if (message.isEnabled()) {
String customName = stack.getCustomName() == null ? "" : " \"" + stack.getCustomName().getString() + "\"";
@@ -61,4 +78,15 @@ public class WarnLowDurability extends Module {
warned.clear();
super.onDisable();
}
// el sistema decibélico es un sistema logarítmico
private float toExponential(NumberSetting setting) {
double linear = setting.getValue();
double normalized = linear / (setting.getMax() - setting.getMax() / 4);
double exponential = Math.pow(normalized, 3);
if (exponential < 0.01) exponential = 0;
return (float) exponential;
}
}
@@ -1,12 +1,9 @@
package me.retucio.camtweaks.module.settings;
import me.retucio.camtweaks.CameraTweaks;
import me.retucio.camtweaks.event.events.camtweaks.UpdateSettingEvent;
import java.util.function.Consumer;
// ajuste booleano, es decir, o se encuentra encencido o apagado (similar a un interruptor)
public class BooleanSetting extends AbstractSetting {
public class BooleanSetting extends Setting {
private boolean defaultValue;
private boolean enabled;
@@ -2,14 +2,13 @@ package me.retucio.camtweaks.module.settings;
import me.retucio.camtweaks.util.Colors;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import java.awt.*;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
public class ColorSetting extends AbstractSetting {
public class ColorSetting extends Setting {
private Color color;
private Consumer<Color> updateListener;
@@ -1,14 +1,11 @@
package me.retucio.camtweaks.module.settings;
import me.retucio.camtweaks.CameraTweaks;
import me.retucio.camtweaks.event.events.camtweaks.UpdateSettingEvent;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
// ajuste que te deja elegir entre distintas opciones definidas, dentro de un Enum
public class EnumSetting<E extends Enum<E>> extends AbstractSetting {
public class EnumSetting<E extends Enum<E>> extends Setting {
private final List<E> values;
private E defaultValue;
@@ -9,7 +9,7 @@ import org.lwjgl.glfw.GLFW;
import java.util.function.Consumer;
public class KeySetting extends AbstractSetting {
public class KeySetting extends Setting {
private int key;
private int defaultKey;
@@ -1,16 +1,14 @@
package me.retucio.camtweaks.module.settings;
import me.retucio.camtweaks.CameraTweaks;
import me.retucio.camtweaks.event.events.camtweaks.UpdateSettingEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
public class ListSetting<T> extends AbstractSetting {
public class ListSetting<T> extends Setting {
private final List<T> options;
private List<T> options;
private Map<T, Boolean> values;
private Map<T, Boolean> defaultValues;
private Map<T, String> displayNames = null;
@@ -19,7 +17,7 @@ public class ListSetting<T> extends AbstractSetting {
public ListSetting(String name, String description, List<T> options, Map<T, Boolean> initialValues) {
super(name, description);
this.options = options;
this.options = new ArrayList<>(options);
this.defaultValues = new HashMap<>();
for (T option : options) {
@@ -66,6 +64,25 @@ public class ListSetting<T> extends AbstractSetting {
defaultValues = values;
}
public Map<String, Boolean> getConfigValues() {
Map<String, Boolean> configValues = new HashMap<>();
for (int i = 0; i < values.size(); i++)
configValues.put(getDisplayName(options.get(i)), values.get(options.get(i)));
return configValues;
}
public void addOption(T option, boolean value, String displayName) {
if (!(this.options instanceof ArrayList))
this.options = new ArrayList<>(this.options);
this.options.add(option);
this.values.put(option, value);
this.defaultValues.put(option, value);
if (this.displayNames != null)
this.displayNames.put(option, displayName);
}
public void reset() {
values.clear();
values.putAll(defaultValues);
@@ -1,12 +1,9 @@
package me.retucio.camtweaks.module.settings;
import me.retucio.camtweaks.CameraTweaks;
import me.retucio.camtweaks.event.events.camtweaks.UpdateSettingEvent;
import java.util.function.Consumer;
// ajuste numérico, es decir, que eliges un valor númerico entre el mínimo y el máximo disponibles
public class NumberSetting extends AbstractSetting {
public class NumberSetting extends Setting {
private double value;
private double defaultValue;
@@ -0,0 +1,98 @@
package me.retucio.camtweaks.module.settings;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
public class OptionSetting<T> extends Setting{
List<T> options = new ArrayList<>();
Map<T, String> displayNames;
T option;
T defaultOption;
private Consumer<T> updateListener;
public OptionSetting(String name, String description, List<T> options, T defaultOption) {
super(name, description);
this.options = options;
this.option = defaultOption;
this.defaultOption = defaultOption;
}
public OptionSetting(String name, String description, List<T> options, T defaultOption, Map<T, String> displayNames) {
super(name, description);
this.options = options;
this.option = defaultOption;
this.defaultOption = defaultOption;
this.displayNames = displayNames;
}
public T getValue() {
return option;
}
public void setValue(T option) {
if (options.contains(option)) this.option = option;
fireUpdateEvent();
if (updateListener != null) updateListener.accept(option);
}
public List<T> getOptions() {
return options;
}
public T getOption(int index) {
return options.get(index);
}
public T getDefaultValue() {
return defaultOption;
}
public int getSize() {
return options.size();
}
public int getIndex() {
int index = 0;
for (T option : options) {
if (this.option == option) break;
index += 1;
}
return index;
}
public boolean is(T option) {
return getValue() == option;
}
public int getIndex(T option1) {
int index = 0;
for (T option : options) {
if (option1 == option) break;
index += 1;
}
return index;
}
public void reset() {
setValue(defaultOption);
}
public void onUpdate(Consumer<T> listener) {
this.updateListener = listener;
if (updateListener != null) updateListener.accept(option);
}
public Map<T, String> getDisplayNames() {
return displayNames;
}
public String getDisplayName(T key) {
if (displayNames != null) return displayNames.get(key);
return key.toString();
}
}
@@ -5,7 +5,7 @@ import me.retucio.camtweaks.event.events.camtweaks.UpdateSettingEvent;
import me.retucio.camtweaks.module.Module;
// base para los tipos de ajustes
public abstract class AbstractSetting {
public abstract class Setting {
private final String name;
private final String description;
@@ -15,7 +15,7 @@ public abstract class AbstractSetting {
private Module module;
protected AbstractSetting(String name, String description) {
protected Setting(String name, String description) {
this.name = name;
this.description = description;
}
@@ -1,11 +1,8 @@
package me.retucio.camtweaks.module.settings;
import me.retucio.camtweaks.CameraTweaks;
import me.retucio.camtweaks.event.events.camtweaks.UpdateSettingEvent;
import java.util.function.Consumer;
public class StringSetting extends AbstractSetting {
public class StringSetting extends Setting {
private String value;
private String defaultValue;
@@ -1,241 +0,0 @@
package me.retucio.camtweaks.ui;
import me.retucio.camtweaks.config.ConfigManager;
import me.retucio.camtweaks.event.SubscribeEvent;
import me.retucio.camtweaks.event.events.PacketEvent;
import me.retucio.camtweaks.event.events.camtweaks.UpdateSettingEvent;
import me.retucio.camtweaks.module.ModuleManager;
import me.retucio.camtweaks.module.modules.Freecam;
import me.retucio.camtweaks.module.modules.HUD;
import me.retucio.camtweaks.ui.screen.HudEditorScreen;
import me.retucio.camtweaks.ui.widgets.HudElement;
import me.retucio.camtweaks.util.Colors;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.gui.screen.TitleScreen;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.render.RenderTickCounter;
import net.minecraft.network.packet.s2c.play.WorldTimeUpdateS2CPacket;
import net.minecraft.util.math.Vec3d;
import java.awt.*;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class HudRenderer {
private static final MinecraftClient mc = MinecraftClient.getInstance();
// tps
private static float estimatedTPS = 20f;
private static final List<Float> tpsHistory = new ArrayList<>();
private long lastWorldTime = -1L;
private long lastRealTime = -1L;
private static final Map<String, int[]> positions = ConfigManager.getConfig().hudPositions;
private static final Map<String, Boolean> visibilities = ConfigManager.getConfig().hudVisibilities;
private static final List<HudElement> elements = new ArrayList<>();
private static boolean initialized = false;
private static HudElement customTextElement = null;
public static void initElements() {
if (initialized) return;
initialized = true;
HUD hud = ModuleManager.INSTANCE.getModuleByClass(HUD.class);
// coordenadas
addElement("coords", 2, mc.getWindow().getScaledHeight() - mc.textRenderer.fontHeight, (ctx, mx, my, delta) -> {
drawSnappedText(ctx, getElementText("coords", delta, hud), mx, my, getColor(hud).getRGB(), hud.shadow.isEnabled());
});
// FPS
addElement("fps", 2, 2, (ctx, mx, my, delta) -> {
drawSnappedText(ctx, getElementText("fps", 0, hud), mx, my, getColor(hud).getRGB(), hud.shadow.isEnabled());
});
// TPS
addElement("tps", 2, mc.textRenderer.fontHeight + 4, (ctx, mx, my, delta) -> {
drawSnappedText(ctx, getElementText("tps", delta, hud), mx, my, getColor(hud).getRGB(), hud.shadow.isEnabled());
});
// texto custom
addElement("customText", mc.getWindow().getScaledWidth() / 2 - mc.textRenderer.getWidth(getElementText("customText", 0, ModuleManager.INSTANCE.getModuleByClass(HUD.class))) / 2, 2, (ctx, mx, my, delta) -> {
drawSnappedText(ctx, getElementText("customText", delta, hud), mx, my, getColor(hud).getRGB(), hud.shadow.isEnabled());
});
customTextElement = elements.stream()
.filter(e -> e.getId().equals("customText"))
.findFirst()
.orElse(null);
// hora
addElement("time", mc.getWindow().getScaledWidth() - mc.textRenderer.getWidth("04:20"), mc.getWindow().getScaledHeight() - mc.textRenderer.fontHeight - 2, (ctx, mx, my, delta) -> {
drawSnappedText(ctx, getElementText("time", delta, hud), mx, my, getColor(hud).getRGB(), hud.shadow.isEnabled());
});
// ping
addElement("ping", 2, 2 * (mc.textRenderer.fontHeight + 4), (ctx, mx, my, delta) -> {
drawSnappedText(ctx, getElementText("ping", delta, hud), mx, my, getColor(hud).getRGB(), hud.shadow.isEnabled());
});
HudEditorScreen.INSTANCE.setElements(getElements());
}
private static void addElement(String id, int defX, int defY, HudElement.Renderer renderer) {
int[] saved = positions.get(id);
Boolean visible = visibilities.get(id);
int x = saved == null ? defX : saved[0];
int y = saved == null ? defY : saved[1];
boolean v = visible == null || visible;
if (visibilities.isEmpty()) v = true;
elements.add(new HudElement(id, defX, defY, x, y, v) {
@Override public void render(DrawContext ctx, int mx, int my, float delta) {
renderer.render(ctx, x, y, delta);
}
});
}
public static Color getColor(HUD hud) {
return hud.color.getColor();
}
public static void drawSnappedText(DrawContext ctx, String text, int x, int y, int color, boolean shadow) {
int textWidth = mc.textRenderer.getWidth(text);
int screenWidth = mc.getWindow().getScaledWidth();
int screenHeight = mc.getWindow().getScaledHeight();
boolean snapRight = x > screenWidth / 2;
int drawX = snapRight ? x + (textWidth + 2) - textWidth : x;
// clampear y
y = Math.max(0, Math.min(y, screenHeight - mc.textRenderer.fontHeight));
// clampear x
drawX = Math.max(0, Math.min(drawX, screenWidth - textWidth));
ctx.drawText(mc.textRenderer, text, drawX, y, color, shadow);
}
public static void render(DrawContext ctx, RenderTickCounter tc) {
if (ModuleManager.INSTANCE == null
|| mc.player == null
|| mc.getCameraEntity() == null
|| mc.currentScreen instanceof TitleScreen
|| mc.options.hudHidden)
return;
HUD hud = ModuleManager.INSTANCE.getModuleByClass(HUD.class);
if (!hud.isEnabled()) return;
if (mc.debugHudEntryList.isF3Enabled() && !hud.showOnF3.isEnabled()) return;
if (mc.currentScreen instanceof ChatScreen && !hud.showOnChat.isEnabled()) return;
initElements();
if (mc.currentScreen instanceof HudEditorScreen) return;
float deltaTime = tc.getDynamicDeltaTicks();
for (HudElement element : elements)
if (element.isVisible()) element.render(ctx, 0, 0, deltaTime);
}
public static List<HudElement> getElements() {
return elements;
}
// texto a dibujar por elemento
public static String getElementText(String id, float delta, HUD hud) {
switch (id) {
case "coords" -> {
Freecam freecam = ModuleManager.INSTANCE.getModuleByClass(Freecam.class);
Vec3d pos = freecam.isEnabled()
? new Vec3d(freecam.getX(delta), freecam.getY(delta), freecam.getZ(delta))
: mc.player.getEntityPos();
return (int) pos.x + " " + (int) pos.y + " " + (int) pos.z;
}
case "fps" -> {
return "FPS: " + mc.getCurrentFps();
}
case "tps" -> {
return String.format("TPS: %.1f", estimatedTPS);
}
case "customText" -> {
return ModuleManager.INSTANCE.getModuleByClass(HUD.class).customText.getValue();
}
case "time" -> {
ZoneOffset offset = ZoneOffset.ofHours(hud.timezone.getIntValue());
LocalTime now = LocalTime.now(offset);
boolean is24 = hud.timeFormat.is(HUD.TimeFormat.TWENTY_FOUR_HOUR);
DateTimeFormatter format = DateTimeFormatter.ofPattern(is24 ? "HH:mm" : "hh:mm a");
return now.format(format);
}
case "ping" -> {
if (mc.getNetworkHandler() == null || mc.player == null) return "? ms";
if (mc.isInSingleplayer()) return "-1 ms";
PlayerListEntry playerListEntry = mc.getNetworkHandler().getPlayerListEntry(mc.player.getUuid());
return playerListEntry != null ? playerListEntry.getLatency() + " ms" : "? ms";
}
default -> { return id; }
}
}
@SubscribeEvent
public void onReceivePacket(PacketEvent.Receive event) {
if (event.getPacket() instanceof WorldTimeUpdateS2CPacket packet) {
long currentWorldTime = packet.time();
long currentRealTime = System.currentTimeMillis();
if (lastWorldTime != -1L && lastRealTime != -1L) {
long elapsedRealTime = currentRealTime - lastRealTime;
long elapsedWorldTicks = currentWorldTime - lastWorldTime;
if (elapsedRealTime > 0) {
// TPS = (ticks passed) / (seconds passed)
float tps = (float) elapsedWorldTicks / (elapsedRealTime / 1000.0f);
// clampear
tps = Math.max(0.1f, Math.min(20.0f, tps));
// usar historial para suavizar resultados
tpsHistory.add(tps);
if (tpsHistory.size() > 10)
tpsHistory.removeFirst();
// calcular media de tps
float sum = 0;
for (float t : tpsHistory) sum += t;
estimatedTPS = sum / tpsHistory.size();
}
}
lastWorldTime = currentWorldTime;
lastRealTime = currentRealTime;
}
}
/** para cuando se cambie el valor del texto custom */
@SubscribeEvent
public void onUpdateSetting(UpdateSettingEvent event) {
if (ModuleManager.INSTANCE == null) return;
HUD hud = ModuleManager.INSTANCE.getModuleByClass(HUD.class);
if (event.getSetting() == hud.customText) {
if (customTextElement != null) {
int newX = mc.getWindow().getScaledWidth() / 2 - mc.textRenderer.getWidth(hud.customText.getValue()) / 2;
customTextElement.setX(newX);
}
}
}
}
@@ -0,0 +1,134 @@
package me.retucio.camtweaks.ui.buttons;
import me.retucio.camtweaks.module.Module;
import me.retucio.camtweaks.module.settings.BooleanSetting;
import me.retucio.camtweaks.module.settings.OptionSetting;
import me.retucio.camtweaks.ui.frames.SettingsFrame;
import me.retucio.camtweaks.ui.screen.ClickGUI;
import me.retucio.camtweaks.util.Colors;
import net.minecraft.client.gui.DrawContext;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import static me.retucio.camtweaks.CameraTweaks.mc;
public class ChooseButton<T> extends SettingButton {
private final OptionSetting<T> setting;
private final Module dummy;
private final Map<T, BooleanSetting> optionButtons = new HashMap<>();
private T lastSelectedValue;
public ChooseButton(OptionSetting<T> setting, SettingsFrame parent, int offset) {
super(setting, parent, offset);
this.setting = setting;
this.lastSelectedValue = setting.getValue();
// crear un módulo "dummy" (falso)
dummy = new Module(setting.getName(), setting.getDescription()) {
@Override public void onEnable() {}
@Override public void onDisable() {}
};
// ocultar cosas innecesarias
dummy.getBind().setVisible(false);
dummy.getSettings().stream()
.filter(s -> s.getName().equalsIgnoreCase("modo de tecla"))
.findFirst()
.ifPresent(s -> s.setVisible(false));
dummy.getSettings().stream()
.filter(s -> s.getName().equalsIgnoreCase("notificar"))
.findFirst()
.ifPresent(s -> s.setVisible(false));
dummy.shouldSaveSettings(false);
}
@Override
public void render(DrawContext ctx, double mouseX, double mouseY, float delta) {
int bgColor = isHovered(mouseX, mouseY)
? Colors.buttonColor.brighter().getRGB()
: Colors.buttonColor.getRGB();
ctx.fill(x, y, x + w, y + h, bgColor);
String label = setting.getName() + ": " + setting.getDisplayName(setting.getValue());
ctx.drawText(parent.mc.textRenderer, label, x + 5, y + 3, -1, true);
}
@Override
public void mouseClicked(double mouseX, double mouseY, int button) {
if (isHovered(mouseX, mouseY) && ClickGUI.INSTANCE.trySelect(this)) {
// click izquierdo / derecho: abrir marco
if (button <= 1 && !mc.isShiftPressed()) {
if (ClickGUI.INSTANCE.isSettingsFrameOpen(dummy)) {
ClickGUI.INSTANCE.closeSettingsFrame(dummy);
return;
}
rebuildDummy();
ClickGUI.INSTANCE.openListSettingsFrame(dummy, parent.x + 40, parent.y + 40);
// shift + clic derecho: restablecer valores
} else if (button == 1 && mc.isShiftPressed()) {
setting.reset();
refreshDummy();
}
}
}
private void rebuildDummy() {
dummy.getSettings().clear();
optionButtons.clear();
setting.getOptions().stream()
.sorted(Comparator.comparing(setting::getDisplayName, String.CASE_INSENSITIVE_ORDER))
.forEach(option -> {
String displayName = setting.getDisplayName(option);
BooleanSetting b = new BooleanSetting(
displayName,
"incluir " + displayName,
setting.is(option)
);
b.onUpdate(value -> {
if (value) {
// deseleccionar el resto de opciones
for (Map.Entry<T, BooleanSetting> entry : optionButtons.entrySet()) {
if (!entry.getKey().equals(option))
entry.getValue().setEnabled(false);
}
setting.setValue(option);
} else {
if (setting.is(option))
b.setEnabled(true);
}
});
dummy.addSetting(b);
optionButtons.put(option, b);
});
}
public void refreshDummy() {
T currentValue = setting.getValue();
for (Map.Entry<T, BooleanSetting> entry : optionButtons.entrySet()) {
boolean shouldBeEnabled = entry.getKey().equals(currentValue);
if (entry.getValue().isEnabled() != shouldBeEnabled) {
entry.getValue().setEnabled(shouldBeEnabled);
}
}
}
public OptionSetting<T> getSetting() {
return setting;
}
@Override
public void mouseReleased(double mouseX, double mouseY, int button) {
ClickGUI.INSTANCE.unselect(this);
}
@Override
public void mouseDragged(double mouseX, double mouseY) {}
}
@@ -1,6 +1,6 @@
package me.retucio.camtweaks.ui.buttons;
import me.retucio.camtweaks.module.settings.AbstractSetting;
import me.retucio.camtweaks.module.settings.Setting;
import me.retucio.camtweaks.ui.screen.ClickGUI;
import me.retucio.camtweaks.ui.frames.SettingsFrame;
import net.minecraft.client.gui.DrawContext;
@@ -9,13 +9,13 @@ import net.minecraft.text.Text;
// clase base para los botones de los ajustes
public abstract class SettingButton {
protected final AbstractSetting setting;
protected final Setting setting;
protected final SettingsFrame parent;
protected int offset;
protected int x, y, w, h;
public SettingButton(AbstractSetting setting, SettingsFrame parent, int offset) {
public SettingButton(Setting setting, SettingsFrame parent, int offset) {
this.setting = setting;
this.parent = parent;
this.offset = offset;
@@ -42,7 +42,7 @@ public abstract class SettingButton {
mouseY > y && mouseY < y + h;
}
public AbstractSetting getSetting() {
public Setting getSetting() {
return setting;
}
@@ -1,13 +1,12 @@
package me.retucio.camtweaks.ui.frames;
import me.retucio.camtweaks.module.Module;
import me.retucio.camtweaks.module.settings.AbstractSetting;
import me.retucio.camtweaks.module.settings.Setting;
import me.retucio.camtweaks.module.settings.BooleanSetting;
import me.retucio.camtweaks.module.settings.ColorSetting;
import me.retucio.camtweaks.module.settings.NumberSetting;
import me.retucio.camtweaks.ui.buttons.*;
import me.retucio.camtweaks.ui.screen.ClickGUI;
import me.retucio.camtweaks.util.ChatUtil;
import me.retucio.camtweaks.util.Colors;
import me.retucio.camtweaks.util.render.DrawUtil;
import net.minecraft.client.gui.DrawContext;
@@ -73,7 +72,7 @@ public class ColorPickerFrame extends SettingsFrame {
// añadir ajustes y tal
dummyModule.addSettings(redSetting, greenSetting, blueSetting, rainbowSpeedSetting, saturationSetting, brightnessSetting, rainbowSetting);
for (AbstractSetting setting : dummyModule.getSettings()) {
for (Setting setting : dummyModule.getSettings()) {
if (setting instanceof NumberSetting n) n.onUpdate(v -> updateColorFromSettings());
if (setting instanceof BooleanSetting b) b.onUpdate(v -> updateColorFromSettings());
rainbowSetting.onUpdate(v -> {
@@ -120,7 +119,7 @@ public class ColorPickerFrame extends SettingsFrame {
updateWidth();
// al parecer este era el problema :/
for (AbstractSetting setting : dummyModule.getSettings())
for (Setting setting : dummyModule.getSettings())
if (setting instanceof NumberSetting ns) ns.setLocked(
pickingAlpha || pickingHue || pickingSaturationBrightness);
@@ -473,7 +472,7 @@ public class ColorPickerFrame extends SettingsFrame {
private void updateSettingsFromColor() {
if (colorSetting == null) return;
for (AbstractSetting setting : dummyModule.getSettings()) {
for (Setting setting : dummyModule.getSettings()) {
switch (setting.getName()) {
case "rojo" -> ((NumberSetting) setting).setValue(colorSetting.getR());
case "verde" -> ((NumberSetting) setting).setValue(colorSetting.getG());
@@ -50,7 +50,7 @@ public class SettingsFrame {
// añadir el respectivo tipo de botón de cada ajuste a la lista de botones
int offset = h;
for (AbstractSetting setting : module.getSettings()) {
for (Setting setting : module.getSettings()) {
switch (setting) {
case BooleanSetting b -> {
addButton(new ToggleButton(b, this, offset));
@@ -73,6 +73,9 @@ public class SettingsFrame {
} case ColorSetting c -> {
addButton(new ColorButton(c, this, offset));
offset += 18;
} case OptionSetting o -> {
addButton(new ChooseButton<>(o, this, offset));
offset += 18;
}
default -> {}
}
@@ -1,19 +1,18 @@
package me.retucio.camtweaks.ui.screen;
package me.retucio.camtweaks.ui.hud;
import me.retucio.camtweaks.config.ConfigManager;
import me.retucio.camtweaks.module.ModuleManager;
import me.retucio.camtweaks.module.modules.HUD;
import me.retucio.camtweaks.ui.frames.ClientSettingsFrame;
import me.retucio.camtweaks.ui.widgets.HudElement;
import me.retucio.camtweaks.util.Colors;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.Click;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.input.KeyInput;
import net.minecraft.text.Text;
import org.lwjgl.glfw.GLFW;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import java.util.ArrayList;
import java.util.List;
@@ -30,7 +29,7 @@ public class HudEditorScreen extends Screen {
private int dragOffsetX, dragOffsetY;
public HudEditorScreen() {
super(Text.literal("editor del hud"));
super(Text.literal("editor del HUD"));
}
public void setElements(List<HudElement> elements) {
@@ -42,24 +41,26 @@ public class HudEditorScreen extends Screen {
public void render(DrawContext ctx, int mouseX, int mouseY, float delta) {
ctx.fill(0, 0, this.width, this.height, Colors.hudEditorScreenBackgroundColor.getRGB());
// texto con instrucciones
ctx.drawCenteredTextWithShadow(mc.textRenderer, "EDITOR DEL HUD", this.width / 2, this.height / 2 - mc.textRenderer.fontHeight, -1);
// instrucciones
ctx.drawCenteredTextWithShadow(mc.textRenderer, "editor del HUD",
this.width / 2, this.height / 2 - mc.textRenderer.fontHeight, -1);
ctx.drawCenteredTextWithShadow(mc.textRenderer,
Text.literal("arrastrar para mover · click derecho para alternar visibilidad · esc para guardar y salir · shift + click derecho para restablecer"),
Text.literal("arrastrar para mover · clic derecho para visibilidad · ESC para guardar y salir · shift + clic derecho para restablecer"),
this.width / 2, this.height / 2 + mc.textRenderer.fontHeight, Colors.instructionsTextColor.getRGB());
// dibujar elementos
// elementos
for (HudElement element : elements)
element.renderPreview(ctx);
element.renderInEditor(ctx, null);
// tooltips con información sobre el elemento sobre el que está el puntero del ratón
// tooltips
if (!dragging) {
for (HudElement element : elements) {
if (!element.isVisible()) continue;
if (element.contains(mouseX, mouseY)) {
List<Text> tooltip = getTooltipFor(element);
if (!tooltip.isEmpty()) ctx.drawTooltip(mc.textRenderer, tooltip, mouseX + 7, mouseY + 20);
if (element.isHovered(mouseX, mouseY)) {
List<Text> tooltip = element.getTooltip();
if (!tooltip.isEmpty())
ctx.drawTooltip(mc.textRenderer, tooltip, mouseX + 7, mouseY + 20);
break;
}
}
@@ -73,28 +74,27 @@ public class HudEditorScreen extends Screen {
int mouseX = (int) click.x();
int mouseY = (int) click.y();
// iterar de atrás a adelante para respetar el orden z
for (int i = elements.size() - 1; i >= 0; i--) {
HudElement element = elements.get(i);
if (element.contains(mouseX, mouseY)) {
if (element.isHovered(mouseX, mouseY)) {
selected = element;
if (click.button() == 0) {
dragging = true;
dragOffsetX = mouseX - element.getX();
dragOffsetY = mouseY - element.getY();
// traer el elemento seleccionado al frente
elements.remove(i);
elements.add(element);
return true;
} else if (click.button() == 1) {
if (mc.isShiftPressed())
if (mc.isShiftPressed()) {
selected.resetPosition();
else
} else {
selected.setVisible(!selected.isVisible());
}
saveElementToConfig(selected);
return true;
}
}
@@ -114,7 +114,6 @@ public class HudEditorScreen extends Screen {
int newX = mouseX - dragOffsetX;
int newY = mouseY - dragOffsetY;
// clampear para evitar que los elementos se salgan de la pantalla
newX = Math.max(1, Math.min(newX, width - selected.getWidth() - 1));
newY = Math.max(1, Math.min(newY, height - selected.getHeight() - 1));
@@ -126,92 +125,46 @@ public class HudEditorScreen extends Screen {
public boolean mouseReleased(Click click) {
if (dragging && click.button() == 0) {
dragging = false;
savePositionsToConfig(); // guardar inmediatamente al config
return true;
} else if (click.button() == 1 && selected != null) {
saveVisibilitiesToConfig();
selected = null;
if (selected != null)
saveElementToConfig(selected);
return true;
}
selected = null;
return super.mouseReleased(click);
}
@Override
public boolean keyPressed(KeyInput input) {
// esc para guardar y salir
if (input.key() == GLFW.GLFW_KEY_ESCAPE) {
saveAndClose();
saveAllElementsToConfig();
selected = null;
mc.setScreen(null);
return true;
}
return super.keyPressed(input);
}
private void savePositionsToConfig() {
for (HudElement element : elements)
ConfigManager.setHudPosition(element.getId(), element.getX(), element.getY());
private void saveElementToConfig(HudElement element) {
ConfigManager.setHudPosition(element.getId(), element.getX(), element.getY());
ConfigManager.setHudVisibility(element.getId(), element.isVisible());
ConfigManager.save();
}
private void saveVisibilitiesToConfig() {
for (HudElement element : elements)
ConfigManager.setHudVisibility(element.getId(), element.isVisible());
ConfigManager.save();
}
private void saveAndClose() {
savePositionsToConfig();
selected = null;
mc.setScreen(null);
private void saveAllElementsToConfig() {
for (HudElement element : elements) {
saveElementToConfig(element);
}
}
@Override
protected void applyBlur(DrawContext ctx) {
if (ClientSettingsFrame.guiSettings.blur.isEnabled()) super.applyBlur(ctx);
if (ClientSettingsFrame.guiSettings.blur.isEnabled()) {
super.applyBlur(ctx);
}
}
public boolean isSelected(HudElement element) {
return selected == element;
}
// para los tooltips
private List<Text> getTooltipFor(HudElement element) {
List<Text> list = new ArrayList<>();
switch (element.getId()) {
case "coords" -> {
list.add(Text.literal("coordenadas"));
list.add(Text.literal("te muestra tu posición en el mundo en coordenadas XYZ"));
}
case "fps" -> {
list.add(Text.literal("FPS"));
list.add(Text.literal("te muestra la tasa de fotogramas por segundo del juego"));
}
case "tps" -> {
list.add(Text.literal("tps"));
list.add(Text.literal("te muestra la tasa de ticks por segundo del servidor (0-20)"));
}
case "customText" -> {
list.add(Text.literal("texto custom"));
list.add(Text.literal("te permite renderizar texto al gusto"));
}
case "time" -> {
list.add(Text.literal("hora"));
list.add(Text.literal("te muestra la hora y los minutos de la zona horaria escogida"));
}
case "ping" -> {
list.add(Text.literal("ping"));
list.add(Text.literal("tiempo entre que se envía un paquete y este llega a su destino, en milisegundos"));
}
default -> {
list.add(Text.literal(element.getId()));
list.add(Text.literal("."));
}
}
return list;
}
}
}
@@ -0,0 +1,91 @@
package me.retucio.camtweaks.ui.hud;
import me.retucio.camtweaks.module.modules.HUD;
import me.retucio.camtweaks.util.Colors;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.text.Text;
import java.util.List;
public abstract class HudElement {
protected static final MinecraftClient mc = MinecraftClient.getInstance();
private final String id;
protected boolean visible;
protected int x, y;
protected final int defaultX, defaultY;
protected int width = 85, height = 14;
public HudElement(String id, int defaultX, int defaultY) {
this.id = id;
this.defaultX = defaultX;
this.defaultY = defaultY;
this.visible = true;
}
public abstract String getText(float delta, HUD hud);
public abstract String getPreviewText();
public void renderInGame(DrawContext ctx, float delta, HUD hud) {
String text = getText(delta, hud);
int color = hud != null ? HudRenderer.getColor(hud).getRGB() : -1;
boolean shadow = hud != null && hud.shadow.isEnabled();
HudRenderer.drawSnappedText(ctx, text, x, y, color, shadow);
}
public void renderInEditor(DrawContext ctx, HUD hud) {
String previewText = getPreviewText();
width = mc.textRenderer.getWidth(previewText);
height = mc.textRenderer.fontHeight;
drawEditorBackground(ctx);
int color = hud != null ? HudRenderer.getColor(hud).getRGB() : -1;
boolean shadow = hud != null && hud.shadow.isEnabled();
HudRenderer.drawSnappedText(ctx, previewText, x, y, color, shadow);
}
public abstract List<Text> getTooltip();
private void drawEditorBackground(DrawContext ctx) {
int bg = visible ? Colors.visibleHudElementColor.getRGB() : Colors.disabledHudElementColor.getRGB();
int outline = HudEditorScreen.INSTANCE != null && HudEditorScreen.INSTANCE.isSelected(this)
? Colors.selectedHudElementOutlineColor.getRGB()
: Colors.unselectedHudElementOutlineColor.getRGB();
// fondo
ctx.fill(x - 1, y - 1, x + width + 1, y + height + 1, bg);
// contorno
ctx.fill(x - 1, y - 1, x + width + 1, y, outline);
ctx.fill(x - 1, y + height, x + width + 1, y + height + 1, outline);
ctx.fill(x - 1, y, x, y + height, outline);
ctx.fill(x + width, y, x + width + 1, y + height, outline);
}
public boolean isHovered(int mouseX, int mouseY) {
return mouseX >= x && mouseX <= x + width
&& mouseY >= y && mouseY <= y + height;
}
// Getters and setters
public String getId() { return id; }
public int getX() { return x; }
public int getY() { return y; }
public int getWidth() { return width; }
public int getHeight() { return height; }
public boolean isVisible() { return visible; }
public void setVisible(boolean visible) { this.visible = visible; }
public void resetPosition() {
this.x = defaultX;
this.y = defaultY;
}
public void setPosition(int x, int y) {
this.x = x;
this.y = y;
}
}
@@ -0,0 +1,111 @@
package me.retucio.camtweaks.ui.hud;
import me.retucio.camtweaks.config.ConfigManager;
import me.retucio.camtweaks.module.ModuleManager;
import me.retucio.camtweaks.module.modules.HUD;
import me.retucio.camtweaks.ui.hud.elements.*;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.gui.screen.TitleScreen;
import net.minecraft.client.render.RenderTickCounter;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class HudRenderer {
private static final MinecraftClient mc = MinecraftClient.getInstance();
private static final List<HudElement> elements = new ArrayList<>();
private static boolean initialized = false;
public static void init() {
if (initialized) return;
initialized = true;
Map<String, int[]> positions = ConfigManager.getConfig().hudPositions;
Map<String, Boolean> visibilities = ConfigManager.getConfig().hudVisibilities;
addElement(new CoordsElement(), positions, visibilities);
addElement(new FpsElement(), positions, visibilities);
addElement(new TpsElement(), positions, visibilities);
addElement(new CustomTextElement(), positions, visibilities);
addElement(new TimeElement(), positions, visibilities);
addElement(new PingElement(), positions, visibilities);
HudEditorScreen.INSTANCE.setElements(elements);
}
private static void addElement(HudElement element, Map<String, int[]> positions, Map<String, Boolean> visibilities) {
int[] savedPos;
if (positions.get(element.getId()) == null)
savedPos = new int[] {element.defaultX, element.defaultY};
else
savedPos = positions.get(element.getId());
Boolean savedVisibility = visibilities.get(element.getId());
if (savedPos != null)
element.setPosition(savedPos[0], savedPos[1]);
if (savedVisibility != null)
element.setVisible(savedVisibility);
elements.add(element);
}
public static Color getColor(HUD hud) {
return hud.color.getColor();
}
public static void drawSnappedText(DrawContext ctx, String text, int x, int y, int color, boolean shadow) {
int textWidth = mc.textRenderer.getWidth(text);
int screenWidth = mc.getWindow().getScaledWidth();
int screenHeight = mc.getWindow().getScaledHeight();
boolean snapRight = x > screenWidth / 2;
int drawX = snapRight ? x + (textWidth + 2) - textWidth : x;
drawX = Math.max(0, Math.min(drawX, screenWidth - textWidth));
y = Math.max(0, Math.min(y, screenHeight - mc.textRenderer.fontHeight));
ctx.drawText(mc.textRenderer, text, drawX, y, color, shadow);
}
public static void render(DrawContext ctx, RenderTickCounter tickCounter) {
if (shouldSkipRendering()) return;
HUD hud = ModuleManager.INSTANCE.getModuleByClass(HUD.class);
if (!hud.isEnabled()) return;
if (mc.debugHudEntryList.isF3Enabled() && !hud.showOnF3.isEnabled()) return;
if (mc.currentScreen instanceof ChatScreen && !hud.showOnChat.isEnabled()) return;
init();
if (mc.currentScreen instanceof HudEditorScreen) return;
float delta = tickCounter.getDynamicDeltaTicks();
for (HudElement element : elements) {
if (element.isVisible()) {
element.renderInGame(ctx, delta, hud);
}
}
}
private static boolean shouldSkipRendering() {
return ModuleManager.INSTANCE == null
|| mc.player == null
|| mc.getCameraEntity() == null
|| mc.currentScreen instanceof TitleScreen
|| mc.options.hudHidden;
}
public static List<HudElement> getElements() {
return elements;
}
}
@@ -0,0 +1,51 @@
package me.retucio.camtweaks.ui.hud;
import me.retucio.camtweaks.event.events.PacketEvent;
import me.retucio.camtweaks.module.ModuleManager;
import me.retucio.camtweaks.module.modules.Freecam;
import me.retucio.camtweaks.module.modules.HUD;
import net.minecraft.text.Text;
import net.minecraft.util.math.Vec3d;
import java.util.List;
public class CoordsElement extends HudElement {
public CoordsElement() {
super("coords", 2, mc.getWindow().getScaledHeight() - mc.textRenderer.fontHeight);
}
@Override
public String getText(float delta, HUD hud) {
Freecam freecam = ModuleManager.INSTANCE.getModuleByClass(Freecam.class);
Vec3d pos = freecam != null && freecam.isEnabled()
? new Vec3d(freecam.getX(delta), freecam.getY(delta), freecam.getZ(delta))
: mc.player.getEntityPos();
String overworldCoords = (int) pos.x + " " + (int) pos.y + " " + (int) pos.z;
String netherCoords = (int) pos.x / 8 + " " + (int) pos.y / 8 + " " + (int) pos.z / 8;
if (hud.coordsMode.is(HUD.CoordsMode.OVERWORLD)) {
return overworldCoords;
} else if (hud.coordsMode.is(HUD.CoordsMode.NETHER)) {
return netherCoords;
} else {
return overworldCoords + " (" + netherCoords + ")";
}
}
@Override
public String getPreviewText() {
return getText(
mc.getRenderTickCounter().getDynamicDeltaTicks(),
ModuleManager.INSTANCE.getModuleByClass(HUD.class));
}
@Override
public List<Text> getTooltip() {
return List.of(
Text.literal(getId()),
Text.literal("te muestra tu posición XYZ en el mundo")
);
}
}
@@ -0,0 +1,49 @@
package me.retucio.camtweaks.ui.hud.elements;
import me.retucio.camtweaks.event.SubscribeEvent;
import me.retucio.camtweaks.event.events.camtweaks.UpdateSettingEvent;
import me.retucio.camtweaks.module.ModuleManager;
import me.retucio.camtweaks.module.modules.HUD;
import me.retucio.camtweaks.ui.hud.HudElement;
import net.minecraft.text.Text;
import java.util.List;
public class CustomTextElement extends HudElement {
public CustomTextElement() {
super("customText", mc.getWindow().getScaledWidth() / 2 - 40, 2);
}
@Override
public String getText(float delta, HUD hud) {
return hud != null && hud.customText != null ? hud.customText.getValue() : "";
}
@Override
public String getPreviewText() {
HUD hud = ModuleManager.INSTANCE.getModuleByClass(HUD.class);
if (hud != null && hud.customText != null && !hud.customText.getValue().isEmpty())
return hud.customText.getValue();
return "texto custom";
}
@Override
public List<Text> getTooltip() {
return List.of(
Text.literal("texto custom"),
Text.literal("texto que tú eliges")
);
}
@SubscribeEvent
public void onUpdateSetting(UpdateSettingEvent event) {
if (ModuleManager.INSTANCE == null) return;
HUD hud = ModuleManager.INSTANCE.getModuleByClass(HUD.class);
if (hud != null && event.getSetting() == hud.customText) {
int newX = mc.getWindow().getScaledWidth() / 2 - mc.textRenderer.getWidth(hud.customText.getValue()) / 2;
setPosition(newX, y);
}
}
}
@@ -0,0 +1,32 @@
package me.retucio.camtweaks.ui.hud.elements;
import me.retucio.camtweaks.module.modules.HUD;
import me.retucio.camtweaks.ui.hud.HudElement;
import net.minecraft.text.Text;
import java.util.List;
public class FpsElement extends HudElement {
public FpsElement() {
super("fps", 2, 2);
}
@Override
public String getText(float delta, HUD hud) {
return "FPS: " + mc.getCurrentFps();
}
@Override
public String getPreviewText() {
return "FPS: 67";
}
@Override
public List<Text> getTooltip() {
return List.of(
Text.literal("FPS"),
Text.literal("te muestra los fotogramas por segundo a los que corre el juego")
);
}
}
@@ -0,0 +1,37 @@
package me.retucio.camtweaks.ui.hud.elements;
import me.retucio.camtweaks.module.modules.HUD;
import me.retucio.camtweaks.ui.hud.HudElement;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.text.Text;
import java.util.List;
public class PingElement extends HudElement {
public PingElement() {
super("ping", 2, 2 * (mc.textRenderer.fontHeight + 4));
}
@Override
public String getText(float delta, HUD hud) {
if (mc.getNetworkHandler() == null || mc.player == null) return "? ms";
if (mc.isInSingleplayer()) return "-1 ms";
PlayerListEntry playerListEntry = mc.getNetworkHandler().getPlayerListEntry(mc.player.getUuid());
return playerListEntry != null ? playerListEntry.getLatency() + " ms" : "? ms";
}
@Override
public String getPreviewText() {
return "67 ms";
}
@Override
public List<Text> getTooltip() {
return List.of(
Text.literal("ping"),
Text.literal("latencia entre cliente y servidor, en milisegundos")
);
}
}
@@ -0,0 +1,33 @@
package me.retucio.camtweaks.ui.hud.elements;
import me.retucio.camtweaks.module.modules.HUD;
import me.retucio.camtweaks.ui.hud.HudElement;
import me.retucio.camtweaks.util.MiscUtil;
import net.minecraft.text.Text;
import java.util.List;
public class TimeElement extends HudElement {
public TimeElement() {
super("time", mc.getWindow().getScaledWidth() - 50, mc.getWindow().getScaledHeight() - mc.textRenderer.fontHeight - 2);
}
@Override
public String getText(float delta, HUD hud) {
return MiscUtil.getCurrentFormattedTime();
}
@Override
public String getPreviewText() {
return "04:20 PM";
}
@Override
public List<Text> getTooltip() {
return List.of(
Text.literal("hora"),
Text.literal("hora y minutos de la zona horaria seleccionada")
);
}
}
@@ -0,0 +1,33 @@
package me.retucio.camtweaks.ui.hud.elements;
import me.retucio.camtweaks.module.modules.HUD;
import me.retucio.camtweaks.ui.hud.HudElement;
import me.retucio.camtweaks.util.NetworkUtil;
import net.minecraft.text.Text;
import java.util.List;
public class TpsElement extends HudElement {
public TpsElement() {
super("tps", 2, mc.textRenderer.fontHeight + 4);
}
@Override
public String getText(float delta, HUD hud) {
return "TPS: " + NetworkUtil.getTPS();
}
@Override
public String getPreviewText() {
return "TPS: 20.0";
}
@Override
public List<Text> getTooltip() {
return List.of(
Text.literal("TPS"),
Text.literal("te muestra la tasa de ticks por segundo del servidor (TPS óptimo: 20)")
);
}
}
@@ -7,10 +7,8 @@ import me.retucio.camtweaks.event.events.MouseClickEvent;
import me.retucio.camtweaks.event.events.MouseScrollEvent;
import me.retucio.camtweaks.event.events.camtweaks.SettingsFrameEvent;
import me.retucio.camtweaks.module.Module;
import me.retucio.camtweaks.module.ModuleManager;
import me.retucio.camtweaks.module.settings.AbstractSetting;
import me.retucio.camtweaks.module.settings.Setting;
import me.retucio.camtweaks.module.settings.ColorSetting;
import me.retucio.camtweaks.ui.buttons.ColorButton;
import me.retucio.camtweaks.ui.buttons.ListButton;
import me.retucio.camtweaks.ui.buttons.ModuleButton;
import me.retucio.camtweaks.ui.buttons.SettingButton;
@@ -20,7 +18,6 @@ import me.retucio.camtweaks.ui.frames.ModuleFrame;
import me.retucio.camtweaks.ui.frames.SettingsFrame;
import me.retucio.camtweaks.ui.widgets.ScrollBarWidget;
import me.retucio.camtweaks.ui.widgets.SearchBarWidget;
import me.retucio.camtweaks.util.ChatUtil;
import me.retucio.camtweaks.util.KeyUtil;
import net.minecraft.client.MinecraftClient;
@@ -207,7 +204,7 @@ public class ClickGUI extends Screen {
for (SettingsFrame sf : settingsFrames) {
for (SettingButton sb : sf.getButtons()) {
AbstractSetting setting = sb.getSetting();
Setting setting = sb.getSetting();
if (searchInput.isEmpty()) {
setting.setSearchMatch(true);
@@ -0,0 +1,36 @@
package me.retucio.camtweaks.ui.widgets;
import me.retucio.camtweaks.module.settings.Setting;
import me.retucio.camtweaks.ui.frames.SettingsFrame;
import me.retucio.camtweaks.ui.screen.ClickGUI;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.text.Text;
public abstract class Button {
protected Frame parent;
protected int offset;
protected int x, y, w, h;
public Button(Frame parent, int offset) {
this.parent = parent;
this.offset = offset;
}
public abstract void render(DrawContext ctx, int mouseX, int mouseY, float delta);
public abstract void mouseClicked(int mouseX, int mouseY, int button);
public abstract void mouseDragged(int mouseX, int mouseY);
public void mouseReleased(int mouseX, int mouseY, int button) {
ClickGUI.INSTANCE.unselect(this);
}
public abstract void drawTooltip(DrawContext ctx, double mouseX, double mouseY);
protected boolean isHovered(int mouseX, int mouseY) {
if (!ClickGUI.INSTANCE.canSelect(this)) return false;
return mouseX > x && mouseX < x + w &&
mouseY > y && mouseY < y + h;
}
}
@@ -0,0 +1,63 @@
package me.retucio.camtweaks.ui.widgets;
import me.retucio.camtweaks.ui.screen.ClickGUI;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import java.util.ArrayList;
import java.util.List;
public abstract class Frame {
private final MinecraftClient mc = MinecraftClient.getInstance();
public final String title;
private final List<Button> buttons = new ArrayList<>();
private List<Button> visibleButtons = new ArrayList<>();
private int x, y, w, h;
private int renderY;
private int dragX, dragY;
private boolean dragging;
public int totalHeight = 0;
public Frame(String title, int x, int y, int w, int h) {
this.title = title;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
public abstract void render(DrawContext ctx, int mouseX, int mouseY, float delta);
public void drawTooltips(DrawContext ctx, int mouseX, int mouseY) {
for (Button button : visibleButtons) button.drawTooltip(ctx, mouseX, mouseY);
}
public abstract void mouseClicked(int mouseX, int mouseY, int button);
public abstract void mouseDragged(int mouseX, int mouseY);
public void mouseReleased(int mouseX, int mouseY, int button) {
ClickGUI.INSTANCE.unselect(this);
}
public abstract void updateWidth();
public List<Button> getButtons() {
return buttons;
}
public List<Button> getVisibleButtons() {
return visibleButtons;
}
public boolean isHovered(double mouseX, double mouseY) {
return mouseX > x && mouseX < x + w && mouseY > renderY && mouseY < renderY + h;
}
public void updateRenderY(int scrollOffset) {
renderY = y - scrollOffset;
}
}
@@ -1,145 +0,0 @@
package me.retucio.camtweaks.ui.widgets;
import me.retucio.camtweaks.module.ModuleManager;
import me.retucio.camtweaks.module.modules.HUD;
import me.retucio.camtweaks.ui.screen.HudEditorScreen;
import me.retucio.camtweaks.ui.HudRenderer;
import me.retucio.camtweaks.util.Colors;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.text.Text;
public class HudElement {
protected final MinecraftClient mc = MinecraftClient.getInstance();
private final String id;
protected boolean visible;
protected int x, y;
protected int defaultX, defaultY;
protected int width = 85, height = 14; // tamaño por defecto
public HudElement(String id, int defX, int defY, int x, int y, boolean visible) {
this.id = id;
this.visible = visible;
this.x = x;
this.y = y;
this.defaultX = defX;
this.defaultY = defY;
}
// fallback
public void render(DrawContext ctx, int mouseX, int mouseY, float tickDelta) {
ctx.drawText(mc.textRenderer, Text.literal(getId()), x, y, -1, false);
}
/** renderizar previsualización del elemento para el editor */
public void renderPreview(DrawContext ctx) {
final HUD hud = ModuleManager.INSTANCE.getModuleByClass(HUD.class);
final String previewText = buildPreviewText(hud);
width = mc.textRenderer.getWidth(previewText);
height = mc.textRenderer.fontHeight;
drawBackground(ctx);
int color = -1;
boolean shadow = false;
if (hud != null) {
color = HudRenderer.getColor(hud).getRGB();
shadow = hud.shadow.isEnabled();
}
HudRenderer.drawSnappedText(ctx, previewText, x, y, color, shadow);
}
/** construir texto para la previsualización */
private String buildPreviewText(HUD hud) {
float delta = mc.getRenderTickCounter().getDynamicDeltaTicks();
if ("coords".equals(id)) {
if (mc.player == null) return "X Y Z";
return HudRenderer.getElementText(id, delta, hud);
}
if ("fps".equals(id)) {
return HudRenderer.getElementText(id, delta, hud);
}
if ("tps".equals(id)) {
return HudRenderer.getElementText(id, delta, hud);
}
if ("customText".equals(id)) {
if (hud != null && hud.customText != null && !hud.customText.getValue().isEmpty())
return HudRenderer.getElementText(id, delta, hud);
return "texto custom";
}
if ("time".equals(id)) {
if (hud != null && hud.timeFormat != null)
return HudRenderer.getElementText(id, delta, hud);
return "4:20 PM";
}
if ("ping".equals(id)) {
if (mc.getCurrentServerEntry() != null)
return HudRenderer.getElementText(id, delta, hud);
return "67 ms";
}
return id; // fallback: id del elemento
}
/** fondo y contorno */
private void drawBackground(DrawContext ctx) {
int bg = visible ? Colors.visibleHudElementColor.getRGB() : Colors.disabledHudElementColor.getRGB();
int outline = HudEditorScreen.INSTANCE.isSelected(this) ? Colors.selectedHudElementOutlineColor.getRGB() : Colors.unselectedHudElementOutlineColor.getRGB();
// fondo
ctx.fill(x - 1, y - 1, x + width + 1, y + height + 1, bg);
// contorno
ctx.fill(x - 1, y - 1, x + width + 1, y, outline);
ctx.fill(x - 1, y + height, x + width + 1, y + height + 1, outline);
ctx.fill(x - 1, y, x, y + height, outline);
ctx.fill(x + width, y, x + width + 1, y + height, outline);
}
public boolean contains(int mouseX, int mouseY) {
return mouseX >= x && mouseX <= x + width
&& mouseY >= y && mouseY <= y + height;
}
// getters y setters
public String getId() { return id; }
public int getX() { return x; }
public int getY() { return y; }
public void setX(int x) { this.x = x; }
public void setY(int y) { this.y = y; }
public int getWidth() { return width; }
public int getHeight() { return height; }
public boolean isVisible() { return visible; }
public void setVisible(boolean visible) { this.visible = visible; }
public void setPosition(int newX, int newY) {
this.x = newX;
this.y = newY;
}
public void resetPosition() {
this.x = defaultX;
this.y = defaultY;
}
public interface Renderer {
void render(DrawContext ctx, int x, int y, float delta);
}
}
@@ -25,7 +25,7 @@ public class ChatUtil {
}
public static void addMessage(Text text) {
if (mc.inGameHud == null || !CameraTweaks.INSTANCE.settingsApplied) return;
if (mc.inGameHud == null || !CameraTweaks.settingsApplied) return;
mc.inGameHud.getChatHud().addMessage(text);
}
@@ -0,0 +1,103 @@
package me.retucio.camtweaks.util;
import net.minecraft.entity.Entity;
import net.minecraft.entity.projectile.ProjectileUtil;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.RaycastContext;
import org.joml.Vector3d;
import static me.retucio.camtweaks.CameraTweaks.mc;
public class EntityUtil {
public static Vector3d getEntityVector(Vector3d vector, Entity entity, double tickDelta) {
vector.x = MathHelper.lerp(tickDelta, entity.lastRenderX, entity.getX());
vector.y = MathHelper.lerp(tickDelta, entity.lastRenderY, entity.getY());
vector.z = MathHelper.lerp(tickDelta, entity.lastRenderZ, entity.getZ());
return vector;
}
public static Entity getEntityPlayerIsLookingAt() {
if (mc.player == null || mc.world == null) return null;
float reachDistance = (float) mc.player.getEntityInteractionRange();
Vec3d cameraPos = mc.player.getCameraPosVec(1.0F);
Vec3d rotation = mc.player.getRotationVec(1.0F);
Vec3d endPos = cameraPos.add(rotation.x * reachDistance, rotation.y * reachDistance, rotation.z * reachDistance);
EntityHitResult entityHitResult = ProjectileUtil.raycast(
mc.player,
cameraPos,
endPos,
new Box(cameraPos, endPos),
entity -> !entity.isSpectator() && entity.canHit(),
reachDistance * reachDistance
);
return entityHitResult != null ? entityHitResult.getEntity() : null;
}
public static boolean hasLineOfSight(Entity viewer, Entity target) {
HitResult hitResult = viewer.getEntityWorld().raycast(new RaycastContext(
viewer.getEyePos(),
target.getEyePos(),
RaycastContext.ShapeType.COLLIDER,
RaycastContext.FluidHandling.NONE,
viewer
));
if (hitResult.getType() == HitResult.Type.MISS) return true;
else if (hitResult.getType() == HitResult.Type.ENTITY) {
return ((EntityHitResult) hitResult).getEntity() == target;
}
return false;
}
public static double getYaw(Entity entity) {
return getYaw(entity.getEntityPos());
}
public static double getYaw(Vec3d pos) {
return mc.player.getYaw() + MathHelper.wrapDegrees(
(float) Math.toDegrees(Math.atan2(
pos.getZ() - mc.player.getZ(),
pos.getX() - mc.player.getX())
) - 90f - mc.player.getYaw());
}
public static double getPitch(Vec3d pos) {
double diffX = pos.getX() - mc.player.getX();
double diffY = pos.getY() - (mc.player.getY() + mc.player.getEyeHeight(mc.player.getPose()));
double diffZ = pos.getZ() - mc.player.getZ();
double diffXZ = Math.sqrt(diffX * diffX + diffZ * diffZ);
return mc.player.getPitch() + MathHelper.wrapDegrees((float) -Math.toDegrees(Math.atan2(diffY, diffXZ)) - mc.player.getPitch());
}
public static double getPitch(Entity entity, Target target) {
double y;
if (target == Target.HEAD) y = entity.getEyeY();
else if (target == Target.BODY) y = entity.getY() + entity.getHeight() / 2;
else y = entity.getY();
double diffX = entity.getX() - mc.player.getX();
double diffY = y - (mc.player.getY() + mc.player.getEyeHeight(mc.player.getPose()));
double diffZ = entity.getZ() - mc.player.getZ();
double diffXZ = Math.sqrt(diffX * diffX + diffZ * diffZ);
return mc.player.getPitch() + MathHelper.wrapDegrees((float) -Math.toDegrees(Math.atan2(diffY, diffXZ)) - mc.player.getPitch());
}
public static enum Target {
HEAD,
BODY,
FEET;
}
}
@@ -0,0 +1,264 @@
package me.retucio.camtweaks.util;
import me.retucio.camtweaks.event.SubscribeEvent;
import me.retucio.camtweaks.event.events.DisconnectEvent;
import me.retucio.camtweaks.event.events.OpenScreenEvent;
import me.retucio.camtweaks.mixin.accessor.KeyBindingAccessor;
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.GenericContainerScreenHandler;
import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.slot.Slot;
import net.minecraft.screen.slot.SlotActionType;
import net.minecraft.text.Text;
import java.util.ArrayList;
import java.util.List;
import static me.retucio.camtweaks.CameraTweaks.mc;
public class InventoryUtil {
public static final int HOTBAR_START = 0;
public static final int HOTBAR_END = 8;
public static final int MAIN_INVENTORY_START = 9;
public static final int MAIN_INVENTORY_END = 35;
public static final int ARMOR_START = 36;
public static final int ARMOR_END = 39;
public static final int OFFHAND_SLOT = 40;
private static Inventory echestInv;
public static ItemStack getStackOfItem(Item item) {
if (mc.player == null) return null;
for (ItemStack stack : mc.player.getInventory())
if (stack.getItem() == item)
return stack;
return null;
}
public static void swapSlots(int containerSlot1, int containerSlot2, HandledScreen<?> screen) {
if (mc.player == null || mc.interactionManager == null) return;
ScreenHandler handler = screen.getScreenHandler();
int syncId = handler.syncId;
mc.interactionManager.clickSlot(syncId, containerSlot1, 0, SlotActionType.PICKUP, mc.player);
mc.interactionManager.clickSlot(syncId, containerSlot2, 0, SlotActionType.PICKUP, mc.player);
mc.interactionManager.clickSlot(syncId, containerSlot1, 0, SlotActionType.PICKUP, mc.player);
}
public static void swapWithHotbar(int containerSlot, int hotbarSlot, HandledScreen<?> screen) {
if (mc.player == null || mc.interactionManager == null) return;
ScreenHandler handler = screen.getScreenHandler();
mc.interactionManager.clickSlot(handler.syncId, containerSlot, hotbarSlot, SlotActionType.SWAP, mc.player);
}
public static void quickMove(int containerSlot, HandledScreen<?> screen) {
if (mc.player == null || mc.interactionManager == null) return;
ScreenHandler handler = screen.getScreenHandler();
mc.interactionManager.clickSlot(handler.syncId, containerSlot, 0, SlotActionType.QUICK_MOVE, mc.player);
}
public static void dropItem(int containerSlot, boolean dropStack, HandledScreen<?> screen) {
if (mc.player == null || mc.interactionManager == null) return;
ScreenHandler handler = screen.getScreenHandler();
int button = dropStack ? 1 : 0;
mc.interactionManager.clickSlot(handler.syncId, containerSlot, button, SlotActionType.THROW, mc.player);
}
public static int getContainerSlotByPlayerIndex(ScreenHandler handler, int playerStorageIndex) {
for (Slot slot : handler.slots)
if (slot.inventory instanceof PlayerInventory && slot.getIndex() == playerStorageIndex)
return slot.id;
return -1;
}
public static int getPlayerIndexFromContainerSlot(ScreenHandler handler, int containerSlot) {
if (containerSlot < 0 || containerSlot >= handler.slots.size()) return -1;
Slot slot = handler.getSlot(containerSlot);
if (slot.inventory instanceof PlayerInventory)
return slot.getIndex();
return -1;
}
public static boolean isPlayerInventorySlot(ScreenHandler handler, int containerSlot) {
if (containerSlot < 0 || containerSlot >= handler.slots.size()) return false;
Slot slot = handler.getSlot(containerSlot);
return slot.inventory instanceof PlayerInventory;
}
public static List<Integer> getPlayerContainerSlots(ScreenHandler handler) {
List<Integer> playerSlots = new ArrayList<>();
for (Slot slot : handler.slots)
if (slot.inventory instanceof PlayerInventory)
playerSlots.add(slot.id);
return playerSlots;
}
public static List<Integer> getSlotsInSameColumn(ScreenHandler handler, int playerStorageIndex) {
List<Integer> slotsInColumn = new ArrayList<>();
int column = playerStorageIndex % 9;
for (Slot slot : handler.slots) {
if (slot.inventory instanceof PlayerInventory) {
int index = slot.getIndex();
if (index >= 0 && index <= 35) {
if (index % 9 == column) {
slotsInColumn.add(slot.id);
}
}
}
}
slotsInColumn.sort((a, b) -> {
int indexA = getPlayerIndexFromContainerSlot(handler, a);
int indexB = getPlayerIndexFromContainerSlot(handler, b);
return Integer.compare(indexA / 9, indexB / 9);
});
return slotsInColumn;
}
public static void moveToOffhand(int containerSlot, HandledScreen<?> screen) {
if (mc.player == null || mc.interactionManager == null) return;
ScreenHandler handler = screen.getScreenHandler();
int offhandContainerSlot = getContainerSlotByPlayerIndex(handler, OFFHAND_SLOT);
if (offhandContainerSlot == -1) return;
swapSlots(containerSlot, offhandContainerSlot, screen);
}
public static ItemStack getOffhandItem() {
if (mc.player == null) return ItemStack.EMPTY;
return mc.player.getOffHandStack();
}
public static boolean hasEmptyHotbarSlot() {
if (mc.player == null) return false;
PlayerInventory inv = mc.player.getInventory();
for (int i = HOTBAR_START; i <= HOTBAR_END; i++)
if (inv.getStack(i).isEmpty())
return true;
return false;
}
public static int findEmptyHotbarSlot() {
if (mc.player == null) return -1;
PlayerInventory inv = mc.player.getInventory();
for (int i = HOTBAR_START; i <= HOTBAR_END; i++)
if (inv.getStack(i).isEmpty())
return i;
return -1;
}
public static List<Integer> findMatchingItems(HandledScreen<?> screen, ItemStack reference) {
List<Integer> matchingSlots = new ArrayList<>();
if (reference.isEmpty()) return matchingSlots;
ScreenHandler handler = screen.getScreenHandler();
for (int i = 0; i < handler.slots.size(); i++) {
ItemStack stack = handler.getSlot(i).getStack();
if (!stack.isEmpty() && ItemStack.areItemsAndComponentsEqual(reference, stack)) {
matchingSlots.add(i);
}
}
return matchingSlots;
}
public static void quickMoveAll(HandledScreen<?> screen, ItemStack reference) {
if (mc.player == null || mc.interactionManager == null) return;
List<Integer> matchingSlots = findMatchingItems(screen, reference);
ScreenHandler handler = screen.getScreenHandler();
for (int slot : matchingSlots) {
mc.interactionManager.clickSlot(handler.syncId, slot, 0, SlotActionType.QUICK_MOVE, mc.player);
}
}
public static boolean isPlayerScreen(HandledScreen<?> screen) {
return screen.getScreenHandler() instanceof PlayerScreenHandler;
}
public static int getRowOffset(HandledScreen<?> screen) {
return isPlayerScreen(screen) ? 0 : 9;
}
public static int calculateTargetSlot(HandledScreen<?> screen, int currentContainerSlot,
int hotbarColumn, int rowOffset) {
ScreenHandler handler = screen.getScreenHandler();
if (!isPlayerScreen(screen)) {
int targetRow = rowOffset / 9;
for (Slot slot : handler.slots) {
if (slot.inventory instanceof PlayerInventory) {
int playerIndex = slot.getIndex();
if (playerIndex >= 0 && playerIndex <= 35) {
int playerColumn = playerIndex % 9;
int playerRow = playerIndex / 9;
if (playerColumn == hotbarColumn && playerRow == targetRow) {
return slot.id;
}
}
}
}
} else {
if (currentContainerSlot >= 9 && currentContainerSlot <= 44) {
int targetPlayerIndex = hotbarColumn + rowOffset;
if (targetPlayerIndex >= 0 && targetPlayerIndex <= 26) {
return targetPlayerIndex + 9;
} else if (targetPlayerIndex >= 27 && targetPlayerIndex <= 35) {
return targetPlayerIndex - 27 + 36;
}
}
}
return -1;
}
public static int getSlotNumberFromKey(int key) {
for (int i = 0; i < 9; i++)
if (((KeyBindingAccessor) (mc.options.hotbarKeys[i])).getBoundKey().getCode() == key) return i;
return -1;
}
@SubscribeEvent
public static void onOpenScreen(OpenScreenEvent event) {
if (mc.player == null
|| event.getScreen() == null
|| !(mc.player.currentScreenHandler instanceof GenericContainerScreenHandler handler))
return;
if (event.getScreen() instanceof GenericContainerScreen screen
&& screen.getTitle().equals(Text.translatable("container.enderchest")))
echestInv = handler.getInventory();
}
@SubscribeEvent
public void onDisconnect(DisconnectEvent event) {
echestInv = null;
}
public static Inventory getEchestInv() {
return echestInv;
}
}
@@ -21,6 +21,11 @@ public class KeyUtil {
) != GLFW.GLFW_RELEASE;
}
public static boolean isShiftDown() {
return isKeyDown(GLFW.GLFW_KEY_LEFT_SHIFT)
|| isKeyDown(GLFW.GLFW_KEY_RIGHT_SHIFT);
}
public static String getKeyName(int key) {
if (key == GLFW.GLFW_KEY_UNKNOWN) return "ninguna";
@@ -1,13 +1,20 @@
package me.retucio.camtweaks.util;
import com.ibm.icu.impl.locale.XCldrStub;
import net.minecraft.block.Block;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.sound.Sound;
import net.minecraft.entity.EntityType;
import net.minecraft.item.Item;
import net.minecraft.network.packet.PacketType;
import net.minecraft.particle.ParticleType;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.registry.Registries;
import net.minecraft.resource.featuretoggle.FeatureFlag;
import net.minecraft.resource.featuretoggle.FeatureFlags;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.sound.SoundEvent;
import net.minecraft.text.Text;
import java.awt.*;
@@ -30,22 +37,48 @@ public class Lists {
public static Map<Item, String> itemNames;
public static final List<Block> blockList = Registries.BLOCK.stream().toList();
public static Map<Block, String> blockNames;
public static final List<SoundEvent> soundList = Registries.SOUND_EVENT.stream().toList();
public static Map<SoundEvent, String> soundNames;
public static final List<ScreenHandlerType<?>> screenList = Registries.SCREEN_HANDLER.stream().toList();
public static Map<ScreenHandlerType<?>, String> screenNames;
public static final List<Color> colorList = new ArrayList<>();
// intentar traducir nombres y fallar miserablemente
public static void init() {
// no consigo traducir el texto. a tomar por culo, se queda en inglés, si no entiendes pues a estudiar
entityNames = getMapOfLists(entityList,
entityList.stream().map(entity -> I18n.translate(entity.getTranslationKey())).toList());
entityList.stream().map(entity -> Text.translatable(entity.getTranslationKey()).getString()).toList());
// no hay traducciones para nombres de partículas, y paso de hacerlas yo
particleNames = getMapOfLists(particleList,
particleList.stream().map(particle -> Registries.PARTICLE_TYPE.getId(particle).toShortTranslationKey()).toList());
particleList.stream().map(particle -> Text.translatable(
Registries.PARTICLE_TYPE.getId(particle).toShortTranslationKey()).getString()
).toList());
itemNames = getMapOfLists(itemList,
itemList.stream().map(item -> I18n.translate(item.getTranslationKey())).toList());
itemList.stream().map(item -> Text.translatable(
item.getTranslationKey()).getString()
).toList());
colorList.addAll(Arrays.asList(RED, ORANGE, YELLOW, LIME, GREEN, CYAN, CELESTE, BLUE, PURPLE, MAGENTA, PINK, LAVENDER, WHITE, SILVER, GRAY, BLACK, BROWN));
blockNames = getMapOfLists(blockList,
blockList.stream().map(block -> Text.translatable(
block.getTranslationKey()).getString()
).toList());
soundNames = getMapOfLists(soundList,
soundList.stream().map(sound -> Text.translatable(
sound.id().toShortTranslationKey()).getString()
).toList());
screenNames = getMapOfLists(screenList,
screenList.stream().map(screen -> Text.translatable(
Registries.SCREEN_HANDLER.getId(screen).toShortTranslationKey()).getString()
).toList());
colorList.addAll(Arrays.asList(
RED, ORANGE, YELLOW, LIME, GREEN, CYAN, CELESTE, BLUE, PURPLE, MAGENTA, PINK, LAVENDER, WHITE, SILVER, GRAY, BLACK, BROWN));
}
public static <T> Map<T, Boolean> allTrue(List<T> options) {
@@ -1,29 +1,23 @@
package me.retucio.camtweaks.util;
import me.retucio.camtweaks.event.SubscribeEvent;
import me.retucio.camtweaks.event.events.DisconnectEvent;
import me.retucio.camtweaks.event.events.OpenScreenEvent;
import me.retucio.camtweaks.event.events.TickEvent;
import me.retucio.camtweaks.module.ModuleManager;
import me.retucio.camtweaks.module.modules.HUD;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
import net.minecraft.entity.Entity;
import net.minecraft.entity.projectile.ProjectileUtil;
import net.minecraft.inventory.Inventory;
import net.minecraft.screen.GenericContainerScreenHandler;
import net.minecraft.text.Text;
import net.minecraft.util.annotation.UsesSystemOut;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import org.joml.Vector3d;
import java.time.Instant;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import static me.retucio.camtweaks.CameraTweaks.mc;
public class MiscUtil {
public static Screen screen;
private static Inventory echestInv;
@SubscribeEvent
public static void onTick(TickEvent.Post event) {
@@ -33,58 +27,29 @@ public class MiscUtil {
}
}
@SubscribeEvent
public static void onOpenScreen(OpenScreenEvent event) {
if (mc.player == null
|| event.getScreen() == null
|| !(mc.player.currentScreenHandler instanceof GenericContainerScreenHandler handler))
return;
if (event.getScreen() instanceof GenericContainerScreen screen
&& screen.getTitle().equals(Text.translatable("container.enderchest")))
echestInv = handler.getInventory();
}
@SubscribeEvent
public void onDisconnect(DisconnectEvent event) {
echestInv = null;
}
public static void copyVector(Vector3d destination, Vec3d source) {
destination.x = source.x;
destination.y = source.y;
destination.z = source.z;
}
public static Vector3d getEntityVector(Vector3d vector, Entity entity, double tickDelta) {
vector.x = MathHelper.lerp(tickDelta, entity.lastRenderX, entity.getX());
vector.y = MathHelper.lerp(tickDelta, entity.lastRenderY, entity.getY());
vector.z = MathHelper.lerp(tickDelta, entity.lastRenderZ, entity.getZ());
return vector;
public static String getCurrentFormattedTime() {
return getFormattedTime(System.currentTimeMillis());
}
public static Entity getEntityPlayerIsLookingAt() {
if (mc.player == null || mc.world == null) return null;
public static String getFormattedTime(long timeMillis) {
try {
HUD hud = ModuleManager.INSTANCE.getModuleByClass(HUD.class);
Instant instant = Instant.ofEpochMilli(timeMillis);
ZoneOffset offset = ZoneOffset.ofHours(hud.timezone.getIntValue());
LocalTime time = LocalTime.from(instant.atOffset(offset));
float reachDistance = (float) mc.player.getEntityInteractionRange();
Vec3d cameraPos = mc.player.getCameraPosVec(1.0F);
Vec3d rotation = mc.player.getRotationVec(1.0F);
Vec3d endPos = cameraPos.add(rotation.x * reachDistance, rotation.y * reachDistance, rotation.z * reachDistance);
EntityHitResult entityHitResult = ProjectileUtil.raycast(
mc.player,
cameraPos,
endPos,
new Box(cameraPos, endPos),
entity -> !entity.isSpectator() && entity.canHit(),
reachDistance * reachDistance
);
return entityHitResult != null ? entityHitResult.getEntity() : null;
boolean is24 = hud.timeFormat.is(HUD.TimeFormat.TWENTY_FOUR_HOUR);
DateTimeFormatter format = DateTimeFormatter.ofPattern(is24 ? "HH:mm" : "hh:mm a");
return time.format(format);
} catch (Exception e) {
return "??:??";
}
}
public static Inventory getEchestInv() {
return echestInv;
}
}
@@ -0,0 +1,74 @@
package me.retucio.camtweaks.util;
import me.retucio.camtweaks.event.SubscribeEvent;
import me.retucio.camtweaks.event.events.PacketEvent;
import net.minecraft.client.MinecraftClient;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.listener.PacketListener;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.s2c.play.WorldTimeUpdateS2CPacket;
import java.util.ArrayList;
import java.util.List;
public class NetworkUtil {
private static final MinecraftClient mc = MinecraftClient.getInstance();
// tps
private static final List<Float> tpsHistory = new ArrayList<>();
private static float estimatedTPS = 20f;
private static long lastWorldTime = -1L;
private static long lastRealTime = -1L;
public static float getTPS() {
return estimatedTPS;
}
public static void updateTPS(float tps) {
tpsHistory.add(tps);
if (tpsHistory.size() > 10)
tpsHistory.removeFirst();
float sum = 0;
for (float t : tpsHistory) sum += t;
estimatedTPS = sum / tpsHistory.size();
}
@SubscribeEvent
public void onReceivePacket(PacketEvent.Receive event) {
if (event.getPacket() instanceof WorldTimeUpdateS2CPacket packet) {
long currentWorldTime = packet.time();
long currentRealTime = System.currentTimeMillis();
if (lastWorldTime != -1L && lastRealTime != -1L) {
long elapsedRealTime = currentRealTime - lastRealTime;
long elapsedWorldTicks = currentWorldTime - lastWorldTime;
if (elapsedRealTime > 0) {
float tps = (float) elapsedWorldTicks / (elapsedRealTime / 1000.0f);
tps = Math.max(0.1f, Math.min(20.0f, tps));
updateTPS(tps);
}
}
lastWorldTime = currentWorldTime;
lastRealTime = currentRealTime;
}
}
public static void sendPacketNoEvent(Packet<?> packet) {
mc.getNetworkHandler().getConnection().sendImmediately(packet, null, true);
}
public static void receivePacketNoEvent(Packet<?> packet) {
receivePacketNoEvent(packet, mc.getNetworkHandler().getConnection().getPacketListener());
}
public static void receivePacketNoEvent(Packet<?> packet, PacketListener listener) {
ClientConnection.handlePacket(packet, listener);
}
}
@@ -2,14 +2,15 @@ package me.retucio.camtweaks.util.render;
import com.mojang.blaze3d.vertex.VertexFormat;
import me.retucio.camtweaks.util.ChatUtil;
import net.minecraft.SharedConstants;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.render.*;
import net.minecraft.client.render.state.OutlineRenderState;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.*;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import java.awt.*;
@@ -19,16 +20,77 @@ public class RenderUtil {
private static final MinecraftClient mc = MinecraftClient.getInstance();
private static final Tessellator tesselator = Tessellator.getInstance();
public static void drawBlockOutline(MatrixStack matrices, BlockPos pos, Color color, double lineWidth) {
Box box = new Box(pos.getX(), pos.getY(), pos.getZ(),
pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1);
drawOutlineBox(matrices, box, color, lineWidth);
// líneas
public static void drawHorizontalLine(MatrixStack matrices, float x1, float x2, float y, Color color) {
if (x2 < x1) {
float i = x1;
x1 = x2;
x2 = i;
}
drawFilledRect(matrices, x1, y, x2 + 1, y + 1, color);
}
public static void drawBlockFilled(MatrixStack matrices, BlockPos pos, Color color) {
Box box = new Box(pos.getX(), pos.getY(), pos.getZ(),
pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1);
drawFilledBox(matrices, box, color);
public static void drawVerticalLine(MatrixStack matrices, float x, float y1, float y2, Color color) {
if (y2 < y1) {
float i = y1;
y1 = y2;
y2 = i;
}
drawFilledRect(matrices, x, y1 + 1, x + 1, y2, color);
}
public static void drawHorizontalLine(MatrixStack matrices, float x1, float x2, float y, Color color, float width) {
if (x2 < x1) {
float i = x1;
x1 = x2;
x2 = i;
}
drawFilledRect(matrices, x1, y, x2 + width, y + width, color);
}
public static void drawVerticalLine(MatrixStack matrices, float x, float y1, float y2, Color color, float width) {
if (y2 < y1) {
float i = y1;
y1 = y2;
y2 = i;
}
drawFilledRect(matrices, x, y1 + width, x + width, y2, color);
}
// caras
public static void drawFilledRect(MatrixStack matrices, float x, float y, float width, float height, Color color) {
float r = color.getRed() / 255f;
float g = color.getGreen() / 255f;
float b = color.getBlue() / 255f;
float a = color.getAlpha() / 255f;
matrices.push();
matrices.translate(0, 0, 0);
BufferBuilder buffer = tesselator.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);
buffer.vertex(matrices.peek().getPositionMatrix(), x, y + height, 0).color(r, g, b, a);
buffer.vertex(matrices.peek().getPositionMatrix(), x + width, y + height, 0).color(r, g, b, a);
buffer.vertex(matrices.peek().getPositionMatrix(), x + width, y, 0).color(r, g, b, a);
buffer.vertex(matrices.peek().getPositionMatrix(), x, y, 0).color(r, g, b, a);
Layers.getGlobalQuads().draw(buffer.end());
matrices.pop();
}
public static void drawRectOutlines(MatrixStack stack, float x1, float y1, float x2, float y2, Color color, float width) {
drawHorizontalLine(stack, x1, x2, y1, color, width);
drawVerticalLine(stack, x2, y1, y2, color, width);
drawHorizontalLine(stack, x1, x2, y2, color, width);
drawVerticalLine(stack, x1, y1, y2, color, width);
}
// expand es para evitar z-fighting
@@ -107,71 +169,10 @@ public class RenderUtil {
Layers.getGlobalQuads().draw(buffer.end());
}
public static void drawLine(MatrixStack matrices, Vec3d start, Vec3d end, Color color, float width) {
Vec3d cameraPos = mc.gameRenderer.getCamera().getPos();
float x1 = (float) (start.x - cameraPos.x);
float y1 = (float) (start.y - cameraPos.y);
float z1 = (float) (start.z - cameraPos.z);
float x2 = (float) (end.x - cameraPos.x);
float y2 = (float) (end.y - cameraPos.y);
float z2 = (float) (end.z - cameraPos.z);
// cajas
float r = color.getRed() / 255f;
float g = color.getGreen() / 255f;
float b = color.getBlue() / 255f;
float a = color.getAlpha() / 255f;
BufferBuilder buffer = tesselator.begin(VertexFormat.DrawMode.LINE_STRIP, VertexFormats.POSITION_COLOR);
buffer.vertex(matrices.peek().getPositionMatrix(), x1, y1, z1).color(r, g, b, a);
buffer.vertex(matrices.peek().getPositionMatrix(), x2, y2, z2).color(r, g, b, a);
Layers.getGlobalLines(width).draw(buffer.end());
}
public static void drawOutlineRect(MatrixStack matrices, float x, float y, float w, float h, Color color, int linewidth) {
float r = color.getRed() / 255f;
float g = color.getGreen() / 255f;
float b = color.getBlue() / 255f;
float a = color.getAlpha() / 255f;
matrices.push();
matrices.translate(0, 0, 0);
BufferBuilder buffer = tesselator.begin(VertexFormat.DrawMode.DEBUG_LINE_STRIP, VertexFormats.POSITION_COLOR);
buffer.vertex(matrices.peek().getPositionMatrix(), x, y, 0).color(r, g, b, a);
buffer.vertex(matrices.peek().getPositionMatrix(), x + w, y, 0).color(r, g, b, a);
buffer.vertex(matrices.peek().getPositionMatrix(), x + w, y + h, 0).color(r, g, b, a);
buffer.vertex(matrices.peek().getPositionMatrix(), x, y + h, 0).color(r, g, b, a);
buffer.vertex(matrices.peek().getPositionMatrix(), x, y, 0).color(r, g, b, a);
Layers.getGlobalLines(linewidth).draw(buffer.end());
matrices.pop();
}
public static void drawFilledRect(MatrixStack matrices, float x, float y, float width, float height, Color color) {
float r = color.getRed() / 255f;
float g = color.getGreen() / 255f;
float b = color.getBlue() / 255f;
float a = color.getAlpha() / 255f;
matrices.push();
matrices.translate(0, 0, 0);
BufferBuilder buffer = tesselator.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);
buffer.vertex(matrices.peek().getPositionMatrix(), x, y + height, 0).color(r, g, b, a);
buffer.vertex(matrices.peek().getPositionMatrix(), x + width, y + height, 0).color(r, g, b, a);
buffer.vertex(matrices.peek().getPositionMatrix(), x + width, y, 0).color(r, g, b, a);
buffer.vertex(matrices.peek().getPositionMatrix(), x, y, 0).color(r, g, b, a);
Layers.getGlobalQuads().draw(buffer.end());
matrices.pop();
}
public static void drawOutlineBox(MatrixStack matrices, Box box, Color color, double lineWidth) {
public static void drawOutlineBox(MatrixStack matrices, Box box, Color color, float lineWidth) {
float r = color.getRed() / 255f;
float g = color.getGreen() / 255f;
float b = color.getBlue() / 255f;
@@ -235,4 +236,48 @@ public class RenderUtil {
Layers.getGlobalQuads().draw(buffer.end());
}
// formas custom
public static void drawVoxelShapeOutline(MatrixStack matrices, VoxelShape voxelShape, BlockPos pos, Color color, float lineWidth) {
if (voxelShape.isEmpty()) return;
voxelShape.forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> {
Box box = new Box(
pos.getX() + minX, pos.getY() + minY, pos.getZ() + minZ,
pos.getX() + maxX, pos.getY() + maxY, pos.getZ() + maxZ
);
drawOutlineBox(matrices, box, color, lineWidth);
});
}
public static void drawVoxelShapeFilled(MatrixStack matrices, VoxelShape voxelShape, BlockPos pos, Color color) {
if (voxelShape.isEmpty()) return;
voxelShape.forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> {
Box box = new Box(
pos.getX() + minX, pos.getY() + minY, pos.getZ() + minZ,
pos.getX() + maxX, pos.getY() + maxY, pos.getZ() + maxZ
);
drawFilledBox(matrices, box, color);
});
}
// bloques
public static void drawBlockOutline(MatrixStack matrices, BlockPos pos, Color color, float lineWidth) {
Box box = new Box(pos.getX(), pos.getY(), pos.getZ(),
pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1);
drawOutlineBox(matrices, box, color, lineWidth);
}
public static void drawBlockFilled(MatrixStack matrices, BlockPos pos, Color color) {
Box box = new Box(pos.getX(), pos.getY(), pos.getZ(),
pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1);
drawFilledBox(matrices, box, color);
}
}
+10 -2
View File
@@ -1,5 +1,13 @@
accessWidener v2 named
accessible method net/minecraft/network/ClientConnection handleQueuedTasks ()V
accessible method net/minecraft/network/ClientConnection sendImmediately (Lnet/minecraft/network/packet/Packet;Lio/netty/channel/ChannelFutureListener;Z)V
accessible field net/minecraft/network/ClientConnection queuedTasks Ljava/util/Queue;
accessible method net/minecraft/network/ClientConnection handlePacket (Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;)V
accessible class net/minecraft/client/network/ClientCommonNetworkHandler$ConfirmServerResourcePackScreen
accessible class net/minecraft/client/network/ClientCommonNetworkHandler$ConfirmServerResourcePackScreen$Pack
accessible class net/minecraft/client/font/TextRenderer$Drawer
accessible field net/minecraft/client/particle/BillboardParticle alpha F
@@ -9,9 +17,9 @@ accessible field net/minecraft/client/particle/Particle gravityStrength F
accessible field net/minecraft/client/particle/Particle collidesWithWorld Z
accessible field net/minecraft/entity/LivingEntity jumpingCooldown I
accessible field net/minecraft/client/render/WorldRenderer worldRenderState Lnet/minecraft/client/render/state/WorldRenderState;
accessible method net/minecraft/client/render/WorldRenderer method_74752 (Lnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/Frustum;Z)V
accessible method net/minecraft/client/render/GameRenderer getProjectionMatrix (F)Lorg/joml/Matrix4f;
accessible method net/minecraft/client/render/command/DebugHitboxCommandRenderer renderDebugHitbox (Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/entity/state/EntityHitboxAndView;Lnet/minecraft/client/render/VertexConsumer;F)V
accessible class net/minecraft/client/network/ClientCommonNetworkHandler$ConfirmServerResourcePackScreen
accessible class net/minecraft/client/network/ClientCommonNetworkHandler$ConfirmServerResourcePackScreen$Pack
accessible method net/minecraft/screen/ScreenHandlerType register (Ljava/lang/String;Lnet/minecraft/screen/ScreenHandlerType$Factory;)Lnet/minecraft/screen/ScreenHandlerType;