This commit is contained in:
retuci0 committed 2026-05-03 15:06:20 +02:00
1 parent 8933565e07
commit 65afbf6ae6
14 files changed
+179 -67

No files matched your search

+5 -7
View File
@@ -1,4 +1,4 @@
# v4.4
# v4.5
## novedades
@@ -8,17 +8,15 @@
### arreglos / mejoras
- brilli brilli ya funciona
- zoom ya funciona
- zoom ahora ya sí que ya funciona
- arreglado el movimiento laggy de cámara libre
- las cabezas de chatplus ya se renderizan correctamente
## problemas reconocidos
- lo de siempre, además de:
- `colocar en aire` no funciona si el bloque está muy cerca, aunque no colisione con el jugador
- `delay de paquetes` puede crashear el juego
- las cabezas de `chat plus` solo se dibujar en la pantalla del chat, no en el overlay
- movimiento laggy en `cámara libre`
- `inventario plus` no funciona en creativo
- `RPC de Discord` no funciona e incluso puede provocar crashes
- `destello de enchants.` no funciona.
- `destello de enchants.` no funciona, solamente lo hace en la armadura equipada y en ítems translúcidos.
+1 -1
View File
@@ -10,6 +10,6 @@ discord_rpc_version=1.0.3
neutrino_version=1.1.0
jdk_version=25
mod_version=4.4
mod_version=4.5
maven_group=me.retucio
archives_base_name=sputnik
@@ -140,7 +140,8 @@ public class Sputnik implements ClientModInitializer {
// se ejecuta cada vez que se presiona una tecla
public void onInput(int key, int action) {
if (key == GLFW.GLFW_KEY_F3) return; // prevenir interrumpir combos de F3
// prevenir interrumpir combos de F3
if (key == GLFW.GLFW_KEY_F3) return;
boolean anyFocused = isAnySettingButtonFocused() || ClickGUI.INSTANCE.getSearchBar().isFocused();
ClickGUI.INSTANCE.setAnyFocused(anyFocused);
@@ -0,0 +1,59 @@
package me.retucio.sputnik.mixin.mixins.hud;
import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.misc.ChatPlus;
import net.minecraft.client.gui.ActiveTextCollector;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.TextAlignment;
import net.minecraft.client.gui.components.ChatComponent;
import net.minecraft.util.ARGB;
import net.minecraft.util.FormattedCharSequence;
import com.llamalad7.mixinextras.injector.ModifyReceiver;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
/**
* al parecer si hago un mixin combinado ninguno de los dos funciona
* @see DrawingFocusedGraphicsAccessMixin
*/
@Mixin(ChatComponent.DrawingBackgroundGraphicsAccess.class)
public abstract class DrawingBackgroundGraphicsAccessMixin {
@Unique
private static ChatPlus chatPlus;
@Shadow @Final
private GuiGraphicsExtractor graphics;
@Inject(method = "<init>", at = @At("TAIL"))
private void getModules(CallbackInfo ci) {
chatPlus = ModuleManager.INSTANCE.getModuleByClass(ChatPlus.class);
}
@ModifyReceiver(method = "handleMessage", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/ActiveTextCollector;accept(Lnet/minecraft/client/gui/TextAlignment;IILnet/minecraft/client/gui/ActiveTextCollector$Parameters;Lnet/minecraft/util/FormattedCharSequence;)V"))
private ActiveTextCollector onRender_beforeDrawTextWithShadow(ActiveTextCollector instance, TextAlignment textAlignment, int x, int y, ActiveTextCollector.Parameters parameters, FormattedCharSequence formattedCharSequence) {
chatPlus.beforeDrawMessage(graphics, y, ARGB.white(parameters.opacity()));
return instance;
}
@ModifyArg(method = "handleMessage", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/ActiveTextCollector;accept(Lnet/minecraft/client/gui/TextAlignment;IILnet/minecraft/client/gui/ActiveTextCollector$Parameters;Lnet/minecraft/util/FormattedCharSequence;)V"), index = 1)
private int modifyX(int x) {
return (chatPlus.isEnabled() && chatPlus.showHeads.getValue()) ? x + 10 : x;
}
@Inject(method = "handleMessage", at = @At("TAIL"))
private void onRender_afterDrawTextWithShadow(int textTop, float opacity, FormattedCharSequence message, CallbackInfoReturnable<Boolean> cir) {
chatPlus.afterDrawMessage();
}
}
@@ -22,6 +22,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
/**
* al parecer si hago un mixin combinado ninguno de los dos funciona
* @see DrawingBackgroundGraphicsAccessMixin
*/
@Mixin(ChatComponent.DrawingFocusedGraphicsAccess.class)
public abstract class DrawingFocusedGraphicsAccessMixin {
@@ -1,6 +1,7 @@
package me.retucio.sputnik.mixin.mixins.render;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import me.retucio.sputnik.Sputnik;
import me.retucio.sputnik.event.render.GetFOVEvent;
import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.camera.Freelook;
@@ -8,7 +9,6 @@ import me.retucio.sputnik.module.modules.camera.Freecam;
import me.retucio.sputnik.module.modules.camera.PerspectivePlus;
import net.minecraft.client.Camera;
import net.minecraft.client.DeltaTracker;
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
@@ -20,8 +20,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.invoke.arg.Args;
import static me.retucio.sputnik.Sputnik.EVENT_BUS;
@Mixin(Camera.class)
public abstract class CameraMixin {
@@ -50,12 +48,12 @@ public abstract class CameraMixin {
@Inject(method = "update", at = @At("HEAD"))
private void onUpdateHead(DeltaTracker deltaTracker, CallbackInfo ci) {
this.tickDelta = deltaTracker.getGameTimeDeltaTicks();
this.tickDelta = deltaTracker.getGameTimeDeltaPartialTick(true);
}
@ModifyReturnValue(method = "getFov", at = @At("RETURN"))
@ModifyReturnValue(method = "calculateFov", at = @At("RETURN"))
private float modifyFov(float original) {
return EVENT_BUS.post(new GetFOVEvent(original)).getFov();
return Sputnik.EVENT_BUS.post(new GetFOVEvent(original)).getFov();
}
// perspectiva
@@ -4,31 +4,49 @@ import me.retucio.sputnik.module.ModuleManager;
import me.retucio.sputnik.module.modules.render.GlintPlus;
import net.minecraft.client.renderer.feature.ItemFeatureRenderer;
import net.minecraft.client.renderer.rendertype.RenderType;
import net.minecraft.client.renderer.rendertype.RenderTypes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ItemFeatureRenderer.class)
public abstract class ItemFeatureRendererMixin {
@Unique
private static GlintPlus glintPlus;
// obtener módulo en cada redirect, ya que tiene un inicializador estático
@Inject(method = "<init>", at = @At("TAIL"))
private void getModules(CallbackInfo ci) {
glintPlus = ModuleManager.INSTANCE.getModuleByClass(GlintPlus.class);
@Shadow
private static boolean useTransparentGlint(RenderType renderType) {
throw new UnsupportedOperationException("implemented via mixin");
}
@Redirect(method = "getFoilRenderType", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/feature/ItemFeatureRenderer;useTransparentGlint(Lnet/minecraft/client/renderer/rendertype/RenderType;)Z"))
private static boolean alwaysUseTranslucentGlint(RenderType renderType) {
GlintPlus glintPlus = ModuleManager.INSTANCE.getModuleByClass(GlintPlus.class);
if (!glintPlus.isEnabled()) {
useTransparentGlint(renderType);
}
return true;
}
@Redirect(method = "getFoilRenderType", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/rendertype/RenderTypes;glint()Lnet/minecraft/client/renderer/rendertype/RenderType;"))
private static RenderType getGlint() {
return glintPlus.getGlint();
private static RenderType redirectGlint() {
GlintPlus glintPlus = ModuleManager.INSTANCE.getModuleByClass(GlintPlus.class);
if (glintPlus == null) return RenderTypes.glint();
return glintPlus.getGlintTranslucent();
}
@Redirect(method = "getFoilRenderType", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/rendertype/RenderTypes;entityGlint()Lnet/minecraft/client/renderer/rendertype/RenderType;"))
private static RenderType getEntityGlint() {
return glintPlus.getEntityGlint();
private static RenderType redirectEntityGlint() {
GlintPlus glintPlus = ModuleManager.INSTANCE.getModuleByClass(GlintPlus.class);
if (glintPlus == null) return RenderTypes.entityGlint();
return glintPlus.getGlintTranslucent();
}
@Redirect(method = "getFoilRenderType", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/rendertype/RenderTypes;glintTranslucent()Lnet/minecraft/client/renderer/rendertype/RenderType;"))
private static RenderType redirectGlintTranslucent() {
GlintPlus glintPlus = ModuleManager.INSTANCE.getModuleByClass(GlintPlus.class);
if (glintPlus == null) return RenderTypes.glintTranslucent();
return glintPlus.getGlintTranslucent();
}
}
@@ -9,10 +9,6 @@ import me.retucio.sputnik.command.CommandManager;
import me.retucio.sputnik.event.input.ClientClickEvent;
import me.retucio.sputnik.event.network.ReceiveMessageEvent;
import me.retucio.sputnik.event.network.SendMessageEvent;
import me.retucio.sputnik.mixin.mixins.hud.ChatComponentMixin;
import me.retucio.sputnik.mixin.mixins.hud.GuiMixin;
import me.retucio.sputnik.mixin.mixins.misc.StringUtilMixin;
import me.retucio.sputnik.mixin.mixins.screen.ChatScreenMixin;
import me.retucio.sputnik.module.Category;
import me.retucio.sputnik.module.Module;
import me.retucio.sputnik.module.setting.SettingGroup;
@@ -45,8 +41,12 @@ import java.util.regex.Pattern;
/** continúa en:
* @see ChatComponentMixin
* @see ChatScreenMixin
* @see DrawingBackgroundGraphicsAccessMixin
* @see DrawingFocusedGraphicsAccessMixin
* @see GuiMixin
* @see StringUtilMixin
*
* @author retucio
*/
public class ChatPlus extends Module {
@@ -82,10 +82,10 @@ public class ChatPlus extends Module {
private static final List<CustomHeadEntry> CUSTOM_HEAD_ENTRIES = new ArrayList<>();
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*)?(?:<([^<>\\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*)?)");
private static final Pattern LOGGER_REGEX = Pattern.compile("\\n([\\n\\s])+\\n");
private static final Pattern USERNAME_REGEX = Pattern.compile("^(?:\\[[0-9]{2}:[0-9]{2}]\\s*)?(?:<([^<>\\s]+)>|([^<>\\s]+)).*");
private static final Pattern TIMESTAMP_REGEX = Pattern.compile("^<\\d{1,2}:\\d{1,2}>");
private static final Pattern COORDS_REGEX = Pattern.compile("(?<x>-?\\d{3,}(?:\\.\\d*)?)(?:\\s+(?<y>-?\\d{1,3}(?:\\.\\d*)?))?\\s+(?<z>-?\\d{3,}(?:\\.\\d*)?)");
@EventListener
private void onReceiveMessage(ReceiveMessageEvent event) {
@@ -94,10 +94,10 @@ public class ChatPlus extends Module {
// registrar mensajes para evitar su eliminación
if (logger.getValue()) {
String messageString = message.getString();
if (loggerRegex.matcher(messageString).find()) {
if (LOGGER_REGEX.matcher(messageString).find()) {
MutableComponent newMessage = Component.empty();
TextVisitor.visit(message, (text, style, string) -> {
Matcher antiClearMatcher = loggerRegex.matcher(string);
Matcher antiClearMatcher = LOGGER_REGEX.matcher(string);
if (antiClearMatcher.find())
newMessage.append(Component.literal(antiClearMatcher.replaceAll("\n\n")).setStyle(style));
else
@@ -156,7 +156,7 @@ public class ChatPlus extends Module {
int startOffset = 0;
try {
Matcher m = timestampRegex.matcher(text);
Matcher m = TIMESTAMP_REGEX.matcher(text);
if (m.find()) startOffset = m.end() + 1;
}
catch (IllegalStateException ignored) {}
@@ -183,7 +183,7 @@ public class ChatPlus extends Module {
GameProfile sender = line.sputnik$getSender();
if (sender == null) {
Matcher usernameMatcher = usernameRegex.matcher(text);
Matcher usernameMatcher = USERNAME_REGEX.matcher(text);
if (usernameMatcher.matches()) {
String username = usernameMatcher.group(1);
@@ -226,6 +226,6 @@ public class ChatPlus extends Module {
}
private boolean containsCoordinates(String message) {
return coordRegex.matcher(message).find();
return COORDS_REGEX.matcher(message).find();
}
}
@@ -51,6 +51,12 @@ public class GlintPlus extends Module {
return GlintRenderType.glintColor.get(color);
}
public RenderType getGlintTranslucent() {
int color = getColor();
if (!isEnabled() || !items.getValue()) return RenderTypes.glintTranslucent();
return GlintRenderType.glintTranslucentColor.get(color);
}
public RenderType getEntityGlint() {
int color = getColor();
if (!isEnabled() || !items.getValue()) return RenderTypes.entityGlint();
@@ -163,7 +163,7 @@ public class ClickGUI extends Screen {
}
@Override
public boolean mouseDragged(MouseButtonEvent click, double deltaX, double deltaY) {
public boolean mouseDragged(@NonNull MouseButtonEvent click, double deltaX, double deltaY) {
miscWidgets.forEach(w -> w.mouseDragged(
(int) click.x(),
(int) click.y()));
@@ -275,7 +275,6 @@ public class ClickGUI extends Screen {
public void openSettingsFrame(Module module, int x, int y) {
// asegurarse de que no se sale de la pantalla
x = Math.clamp(x, 0, mc.getWindow().getGuiScaledWidth() - 80);
y = Math.clamp(y, 0, mc.getWindow().getGuiScaledHeight() - 120);
SettingsFrame frame = new SettingsFrame(module, x, y, 100, 20);
settingsFrames.add(frame);
@@ -378,8 +377,8 @@ public class ClickGUI extends Screen {
}
@Override
protected void extractBlurredBackground(GuiGraphicsExtractor ctx) {
if (guiSettings.blur.getValue()) super.extractBlurredBackground(ctx);
protected void extractBlurredBackground(@NonNull GuiGraphicsExtractor gui) {
if (guiSettings.blur.getValue()) super.extractBlurredBackground(gui);
}
@@ -49,11 +49,15 @@ public class ModuleButton extends Button {
if (button == 0) { // clic izquierdo para activar / desactivar el módulo
module.toggle();
} else if (button == 1) { // clic derecho para el marco de ajustes (también lo cierra si está abierto)
if (ClickGUI.INSTANCE.isSettingsFrameOpen(module))
if (ClickGUI.INSTANCE.isSettingsFrameOpen(module)) {
ClickGUI.INSTANCE.closeSettingsFrame(module);
else
ClickGUI.INSTANCE.openSettingsFrame(module,
parent.getX() + parent.getW() + 120, parent.getRenderY() + offset);
} else {
ClickGUI.INSTANCE.openSettingsFrame(
module,
parent.getX() + parent.getW() + 120,
parent.getY() + offset
);
}
}
}
}
@@ -1,6 +1,5 @@
package me.retucio.sputnik.util.render;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.vertex.ByteBufferBuilder;
import com.mojang.blaze3d.vertex.MeshData;
import com.mojang.blaze3d.vertex.VertexFormat;
@@ -26,12 +25,14 @@ import java.util.function.Function;
public class GlintRenderType extends RenderType {
public static List<RenderType> glintColor = newRenderList(GlintRenderType::buildGlintRenderLayer);
public static List<RenderType> entityGlintColor = newRenderList(GlintRenderType::buildEntityGlintRenderLayer);
public static List<RenderType> armorEntityGlintColor = newRenderList(GlintRenderType::buildArmorEntityGlintRenderLayer);
public static List<RenderType> glintColor = newRenderList(GlintRenderType::buildGlintRenderType);
public static List<RenderType> entityGlintColor = newRenderList(GlintRenderType::buildEntityGlintRenderType);
public static List<RenderType> armorEntityGlintColor = newRenderList(GlintRenderType::buildArmorEntityGlintRenderType);
public static List<RenderType> glintTranslucentColor = newRenderList(GlintRenderType::buildGlintTranslucentRenderType);
public static void addGlintTypes(Object2ObjectLinkedOpenHashMap<RenderType, ByteBufferBuilder> map) {
addGlintTypes(map, glintColor);
addGlintTypes(map, glintTranslucentColor);
addGlintTypes(map, entityGlintColor);
addGlintTypes(map, armorEntityGlintColor);
}
@@ -58,38 +59,55 @@ public class GlintRenderType extends RenderType {
map.put(renderType, new ByteBufferBuilder(renderType.bufferSize()));
}
private static RenderType buildGlintRenderLayer(String name) {
private static RenderType buildGlintRenderType(String name) {
final Identifier res = Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "textures/misc/glint_" + name.toLowerCase() + ".png");
return RenderType.create("glint_" + name, RenderSetup.builder(RenderPipelines.GLINT)
return RenderType.create(
"glint_" + name,
RenderSetup.builder(RenderPipelines.GLINT)
.withTexture("Sampler0", res)
.setTextureTransform(TextureTransform.GLINT_TEXTURING)
.sortOnUpload()
.createRenderSetup());
.setOutputTarget(OutputTarget.ITEM_ENTITY_TARGET)
.createRenderSetup()
);
}
private static RenderType buildEntityGlintRenderLayer(String name) {
private static RenderType buildGlintTranslucentRenderType(String name) {
final Identifier res = Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "textures/misc/glint_" + name.toLowerCase() + ".png");
return RenderType.create("entity_glint_" + name, RenderSetup.builder(RenderPipelines.GLINT)
return RenderType.create(
"glint_translucent_" + name,
RenderSetup.builder(RenderPipelines.GLINT)
.withTexture("Sampler0", res)
.setTextureTransform(TextureTransform.GLINT_TEXTURING)
.setOutputTarget(OutputTarget.ITEM_ENTITY_TARGET)
.createRenderSetup()
);
}
private static RenderType buildEntityGlintRenderType(String name) {
final Identifier res = Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "textures/misc/glint_" + name.toLowerCase() + ".png");
return RenderType.create(
"entity_glint_" + name,
RenderSetup.builder(RenderPipelines.GLINT)
.withTexture("Sampler0", res)
.setTextureTransform(TextureTransform.ENTITY_GLINT_TEXTURING)
.setOutputTarget(OutputTarget.ITEM_ENTITY_TARGET)
.sortOnUpload()
.createRenderSetup());
.createRenderSetup()
);
}
private static RenderType buildArmorEntityGlintRenderLayer(String name) {
private static RenderType buildArmorEntityGlintRenderType(String name) {
final Identifier res = Identifier.fromNamespaceAndPath(Sputnik.MOD_ID, "textures/misc/glint_" + name.toLowerCase() + ".png");
return RenderType.create("armor_glint_" + name, RenderSetup.builder(RenderPipelines.GLINT)
return RenderType.create(
"armor_glint_" + name,
RenderSetup.builder(RenderPipelines.GLINT)
.withTexture("Sampler0", res)
.setTextureTransform(TextureTransform.ARMOR_ENTITY_GLINT_TEXTURING)
.setLayeringTransform(LayeringTransform.VIEW_OFFSET_Z_LAYERING)
.sortOnUpload()
.createRenderSetup());
.createRenderSetup()
);
}
@Override
+5
View File
@@ -16,6 +16,7 @@ accessible field net/minecraft/client/StringSplitter widthProvider Lnet/minecraf
# chat
accessible class net/minecraft/client/gui/components/ChatComponent$DrawingFocusedGraphicsAccess
accessible method net/minecraft/client/gui/components/ChatComponent addMessage (Lnet/minecraft/network/chat/Component;Lnet/minecraft/network/chat/MessageSignature;Lnet/minecraft/client/multiplayer/chat/GuiMessageSource;Lnet/minecraft/client/multiplayer/chat/GuiMessageTag;)V
accessible class net/minecraft/client/gui/components/ChatComponent$DrawingBackgroundGraphicsAccess
# entidad
accessible method net/minecraft/client/multiplayer/ClientLevel getEntities ()Lnet/minecraft/world/level/entity/LevelEntityGetter;
@@ -32,6 +33,10 @@ accessible field net/minecraft/client/particle/Particle hasPhysics Z
# renderizado 3d
accessible method net/minecraft/client/renderer/rendertype/RenderType <init> (Ljava/lang/String;Lnet/minecraft/client/renderer/rendertype/RenderSetup;)V
accessible method net/minecraft/client/renderer/rendertype/RenderType create (Ljava/lang/String;Lnet/minecraft/client/renderer/rendertype/RenderSetup;)Lnet/minecraft/client/renderer/rendertype/RenderType;
accessible field net/minecraft/client/renderer/RenderPipelines LINES_SNIPPET Lcom/mojang/blaze3d/pipeline/RenderPipeline$Snippet;
accessible field net/minecraft/client/renderer/RenderPipelines DEBUG_FILLED_SNIPPET Lcom/mojang/blaze3d/pipeline/RenderPipeline$Snippet;
accessible field net/minecraft/client/renderer/RenderPipelines GUI_TEXTURED_SNIPPET Lcom/mojang/blaze3d/pipeline/RenderPipeline$Snippet;
# pantallas
accessible field net/minecraft/client/gui/screens/inventory/AbstractContainerScreen imageWidth I
+1
View File
@@ -46,6 +46,7 @@
"mixins.hud.BossBarHudMixin",
"mixins.hud.ChatComponentLineConsumerMixin",
"mixins.hud.ChatComponentMixin",
"mixins.hud.DrawingBackgroundGraphicsAccessMixin",
"mixins.hud.DrawingFocusedGraphicsAccessMixin",
"mixins.hud.GuiMessageLineMixin",
"mixins.hud.GuiMessageMixin",