Skip to content

Commit 6595904

Browse files
committed
ElytraInfo
1 parent 97ef655 commit 6595904

8 files changed

Lines changed: 1010 additions & 70 deletions

File tree

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ I'm pleased to note that many of the features and improvements below are complet
9191
- LootRunner
9292
- AutoFly
9393
- HideModMenu
94+
- SilkOnly
95+
- MobHealth (Inspired By Another Mod)
96+
- GameStats
97+
- AdvancedPacketTool
98+
- ClientChatOverlay
99+
- AutoChat
100+
- Mention
101+
- Force Allow Chats
102+
- MusicAura
103+
- ElytraInfo (Inspired By Another Mod)
94104
- Redstone, Bed, Sign & Workstation ESP
95105
- PearlESP (Not a simple trajectory hack)
96106
- SignFramePassThrough (I didn't know something like this existed as a mod already)
@@ -120,6 +130,7 @@ I have taken the following ideas from other clients/mods:
120130
- UI-Utils
121131
- Bundle Dupe
122132
- BookBot
133+
- NewerNewChunks
123134

124135
I did not, nor could I copy their code directly as most are Meteor based mods. So these are considered my interpretation of the functionality of those hacks.
125136

@@ -812,7 +823,8 @@ This hack is still undergoing development and has only been tested in the end. A
812823
- Can prioritize the newest message while keeping older lines as secondary context.
813824
- Mention detection supports your username plus nickname/derivative variants.
814825
- Optional `Always reply when mentioned` bypasses reply-gap timers for direct mentions.
815-
- Persona is configurable via text field.
826+
- Editable system prompt in-game.
827+
- Persona is configurable via text field and overrides whatever is in the system prompt.
816828
- Model is selectable, including:
817829
`chatgpt-4o-latest`, `gpt-5.2-chat-latest`, `gpt-5.2`, `gpt-4o`,
818830
`gpt-5.1-chat-latest`, `gpt-5-chat-latest`, `gpt-5.1`, `gpt-5`,
@@ -841,6 +853,17 @@ This hack is still undergoing development and has only been tested in the end. A
841853
- Randomly alter music blocks around you, even through walls
842854
- Totally pointless
843855

856+
### ElytraInfo
857+
- HUD under crosshair for elytra info: yaw, pitch, altitude, speed, direction, durability%.
858+
- Draggable when chat/inventory is open.
859+
- Custom text color/opacity/size, optional background color/opacity, optional prefix hiding.
860+
- Optional durability gradient (green -> red).
861+
- Keybindable swap: .elytrainfo swap (elytra <-> best chestplate, skips Binding-cursed items).
862+
- Optional auto-switch back to chestplate on landing.
863+
- Optional auto-switch to new Elytra on <= 5% durability.
864+
865+
![Ely](https://i.imgur.com/9yPOfUH.png)
866+
844867
## What's changed or improved in this fork?
845868

846869
### ChestESP

src/main/java/net/wurstclient/command/CmdList.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public final class CmdList
3131
public final DropCmd dropCmd = new DropCmd();
3232
public final EnabledHaxCmd enabledHaxCmd = new EnabledHaxCmd();
3333
public final EnchantCmd enchantCmd = new EnchantCmd();
34+
public final ElytraInfoCmd elytraInfoCmd = new ElytraInfoCmd();
3435
public final ExcavateCmd excavateCmd = new ExcavateCmd();
3536
public final FeaturesCmd featuresCmd = new FeaturesCmd();
3637
public final FollowCmd followCmd = new FollowCmd();
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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.commands;
9+
10+
import net.wurstclient.WurstClient;
11+
import net.wurstclient.command.Command;
12+
import net.wurstclient.command.CmdError;
13+
14+
public final class ElytraInfoCmd extends Command
15+
{
16+
public ElytraInfoCmd()
17+
{
18+
super("elytrainfo", "ElytraInfo utility commands.", ".elytrainfo swap");
19+
}
20+
21+
@Override
22+
public void call(String[] args) throws CmdError
23+
{
24+
if(args.length == 0 || !args[0].equalsIgnoreCase("swap"))
25+
throw new CmdError("Usage: .elytrainfo swap");
26+
27+
WurstClient.INSTANCE.getHax().elytraInfoHack.swapChestItemFromKeybind();
28+
}
29+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ public final class HackList implements UpdateListener
120120
public final DerpHack derpHack = new DerpHack();
121121
public final DolphinHack dolphinHack = new DolphinHack();
122122
public final ElytraFlightHack elytraFlightHack = new ElytraFlightHack();
123+
public final ElytraInfoHack elytraInfoHack = new ElytraInfoHack();
123124
public final ExcavatorHack excavatorHack = new ExcavatorHack();
124125
public final ExtraElytraHack extraElytraHack = new ExtraElytraHack();
125126
public final FancyChatHack fancyChatHack = new FancyChatHack();

src/main/java/net/wurstclient/hacks/AutoChatHack.java

Lines changed: 146 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,17 @@ public final class AutoChatHack extends Hack implements ChatInputListener
7070
private static final Pattern VALID_PLAYER_NAME =
7171
Pattern.compile("^[A-Za-z0-9_]{1,16}$");
7272

73-
private static final String[] INJECTION_MARKERS =
74-
{"ignore previous", "ignore all previous", "system prompt",
75-
"developer message", "reveal prompt", "show prompt", "jailbreak",
76-
"dan mode", "forget your instructions", "new instructions"};
77-
78-
private static final Pattern DEFAULT_PROMPT_USERNAME_LINE =
79-
Pattern.compile("(?m)^Your username: .*$");
80-
private static final Pattern DEFAULT_PROMPT_PERSONA_LINE =
81-
Pattern.compile("(?m)^Persona: .*$");
73+
private static final String[] INJECTION_MARKERS =
74+
{"ignore previous", "ignore all previous", "system prompt",
75+
"developer message", "reveal prompt", "show prompt", "jailbreak",
76+
"dan mode", "forget your instructions", "new instructions"};
77+
78+
private static final Pattern DEFAULT_PROMPT_USERNAME_LINE =
79+
Pattern.compile("(?m)^Your username: .*$");
80+
private static final Pattern DEFAULT_PROMPT_PERSONA_LINE =
81+
Pattern.compile("(?m)^Persona: .*$");
82+
private static final Pattern SYSTEM_PROMPT_PERSONA_CAPTURE =
83+
Pattern.compile("(?m)^Persona:\\s*(.*)$");
8284

8385
private final TextFieldSetting apiKey =
8486
new TextFieldSetting("OpenAI API key",
@@ -196,6 +198,8 @@ public final class AutoChatHack extends Hack implements ChatInputListener
196198
private int inFlightRequests;
197199
private volatile long lastReplyTime;
198200
private volatile long lastUnsolicitedReplyTime;
201+
private String lastPersonaSnapshot = "";
202+
private String lastCustomPromptSnapshot = "";
199203

200204
public AutoChatHack()
201205
{
@@ -223,6 +227,9 @@ public AutoChatHack()
223227
addSetting(wordsPerMinute);
224228
addSetting(maxConcurrentRequests);
225229
addSetting(debugMode);
230+
lastPersonaSnapshot = persona.getValue();
231+
lastCustomPromptSnapshot =
232+
normalizePromptText(customSystemPrompt.getValue());
226233

227234
}
228235

@@ -827,14 +834,16 @@ private JsonObject buildChatCompletionsRequest(List<ChatLine> snapshot,
827834
return root;
828835
}
829836

830-
private String buildSystemPrompt()
831-
{
832-
String custom = normalizePromptText(customSystemPrompt.getValue());
833-
if(!custom.isBlank() && !isGeneratedDefaultPromptSnapshot(custom))
834-
return custom;
835-
836-
return buildDefaultSystemPrompt();
837-
}
837+
private String buildSystemPrompt()
838+
{
839+
syncPersonaAndPrompt();
840+
841+
String custom = normalizePromptText(customSystemPrompt.getValue());
842+
if(!custom.isBlank() && !isGeneratedDefaultPromptSnapshot(custom))
843+
return custom;
844+
845+
return buildDefaultSystemPrompt();
846+
}
838847

839848
private String buildDefaultSystemPrompt()
840849
{
@@ -868,64 +877,132 @@ public void openSystemPromptEditor()
868877
MC.setScreen(new AutoChatSystemPromptScreen(MC.screen, this));
869878
}
870879

871-
public String getSystemPromptEditorText()
872-
{
873-
String custom = normalizePromptText(customSystemPrompt.getValue());
874-
if(!custom.isBlank() && !isGeneratedDefaultPromptSnapshot(custom))
875-
return custom;
876-
877-
return buildDefaultSystemPrompt();
878-
}
880+
public String getSystemPromptEditorText()
881+
{
882+
syncPersonaAndPrompt();
883+
884+
String custom = normalizePromptText(customSystemPrompt.getValue());
885+
if(!custom.isBlank() && !isGeneratedDefaultPromptSnapshot(custom))
886+
return custom;
887+
888+
return buildDefaultSystemPrompt();
889+
}
879890

880891
public String getGeneratedDefaultSystemPrompt()
881892
{
882893
return buildDefaultSystemPrompt();
883894
}
884895

885-
public void setCustomSystemPrompt(String prompt)
886-
{
887-
if(prompt == null)
888-
return;
889-
890-
String normalized = normalizePromptText(prompt);
891-
if(normalized.isBlank() || isGeneratedDefaultPromptSnapshot(normalized))
892-
{
893-
customSystemPrompt.setValue("");
894-
return;
895-
}
896-
897-
customSystemPrompt.setValue(prompt);
898-
}
899-
900-
private static String normalizePromptText(String prompt)
901-
{
902-
if(prompt == null)
903-
return "";
904-
905-
return prompt.replace("\r\n", "\n").strip();
906-
}
907-
908-
private boolean isGeneratedDefaultPromptSnapshot(String prompt)
909-
{
910-
String normalizedPrompt = normalizePromptText(prompt);
911-
if(normalizedPrompt.isBlank())
912-
return false;
913-
914-
String customSignature = toDefaultPromptSignature(normalizedPrompt);
915-
String defaultSignature =
916-
toDefaultPromptSignature(buildDefaultSystemPrompt());
917-
return customSignature.equals(defaultSignature);
918-
}
919-
920-
private static String toDefaultPromptSignature(String prompt)
921-
{
922-
String signature = normalizePromptText(prompt);
923-
signature = DEFAULT_PROMPT_USERNAME_LINE.matcher(signature)
924-
.replaceFirst("Your username: <dynamic>");
925-
signature = DEFAULT_PROMPT_PERSONA_LINE.matcher(signature)
926-
.replaceFirst("Persona: <dynamic>");
927-
return signature;
928-
}
896+
public void setCustomSystemPrompt(String prompt)
897+
{
898+
if(prompt == null)
899+
return;
900+
901+
String normalized = normalizePromptText(prompt);
902+
if(normalized.isBlank() || isGeneratedDefaultPromptSnapshot(normalized))
903+
{
904+
customSystemPrompt.setValue("");
905+
syncPersonaAndPrompt();
906+
return;
907+
}
908+
909+
customSystemPrompt.setValue(prompt);
910+
syncPersonaAndPrompt();
911+
}
912+
913+
private void syncPersonaAndPrompt()
914+
{
915+
String currentPersona = persona.getValue();
916+
String currentPrompt =
917+
normalizePromptText(customSystemPrompt.getValue());
918+
if(currentPrompt.isBlank())
919+
{
920+
lastPersonaSnapshot = currentPersona;
921+
lastCustomPromptSnapshot = currentPrompt;
922+
return;
923+
}
924+
925+
String promptPersona = extractPersonaFromPrompt(currentPrompt);
926+
if(promptPersona == null)
927+
{
928+
lastPersonaSnapshot = currentPersona;
929+
lastCustomPromptSnapshot = currentPrompt;
930+
return;
931+
}
932+
933+
boolean personaChanged = !currentPersona.equals(lastPersonaSnapshot);
934+
boolean promptChanged = !currentPrompt.equals(lastCustomPromptSnapshot);
935+
936+
if(promptChanged && !personaChanged)
937+
{
938+
if(!currentPersona.equals(promptPersona))
939+
persona.setValue(promptPersona);
940+
}else if(personaChanged && !promptChanged)
941+
{
942+
if(!promptPersona.equals(currentPersona))
943+
{
944+
String synced =
945+
replacePersonaInPrompt(currentPrompt, currentPersona);
946+
customSystemPrompt.setValue(synced);
947+
}
948+
}else if(promptChanged && personaChanged)
949+
{
950+
if(!currentPersona.equals(promptPersona))
951+
persona.setValue(promptPersona);
952+
}else if(!currentPersona.equals(promptPersona))
953+
persona.setValue(promptPersona);
954+
955+
lastPersonaSnapshot = persona.getValue();
956+
lastCustomPromptSnapshot =
957+
normalizePromptText(customSystemPrompt.getValue());
958+
}
959+
960+
private static String extractPersonaFromPrompt(String prompt)
961+
{
962+
Matcher matcher =
963+
SYSTEM_PROMPT_PERSONA_CAPTURE.matcher(normalizePromptText(prompt));
964+
if(!matcher.find())
965+
return null;
966+
967+
return matcher.group(1).strip();
968+
}
969+
970+
private static String replacePersonaInPrompt(String prompt, String persona)
971+
{
972+
return SYSTEM_PROMPT_PERSONA_CAPTURE
973+
.matcher(normalizePromptText(prompt))
974+
.replaceFirst("Persona: " + Matcher.quoteReplacement(persona));
975+
}
976+
977+
private static String normalizePromptText(String prompt)
978+
{
979+
if(prompt == null)
980+
return "";
981+
982+
return prompt.replace("\r\n", "\n").strip();
983+
}
984+
985+
private boolean isGeneratedDefaultPromptSnapshot(String prompt)
986+
{
987+
String normalizedPrompt = normalizePromptText(prompt);
988+
if(normalizedPrompt.isBlank())
989+
return false;
990+
991+
String customSignature = toDefaultPromptSignature(normalizedPrompt);
992+
String defaultSignature =
993+
toDefaultPromptSignature(buildDefaultSystemPrompt());
994+
return customSignature.equals(defaultSignature);
995+
}
996+
997+
private static String toDefaultPromptSignature(String prompt)
998+
{
999+
String signature = normalizePromptText(prompt);
1000+
signature = DEFAULT_PROMPT_USERNAME_LINE.matcher(signature)
1001+
.replaceFirst("Your username: <dynamic>");
1002+
signature = DEFAULT_PROMPT_PERSONA_LINE.matcher(signature)
1003+
.replaceFirst("Persona: <dynamic>");
1004+
return signature;
1005+
}
9291006

9301007
private String buildUserPrompt(List<ChatLine> snapshot, ChatLine latest,
9311008
boolean direct)

0 commit comments

Comments
 (0)