Skip to content

Commit aebc913

Browse files
committed
Merge branch 'wip/uiutils'
2 parents 64cc9fb + c65df4d commit aebc913

17 files changed

+1252
-0
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
@@ -225,6 +225,7 @@ public final class HackList implements UpdateListener
225225
public final TargetPlaceHack targetPlaceHack = new TargetPlaceHack();
226226
public final TiredHack tiredHack = new TiredHack();
227227
public final TooManyHaxHack tooManyHaxHack = new TooManyHaxHack();
228+
public final UiUtilsHack uiUtilsHack = new UiUtilsHack();
228229
public final TpAuraHack tpAuraHack = new TpAuraHack();
229230
public final TrajectoriesHack trajectoriesHack = new TrajectoriesHack();
230231
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: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import net.wurstclient.nicewurst.NiceWurstModule;
2929
import net.wurstclient.serverfinder.CleanUpScreen;
3030
import net.wurstclient.altmanager.screens.AltManagerScreen;
31+
import net.wurstclient.uiutils.UiUtilsState;
3132

3233
@Mixin(JoinMultiplayerScreen.class)
3334
public class MultiplayerScreenMixin extends Screen
@@ -41,6 +42,9 @@ public class MultiplayerScreenMixin extends Screen
4142
private Button cornerCleanUpButton;
4243
@Unique
4344
private Button cornerAltManagerButton;
45+
private Button uiUtilsBypassButton;
46+
@Unique
47+
private Button uiUtilsForceDenyButton;
4448

4549
private MultiplayerScreenMixin(WurstClient wurst, Component title)
4650
{
@@ -54,6 +58,8 @@ private void beforeVanillaButtons(CallbackInfo ci)
5458
cornerServerFinderButton = null;
5559
cornerCleanUpButton = null;
5660
cornerAltManagerButton = null;
61+
uiUtilsBypassButton = null;
62+
uiUtilsForceDenyButton = null;
5763

5864
if(!WurstClient.INSTANCE.isEnabled())
5965
return;
@@ -162,6 +168,52 @@ private void onRefreshWidgetPositions(CallbackInfo ci)
162168
cornerCleanUpButton.setX(width / 2 + 154 + 4);
163169
cornerCleanUpButton.setY(height - 30);
164170
cornerCleanUpButton.setWidth(100);
171+
172+
if(!UiUtilsState.isUiEnabled())
173+
{
174+
if(uiUtilsBypassButton != null)
175+
uiUtilsBypassButton.visible = false;
176+
if(uiUtilsForceDenyButton != null)
177+
uiUtilsForceDenyButton.visible = false;
178+
return;
179+
}
180+
181+
if(uiUtilsBypassButton == null)
182+
{
183+
uiUtilsBypassButton = Button
184+
.builder(Component.literal("Bypass Resource Pack: OFF"), b -> {
185+
UiUtilsState.bypassResourcePack =
186+
!UiUtilsState.bypassResourcePack;
187+
b.setMessage(Component.literal("Bypass Resource Pack: "
188+
+ (UiUtilsState.bypassResourcePack ? "ON" : "OFF")));
189+
}).bounds(0, 0, 160, 20).build();
190+
addRenderableWidget(uiUtilsBypassButton);
191+
}
192+
uiUtilsBypassButton
193+
.setMessage(Component.literal("Bypass Resource Pack: "
194+
+ (UiUtilsState.bypassResourcePack ? "ON" : "OFF")));
195+
196+
if(uiUtilsForceDenyButton == null)
197+
{
198+
uiUtilsForceDenyButton =
199+
Button.builder(Component.literal("Force Deny: OFF"), b -> {
200+
UiUtilsState.resourcePackForceDeny =
201+
!UiUtilsState.resourcePackForceDeny;
202+
b.setMessage(Component.literal("Force Deny: "
203+
+ (UiUtilsState.resourcePackForceDeny ? "ON" : "OFF")));
204+
}).bounds(0, 0, 160, 20).build();
205+
addRenderableWidget(uiUtilsForceDenyButton);
206+
}
207+
uiUtilsForceDenyButton.setMessage(Component.literal("Force Deny: "
208+
+ (UiUtilsState.resourcePackForceDeny ? "ON" : "OFF")));
209+
210+
uiUtilsBypassButton.setX(width - 170);
211+
uiUtilsBypassButton.setY(height - 50);
212+
uiUtilsBypassButton.visible = true;
213+
214+
uiUtilsForceDenyButton.setX(width - 170);
215+
uiUtilsForceDenyButton.setY(height - 25);
216+
uiUtilsForceDenyButton.visible = true;
165217
}
166218

167219
@Inject(at = @At("HEAD"),
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+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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.injection.At;
12+
import org.spongepowered.asm.mixin.injection.Inject;
13+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
14+
import net.minecraft.client.Minecraft;
15+
import net.minecraft.client.gui.components.Button;
16+
import net.minecraft.client.gui.screens.Screen;
17+
import net.minecraft.client.gui.screens.inventory.AbstractSignEditScreen;
18+
import net.minecraft.network.chat.Component;
19+
import net.wurstclient.uiutils.UiUtils;
20+
import net.wurstclient.uiutils.UiUtilsState;
21+
22+
@Mixin(AbstractSignEditScreen.class)
23+
public abstract class UiUtilsAbstractSignEditScreenMixin extends Screen
24+
{
25+
private UiUtilsAbstractSignEditScreenMixin(Component title)
26+
{
27+
super(title);
28+
}
29+
30+
@Inject(at = @At("TAIL"), method = "init()V")
31+
private void onInit(CallbackInfo ci)
32+
{
33+
if(!UiUtilsState.isUiEnabled())
34+
return;
35+
36+
Minecraft mc = Minecraft.getInstance();
37+
int spacing = 4;
38+
int buttonHeight = 20;
39+
int totalHeight = buttonHeight * 2 + spacing;
40+
int startY = Math.max(5, (this.height - totalHeight) / 2);
41+
int baseX = 8;
42+
addRenderableWidget(
43+
Button.builder(Component.literal("Close without packet"), b -> {
44+
UiUtilsState.shouldEditSign = false;
45+
mc.setScreen(null);
46+
}).bounds(baseX, startY, 115, 20).build());
47+
48+
addRenderableWidget(
49+
Button.builder(Component.literal("Disconnect"), b -> {
50+
if(mc.getConnection() != null)
51+
mc.getConnection().getConnection().disconnect(
52+
Component.literal("Disconnecting (UI-UTILS)"));
53+
else
54+
UiUtils.LOGGER.warn(
55+
"Minecraft connection was null while disconnecting.");
56+
}).bounds(baseX, startY + buttonHeight + spacing, 115, 20).build());
57+
}
58+
}

0 commit comments

Comments
 (0)