Skip to content

Commit c65df4d

Browse files
committed
UI-Utils Rework
1 parent 463c56b commit c65df4d

18 files changed

+1275
-22
lines changed

src/main/java/net/wurstclient/WurstInitializer.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import net.wurstclient.chestsearch.ChestCleaner;
1212
import net.wurstclient.chestsearch.TargetHighlighter;
1313
import net.wurstclient.events.RenderListener;
14+
import net.wurstclient.uiutils.UiUtils;
1415

1516
public final class WurstInitializer implements ModInitializer
1617
{
@@ -28,6 +29,11 @@ public void onInitialize()
2829
"WurstInitializer.onInitialize() ran twice!");
2930

3031
WurstClient.INSTANCE.initialize();
32+
try
33+
{
34+
UiUtils.init();
35+
}catch(Throwable ignored)
36+
{}
3137
// Register chest cleaner
3238
try
3339
{

src/main/java/net/wurstclient/hack/HackList.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ public final class HackList implements UpdateListener
216216
public final TargetPlaceHack targetPlaceHack = new TargetPlaceHack();
217217
public final TiredHack tiredHack = new TiredHack();
218218
public final TooManyHaxHack tooManyHaxHack = new TooManyHaxHack();
219+
public final UiUtilsHack uiUtilsHack = new UiUtilsHack();
219220
public final TpAuraHack tpAuraHack = new TpAuraHack();
220221
public final TrajectoriesHack trajectoriesHack = new TrajectoriesHack();
221222
public final TreeBotHack treeBotHack = new TreeBotHack();
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2014-2026 Wurst-Imperium and contributors.
3+
*
4+
* This source code is subject to the terms of the GNU General Public
5+
* License, version 3. If a copy of the GPL was not distributed with this
6+
* file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt
7+
*/
8+
package net.wurstclient.hacks;
9+
10+
import net.wurstclient.Category;
11+
import net.wurstclient.hack.Hack;
12+
import net.wurstclient.uiutils.UiUtilsState;
13+
14+
public final class UiUtilsHack extends Hack
15+
{
16+
public UiUtilsHack()
17+
{
18+
super("UI-Utils");
19+
setCategory(Category.OTHER);
20+
}
21+
22+
@Override
23+
protected void onEnable()
24+
{
25+
UiUtilsState.enabled = true;
26+
}
27+
28+
@Override
29+
protected void onDisable()
30+
{
31+
UiUtilsState.enabled = false;
32+
}
33+
}

src/main/java/net/wurstclient/mixin/ChatScreenMixin.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import net.wurstclient.WurstClient;
2020
import net.wurstclient.event.EventManager;
2121
import net.wurstclient.events.ChatOutputListener.ChatOutputEvent;
22+
import net.wurstclient.uiutils.UiUtils;
23+
import net.wurstclient.uiutils.UiUtilsState;
2224

2325
@Mixin(ChatScreen.class)
2426
public abstract class ChatScreenMixin extends Screen
@@ -48,6 +50,26 @@ public void onSendMessage(String message, boolean addToHistory,
4850
if((message = normalizeChatMessage(message)).isEmpty())
4951
return;
5052

53+
if("^toggleuiutils".equals(message))
54+
{
55+
UiUtilsState.enabled = !UiUtilsState.enabled;
56+
if(minecraft.player != null)
57+
minecraft.player
58+
.displayClientMessage(Component.literal("UI-Utils is now "
59+
+ (UiUtilsState.enabled ? "enabled" : "disabled")
60+
+ "."), false);
61+
else
62+
UiUtils.LOGGER
63+
.warn("Minecraft player was null while toggling UI-Utils.");
64+
65+
if(addToHistory)
66+
minecraft.gui.getChat().addRecentChat(message);
67+
68+
minecraft.setScreen(null);
69+
ci.cancel();
70+
return;
71+
}
72+
5173
// Create and fire the chat output event
5274
ChatOutputEvent event = new ChatOutputEvent(message);
5375
EventManager.fire(event);

src/main/java/net/wurstclient/mixin/ClientCommonNetworkHandlerMixin.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
import net.minecraft.network.protocol.Packet;
2626
import net.minecraft.network.protocol.common.ClientCommonPacketListener;
2727
import net.minecraft.network.protocol.common.ClientboundResourcePackPushPacket;
28+
import net.minecraft.network.protocol.common.ServerboundResourcePackPacket;
29+
import net.wurstclient.uiutils.UiUtils;
30+
import net.wurstclient.uiutils.UiUtilsState;
2831

2932
@Mixin(ClientCommonPacketListenerImpl.class)
3033
public abstract class ClientCommonNetworkHandlerMixin
@@ -55,6 +58,23 @@ private void wrapSendPacket(Connection connection, Packet<?> packet,
5558
private void onResourcePackSend(ClientboundResourcePackPushPacket packet,
5659
CallbackInfo ci)
5760
{
61+
if(UiUtilsState.isUiEnabled() && UiUtilsState.bypassResourcePack
62+
&& (packet.required() || UiUtilsState.resourcePackForceDeny))
63+
{
64+
connection.send(new ServerboundResourcePackPacket(packet.id(),
65+
ServerboundResourcePackPacket.Action.ACCEPTED));
66+
connection.send(new ServerboundResourcePackPacket(packet.id(),
67+
ServerboundResourcePackPacket.Action.SUCCESSFULLY_LOADED));
68+
UiUtils.LOGGER.info(
69+
"[UI Utils] Required resource pack bypassed, " + "message: "
70+
+ (packet.prompt().isEmpty() ? "<no message>"
71+
: packet.prompt().toString())
72+
+ ", url: "
73+
+ (packet.url() == null ? "<no url>" : packet.url()));
74+
ci.cancel();
75+
return;
76+
}
77+
5878
try
5979
{
6080
PolicyResult result = ResourcePackProtector.evaluate(packet);

src/main/java/net/wurstclient/mixin/MultiplayerScreenMixin.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import net.minecraft.network.chat.Component;
2828
import net.wurstclient.nicewurst.NiceWurstModule;
2929
import net.wurstclient.serverfinder.CleanUpScreen;
30+
import net.wurstclient.uiutils.UiUtilsState;
3031

3132
@Mixin(JoinMultiplayerScreen.class)
3233
public class MultiplayerScreenMixin extends Screen
@@ -38,6 +39,10 @@ public class MultiplayerScreenMixin extends Screen
3839
private Button cornerServerFinderButton;
3940
@Unique
4041
private Button cornerCleanUpButton;
42+
@Unique
43+
private Button uiUtilsBypassButton;
44+
@Unique
45+
private Button uiUtilsForceDenyButton;
4146

4247
private MultiplayerScreenMixin(WurstClient wurst, Component title)
4348
{
@@ -50,6 +55,8 @@ private void beforeVanillaButtons(CallbackInfo ci)
5055
antiFingerprintButton = null;
5156
cornerServerFinderButton = null;
5257
cornerCleanUpButton = null;
58+
uiUtilsBypassButton = null;
59+
uiUtilsForceDenyButton = null;
5360

5461
if(!WurstClient.INSTANCE.isEnabled())
5562
return;
@@ -136,6 +143,52 @@ private void onRefreshWidgetPositions(CallbackInfo ci)
136143
cornerCleanUpButton.setX(width / 2 + 154 + 4);
137144
cornerCleanUpButton.setY(height - 30);
138145
cornerCleanUpButton.setWidth(100);
146+
147+
if(!UiUtilsState.isUiEnabled())
148+
{
149+
if(uiUtilsBypassButton != null)
150+
uiUtilsBypassButton.visible = false;
151+
if(uiUtilsForceDenyButton != null)
152+
uiUtilsForceDenyButton.visible = false;
153+
return;
154+
}
155+
156+
if(uiUtilsBypassButton == null)
157+
{
158+
uiUtilsBypassButton = Button
159+
.builder(Component.literal("Bypass Resource Pack: OFF"), b -> {
160+
UiUtilsState.bypassResourcePack =
161+
!UiUtilsState.bypassResourcePack;
162+
b.setMessage(Component.literal("Bypass Resource Pack: "
163+
+ (UiUtilsState.bypassResourcePack ? "ON" : "OFF")));
164+
}).bounds(0, 0, 160, 20).build();
165+
addRenderableWidget(uiUtilsBypassButton);
166+
}
167+
uiUtilsBypassButton
168+
.setMessage(Component.literal("Bypass Resource Pack: "
169+
+ (UiUtilsState.bypassResourcePack ? "ON" : "OFF")));
170+
171+
if(uiUtilsForceDenyButton == null)
172+
{
173+
uiUtilsForceDenyButton =
174+
Button.builder(Component.literal("Force Deny: OFF"), b -> {
175+
UiUtilsState.resourcePackForceDeny =
176+
!UiUtilsState.resourcePackForceDeny;
177+
b.setMessage(Component.literal("Force Deny: "
178+
+ (UiUtilsState.resourcePackForceDeny ? "ON" : "OFF")));
179+
}).bounds(0, 0, 160, 20).build();
180+
addRenderableWidget(uiUtilsForceDenyButton);
181+
}
182+
uiUtilsForceDenyButton.setMessage(Component.literal("Force Deny: "
183+
+ (UiUtilsState.resourcePackForceDeny ? "ON" : "OFF")));
184+
185+
uiUtilsBypassButton.setX(width - 170);
186+
uiUtilsBypassButton.setY(height - 50);
187+
uiUtilsBypassButton.visible = true;
188+
189+
uiUtilsForceDenyButton.setX(width - 170);
190+
uiUtilsForceDenyButton.setY(height - 25);
191+
uiUtilsForceDenyButton.visible = true;
139192
}
140193

141194
@Inject(at = @At("HEAD"),

src/main/java/net/wurstclient/mixin/TitleScreenMixin.java

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,30 @@
1313
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
1414
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
1515

16-
import net.fabricmc.fabric.api.client.screen.v1.Screens;
17-
import net.minecraft.client.gui.components.AbstractWidget;
18-
import net.minecraft.client.gui.components.Button;
19-
import net.minecraft.client.gui.screens.Screen;
20-
import net.minecraft.client.gui.GuiGraphics;
21-
import net.minecraft.client.gui.Font;
22-
import net.minecraft.client.gui.screens.TitleScreen;
23-
import net.minecraft.client.resources.language.I18n;
24-
import net.minecraft.network.chat.Component;
25-
import net.wurstclient.WurstClient;
26-
import net.wurstclient.altmanager.screens.AltManagerScreen;
27-
import net.wurstclient.config.BuildConfig;
28-
import net.wurstclient.nicewurst.NiceWurstModule;
16+
import net.fabricmc.fabric.api.client.screen.v1.Screens;
17+
import net.minecraft.client.gui.components.AbstractWidget;
18+
import net.minecraft.client.gui.components.Button;
19+
import net.minecraft.client.gui.screens.Screen;
20+
import net.minecraft.client.gui.GuiGraphics;
21+
import net.minecraft.client.gui.Font;
22+
import net.minecraft.client.gui.screens.TitleScreen;
23+
import net.minecraft.client.resources.language.I18n;
24+
import net.minecraft.network.chat.Component;
25+
import net.wurstclient.WurstClient;
26+
import net.wurstclient.altmanager.screens.AltManagerScreen;
27+
import net.wurstclient.config.BuildConfig;
28+
import net.wurstclient.nicewurst.NiceWurstModule;
2929

3030
@Mixin(TitleScreen.class)
31-
public abstract class TitleScreenMixin extends Screen
32-
{
33-
private AbstractWidget realmsButton = null;
34-
private Button altsButton;
35-
36-
private TitleScreenMixin(WurstClient wurst, Component title)
37-
{
38-
super(title);
39-
}
31+
public abstract class TitleScreenMixin extends Screen
32+
{
33+
private AbstractWidget realmsButton = null;
34+
private Button altsButton;
35+
36+
private TitleScreenMixin(WurstClient wurst, Component title)
37+
{
38+
super(title);
39+
}
4040

4141
/**
4242
* Adds the AltManager button to the title screen. This mixin must not
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright (c) 2014-2026 Wurst-Imperium and contributors.
3+
*
4+
* This source code is subject to the terms of the GNU General Public
5+
* License, version 3. If a copy of the GPL was not distributed with this
6+
* file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt
7+
*/
8+
package net.wurstclient.mixin.ui_utils;
9+
10+
import org.spongepowered.asm.mixin.Mixin;
11+
import org.spongepowered.asm.mixin.gen.Accessor;
12+
import io.netty.channel.Channel;
13+
import net.minecraft.network.Connection;
14+
15+
@Mixin(Connection.class)
16+
public interface ConnectionAccessor
17+
{
18+
@Accessor("channel")
19+
Channel getChannel();
20+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright (c) 2014-2026 Wurst-Imperium and contributors.
3+
*
4+
* This source code is subject to the terms of the GNU General Public
5+
* License, version 3. If a copy of the GPL was not distributed with this
6+
* file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt
7+
*/
8+
package net.wurstclient.mixin.ui_utils;
9+
10+
import org.spongepowered.asm.mixin.Mixin;
11+
import org.spongepowered.asm.mixin.Unique;
12+
import org.spongepowered.asm.mixin.injection.At;
13+
import org.spongepowered.asm.mixin.injection.Inject;
14+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
15+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
16+
import net.minecraft.client.Minecraft;
17+
import net.minecraft.client.gui.GuiGraphics;
18+
import net.minecraft.client.gui.components.EditBox;
19+
import net.minecraft.client.gui.screens.Screen;
20+
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
21+
import net.minecraft.client.input.KeyEvent;
22+
import net.minecraft.network.chat.Component;
23+
import net.minecraft.world.inventory.AbstractContainerMenu;
24+
import net.wurstclient.uiutils.UiUtils;
25+
import net.wurstclient.uiutils.UiUtilsState;
26+
27+
@Mixin(AbstractContainerScreen.class)
28+
public abstract class UiUtilsAbstractContainerScreenMixin<T extends AbstractContainerMenu>
29+
extends Screen
30+
{
31+
@Unique
32+
private EditBox uiUtilsChatField;
33+
34+
private UiUtilsAbstractContainerScreenMixin(Component title)
35+
{
36+
super(title);
37+
}
38+
39+
@Inject(at = @At("TAIL"), method = "init()V")
40+
private void onInit(CallbackInfo ci)
41+
{
42+
if(!UiUtilsState.isUiEnabled())
43+
return;
44+
45+
Minecraft mc = Minecraft.getInstance();
46+
int spacing = 4;
47+
int buttonHeight = 20;
48+
int buttonCount = 8;
49+
int chatHeight = 20;
50+
int blockHeight = buttonCount * buttonHeight
51+
+ (buttonCount - 1) * spacing + spacing + chatHeight;
52+
int startY = Math.max(5, (this.height - blockHeight) / 2);
53+
int baseX = 8;
54+
int nextY = UiUtils.addUiWidgets(mc, baseX, startY, spacing,
55+
this::addRenderableWidget);
56+
uiUtilsChatField =
57+
UiUtils.createChatField(mc, this.font, baseX, nextY + spacing);
58+
addRenderableWidget(uiUtilsChatField);
59+
}
60+
61+
@Inject(at = @At("TAIL"),
62+
method = "render(Lnet/minecraft/client/gui/GuiGraphics;IIF)V")
63+
private void onRender(GuiGraphics graphics, int mouseX, int mouseY,
64+
float partialTicks, CallbackInfo ci)
65+
{
66+
if(!UiUtilsState.isUiEnabled())
67+
return;
68+
69+
AbstractContainerMenu menu =
70+
((AbstractContainerScreen<?>)(Object)this).getMenu();
71+
UiUtils.renderSyncInfo(Minecraft.getInstance(), graphics, menu);
72+
}
73+
74+
@Inject(at = @At("HEAD"),
75+
method = "keyPressed(Lnet/minecraft/client/input/KeyEvent;)Z",
76+
cancellable = true)
77+
private void onKeyPressed(KeyEvent keyEvent,
78+
CallbackInfoReturnable<Boolean> cir)
79+
{
80+
if(!UiUtilsState.isUiEnabled())
81+
return;
82+
83+
if(uiUtilsChatField == null || !uiUtilsChatField.isFocused())
84+
return;
85+
86+
if(uiUtilsChatField.keyPressed(keyEvent))
87+
{
88+
cir.setReturnValue(true);
89+
return;
90+
}
91+
92+
if(keyEvent.isEscape())
93+
{
94+
uiUtilsChatField.setFocused(false);
95+
cir.setReturnValue(true);
96+
return;
97+
}
98+
99+
cir.setReturnValue(true);
100+
}
101+
102+
}

0 commit comments

Comments
 (0)